POSTMASTER_HANDLER prefilter unconditionally bypasses spam scoring for postmaster@ mail — no safe way to customize via local.d

Author: PatrickDrewsESCreated Sep 18, 2026Updated Sep 18, 2026

Behavior: data/conf/rspamd/lua/rspamd.local.lua's POSTMASTER_HANDLER prefilter sets pre_result('accept', ...) for any single-envelope-recipient mail to postmaster@, unconditionally — no SPF/DKIM/DMARC check, no scoring, Authentication-Results: none.

Real-world impact: Received a phishing mail (fake "domain expiry" notice, spoofed brand, external link) sent solely to postmaster@<domain>. It bypassed all filtering purely because of this rule. postmaster@ is an RFC 2142 standardized, guessable address, so this is a predictable attack surface, not a theoretical one.

Attempted fix: Tried to narrow this via local.d/rspamd.lua (the documented user-customization slot) — quarantine only when the mail is not a DSN and contains an http(s) link, otherwise keep the original accept. Tested three approaches via real SMTP injection through the postfix→rspamd milter path (not just rspamc, which gave inconsistent results):

  1. A separate, higher-priority prefilter calling set_pre_result before POSTMASTER_HANDLER — original accept still won.
  2. Re-registering a symbol named POSTMASTER_HANDLER from local.d/ — rejected by rspamd (duplicate symbol: POSTMASTER_HANDLER, skip registering).
  3. A postfilter calling set_pre_result again after the prefilter — confirmed to execute (longer processing time), but the original accept still won as final.

Conclusion: a prefilter's pre_result, once set, can't be overridden by anything running later, regardless of priority. The only working method is to fully shadow the 947-line lua/rspamd.local.lua via local.d/rspamd.local.lua, which defeats the purpose of local.d as a lightweight customization point and forks every other rule in that file (SMTP_ACCESS, MAILCOW_AUTH, KEEP_SPAM, TAG_MOO, POSTMASTER_FROM) away from upstream updates.

Ask: Either narrow POSTMASTER_HANDLER's default bypass condition (e.g. skip only greylisting/ratelimiting, not a full accept; or exclude messages containing links), or split it into its own separately-overridable file/symbol name so a local.d customization doesn't require forking unrelated rules.

Source: mailcow/mailcow-dockerized