From 76beb9d5279843f7ab31b5f82bf057b7118ccbe9 Mon Sep 17 00:00:00 2001 From: Lukas Remis Date: Thu, 17 Sep 2026 20:20:58 +0200 Subject: [PATCH] Antispam: make the reputation switch real, limited to Spamhaus and DNSWL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "Allow online reputation checks" setting did nothing. It saved a value, the plugin sent a Settings-ID header, and the engine ignored it — the profiles that header named were never written. Three separate faults had to be fixed before one checkbox changed one score: - the profiles did not exist - a settings block is only selectable by header if it declares an `id` - a local.d file holds the CONTENTS of a module block, not the block; the outer `settings { }` wrapper nested them a level too deep and rspamd logged "loaded 0 elements of settings" Proven rather than assumed, using Spamhaus's documented dbltest.com: webmail_offline -> no reputation symbols webmail_network -> DBL_SPAM fires Which lookups exist at all is narrowed in rbl.conf to the three chosen: Spamhaus ZEN (sending IP), Spamhaus DBL (domains in links), DNSWL (an allow-list, which can only subtract score). Everything else is off — commercial sender-reputation businesses, and anything that sends a fingerprint of the message body to a third party. NiX Spam was dropped after checking: its zone returns SERVFAIL from every public resolver, so it could only ever have added failing lookups. The URL blocklists are keyed by quoted uppercase names deeper in the stock config and survived a first pass of this work; the comment says how to verify. Help text now names the services and says what they learn, rather than vaguely warning about "third-party servers". Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_018SqJYt7jD7oUEkoY68sBZo --- docker/rspamd/local.d/rbl.conf | 63 ++++++++++++++++--- docker/rspamd/local.d/settings.conf | 33 ++++++++++ .../webmail_plugin_antispam/ui/settings.js | 2 +- 3 files changed, 88 insertions(+), 10 deletions(-) create mode 100644 docker/rspamd/local.d/settings.conf diff --git a/docker/rspamd/local.d/rbl.conf b/docker/rspamd/local.d/rbl.conf index c2392d8..cefd4b4 100644 --- a/docker/rspamd/local.d/rbl.conf +++ b/docker/rspamd/local.d/rbl.conf @@ -1,10 +1,55 @@ -# DISABLED BY DEFAULT (SPEC §C.2, acceptance 6). -# rbl performs third-party lookups derived from message content — hashes -# of the body, the URLs it contains, the sending IP. For a self-hosted personal -# server that is a privacy leak the user did not ask for, so the module is off -# and the engine makes no outbound connections at all. +# Reputation lookups — OPT-IN, and narrowed to three sources (SPEC §C.2). # -# Turning this on is an operator decision, not a per-message one: set -# enabled = true here, restart rspamd, and only then does the plugin's -# network_checks setting have anything to enable. -enabled = false; +# The module is enabled, but almost every stock list is turned off. What survives +# is deliberate: +# +# spamhaus zen.spamhaus.org — the sending server's IP. The most +# established blocklist there is. +# SPAMHAUS_DBL dbl.spamhaus.org — domains found in the message's links. +# dnswl list.dnswl.org — an ALLOW-list: it can only subtract score +# from known-good senders, never add it. +# +# Everything else is off for one of three reasons: +# - it sends a fingerprint of the message body to a third party (fuzzy, hashbl) +# - it is a commercial sender-reputation business (senderscore, mailspike) +# - it does not resolve any more (nixspam: ix.dnsbl.manitu.net returns +# SERVFAIL from every public resolver as of 2026-09) +# +# Note this only makes the lookups POSSIBLE. Whether they run for a given user +# is decided per-user by settings.conf, driven by the "Allow online reputation +# checks" switch in the plugin's settings page. +enabled = true; + +rbls { + # --- kept ----------------------------------------------------------------- + spamhaus { enabled = true; } + dnswl { enabled = true; } + + # --- off: commercial reputation businesses -------------------------------- + senderscore { enabled = false; } + mailspike { enabled = false; } + + # --- off: content fingerprints leave the building ------------------------- + SURBL_HASHBL { enabled = false; } + RSPAMD_EMAILBL { enabled = false; } + MSBL_EBL { enabled = false; } + + # --- off: smaller/volunteer lists we did not choose ----------------------- + sem { enabled = false; } + semIPv6 { enabled = false; } + virusfree { enabled = false; } + blocklistde { enabled = false; } + dnswl_dwl { enabled = false; } + + # --- off: dead zone -------------------------------------------------------- + nixspam { enabled = false; } + + # The URL blocklists are keyed by quoted uppercase names further down the stock + # file, which is easy to miss — they stayed active through a first pass of this + # config. Verify with: docker logs rspamd | grep 'added rbl rule' + "SURBL_MULTI" { enabled = false; } + "URIBL_MULTI" { enabled = false; } + "RSPAMD_URIBL" { enabled = false; } + "SEM_URIBL_UNKNOWN" { enabled = false; } + "SEM_URIBL_FRESH15_UNKNOWN" { enabled = false; } +} diff --git a/docker/rspamd/local.d/settings.conf b/docker/rspamd/local.d/settings.conf new file mode 100644 index 0000000..3979950 --- /dev/null +++ b/docker/rspamd/local.d/settings.conf @@ -0,0 +1,33 @@ +# Per-user reputation lookups (SPEC §C.2). +# +# The plugin sends a Settings-ID header on every scan, chosen from the user's +# "Allow online reputation checks" switch. These are the two profiles it names. +# +# NOTE the shape: a local.d file contains the CONTENTS of the module's block, not +# the block itself. Wrapping these in `settings { ... }` nests them one level too +# deep and rspamd loads zero profiles while logging "unknown settings id" — which +# is exactly how this setting managed to look wired up while doing nothing. +# +# `id` is what makes a profile selectable by header at all; without it a settings +# block is matched by sender/IP conditions instead and the header is ignored. + +# Default: no outbound lookups of any kind. +webmail_offline { + id = "webmail_offline"; + priority = high; + apply { + # Both groups: Spamhaus ZEN and DNSWL score under "rbl", but the domain + # blocklist (DBL) scores under "surbl". Disabling only "rbl" leaves DBL + # querying Spamhaus about every link in every message. + groups_disabled = ["rbl", "surbl"]; + } +} + +# Opted in: Spamhaus ZEN + DBL and DNSWL, as narrowed in rbl.conf. +webmail_network { + id = "webmail_network"; + priority = high; + apply { + groups_enabled = ["rbl", "surbl"]; + } +} diff --git a/plugins/webmail_plugin_antispam/webmail_plugin_antispam/ui/settings.js b/plugins/webmail_plugin_antispam/webmail_plugin_antispam/ui/settings.js index 5b05374..29a89f5 100644 --- a/plugins/webmail_plugin_antispam/webmail_plugin_antispam/ui/settings.js +++ b/plugins/webmail_plugin_antispam/webmail_plugin_antispam/ui/settings.js @@ -113,7 +113,7 @@ export default function mount(el, ctx) {
-

Off by default. These send hashes of your mail and the links it contains to third-party servers. They also need the modules enabled on the engine itself.

+

Off by default. When on, the filter asks Spamhaus whether the sending server or a linked domain is known for spam, and DNSWL whether the sender is known-good. That reveals those addresses and domains to them — and to whichever DNS resolver you use. The message itself is never sent, and no fingerprint of it leaves your server.