]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Fix] Forged recipients: compare addresses as they were transmitted
authorVsevolod Stakhov <vsevolod@rspamd.com>
Thu, 16 Jul 2026 09:47:27 +0000 (10:47 +0100)
committerVsevolod Stakhov <vsevolod@rspamd.com>
Thu, 16 Jul 2026 09:47:27 +0000 (10:47 +0100)
The rule compared the rewritten envelope view against the wire MIME
headers, so a recipient alias mapping to another domain (legal for
recipients) could make a perfectly matching To header look forged.
Compare the envelope and the headers at the same altitude: both as they
were seen in the message, which is also what this rule checked before
alias rewriting was applied to tasks.

Issue: #6137

src/plugins/lua/forged_recipients.lua
test/functional/cases/001_merged/360_aliases.robot
test/functional/messages/aliases_rcpt_virtual.eml [new file with mode: 0644]

index 0d51db3920100ef8b6e49544bb22ea000ab2615f..8605e7713945bd4a087693d30c5413e41bc3e7e7 100644 (file)
@@ -37,8 +37,11 @@ local E = {}
 local function check_forged_headers(task)
   local auser = task:get_user()
   local delivered_to = task:get_header('Delivered-To')
-  local smtp_rcpts = task:get_recipients(1)
-  local smtp_from = task:get_from(1)
+  -- Compare the envelope and the headers as they were transmitted: alias
+  -- rewrites (e.g. a cross-domain virtual alias applied to the envelope
+  -- recipients) must not make the wire To/Cc headers look forged
+  local smtp_rcpts = task:get_recipients({ 'smtp', 'orig' })
+  local smtp_from = task:get_from({ 'smtp', 'orig' })
 
   if not smtp_rcpts then
     return
@@ -144,7 +147,7 @@ local function check_forged_headers(task)
 
   -- Check sender
   if smtp_from and smtp_from[1] and smtp_from[1]['addr'] ~= '' then
-    local mime_from = task:get_from(2)
+    local mime_from = task:get_from({ 'mime', 'orig' })
     if not mime_from or not mime_from[1] or
         not rspamd_util.strequal_caseless_utf8(mime_from[1]['addr'], smtp_from[1]['addr']) then
       task:insert_result(symbol_sender, 1, ((mime_from or E)[1] or E).addr or '', smtp_from[1].addr)
index 26d4daaaa9ad24f80ca004ec48729016d8dbd51d..a341ab55964d35deb64d2e8e8f77aae32a0ac4ed 100644 (file)
@@ -184,3 +184,14 @@ FROM SAME-DOMAIN ALIAS - APPLIED
   ...  Rcpt=user@example.com
   Expect Symbol  ALIAS_RESOLVED
   Expect Symbol With Exact Options  GET_FROM  Abuse Desk,admin@example.com,admin,example.com
+
+RCPT CROSS-DOMAIN ALIAS - NOT FORGED
+  [Documentation]  A recipient rewritten to another domain (allowed for
+  ...  recipients) must not make the matching wire To header look forged:
+  ...  forged_recipients compares the addresses as transmitted
+  Scan File  ${RSPAMD_TESTDIR}/messages/aliases_rcpt_virtual.eml
+  ...  From=sender@external.com
+  ...  Rcpt=virtual@example.com
+  Expect Symbol  ALIAS_RESOLVED
+  Do Not Expect Symbol  FORGED_RECIPIENTS
+  Do Not Expect Symbol  FORGED_SENDER
diff --git a/test/functional/messages/aliases_rcpt_virtual.eml b/test/functional/messages/aliases_rcpt_virtual.eml
new file mode 100644 (file)
index 0000000..a246ccf
--- /dev/null
@@ -0,0 +1,8 @@
+From: Sender <sender@external.com>
+To: virtual@example.com
+Subject: Test cross-domain recipient alias vs forged recipients
+Message-ID: <test-rcpt-virtual@example.com>
+Date: Mon, 01 Jan 2025 10:00:00 +0000
+
+A recipient rewritten to another domain must not make the wire To header
+look forged.