[pfx] Dynamic content filter allows for forged mails to be signed with DKIM

Peymaneh Nejad via Postfix-users <[email protected]>
Newsgroups gmane.mail.postfix.user
Message-ID <[email protected]>
Hello,

I have a question about the correct usage of the FILTER directive in access 
controls. It seems that our current setup allows for forged, unauthenticated 
mails for our domain to be signed with our DKIM signature.

I am maintaining a mail server with mostly App-managed "dummy" 
accounts/identities, for which there is no need of spam filtering. Only a few 
mailboxes, like [email protected], are ever reviewed by humans, and for these we 
use spamassassin to rewrite the subject header with ****Spam**** (no blocking).

Because we only selectively use spamassassin based on the recipient mail, we do 
not use the milter interface but instead do this:

main.cf:
```
smtpd_recipient_restrictions =
     check_recipient_access hash:/etc/postfix/spamfilter_access,
     permit_mynetworks,
     permit_sasl_authenticated,
     reject_unauth_destination,
     check_policy_service unix:private/policy-spf
```

Where this is the content of /etc/postfix/spamfilter_access:
```
[email protected]  FILTER spamassassin:
...
```

Now it seems that this setups allows unauthenticated and forged mails from a 
nonexistent user via port 25 to be signed with a DKIM signature by us:
```
From: Non existent <[email protected]>
To: info <[email protected]>
Subject: Testmail for debugging

Lorem ipsum
```

```
curl smtp://mail.example.org --mail-from "<>" --mail-rcpt [email protected] 
--upload-file ~/fakemail.txt
```

The mails seem to pass the queue because empty "<>" passes the smtpd 
restrictions (so that mails from Mailer Daemon do not bounce, I understand), and 
is then signed by OpenDKIM, seemingly after the mail is passed on to 
spamassassin, which then re-inserts it into the queue with as a new mail, and 
therefore the forged mail seems to originate from localhost (which is OpenDKIM 
is configured to trust)

Related logs:
```
2026-08-11T10:37:19.031392+02:00 mail postfix/smtpd[313003]: connect from 
unknown[redacted-ip]
2026-08-11T10:37:19.107728+02:00 mail postfix/smtpd[313003]: NOQUEUE: filter: 
RCPT from unknown[redacted-ip]: <[email protected]>: Recipient address triggers 
FILTER spamassassin:; from=<> to=<[email protected]> proto=ESMTP helo=<fakemail.txt>
2026-08-11T10:37:19.108931+02:00 mail policyd-spf[499496]: : prepend 
Authentication-Results: mail.example.org; spf=none (no SPF record) 
smtp.helo=fakemail.txt (client-ip=redacted-ip; helo=fakemail.txt; 
envelope-from=<>; receiver=example.org)
2026-08-11T10:37:19.109625+02:00 mail postfix/smtpd[313003]: 1ABE0A40002: 
client=unknown[redacted-ip]
2026-08-11T10:37:19.157890+02:00 mail postfix/cleanup[451699]: 1ABE0A40002: 
message-id=<[email protected]>
2026-08-11T10:37:19.173415+02:00 mail opendkim[3959515]: 1ABE0A40002: 
[redacted-ip] [redacted-ip] not internal
2026-08-11T10:37:19.173494+02:00 mail opendkim[3959515]: 1ABE0A40002: not 
authenticated
2026-08-11T10:37:19.215745+02:00 mail opendmarc[1186913]: 1ABE0A40002: 
example.org fail
2026-08-11T10:37:19.261344+02:00 mail postfix/qmgr[3958735]: 1ABE0A40002: 
from=<>, size=771, nrcpt=1 (queue active)
2026-08-11T10:37:19.354471+02:00 mail postfix/smtpd[313003]: disconnect from 
unknown[redacted-ip] ehlo=1 mail=1 rcpt=1 data=1 quit=1 commands=5
2026-08-11T10:37:19.663155+02:00 mail postfix/pickup[3929985]: A1D22A40005: 
uid=131 from=<MAILER-DAEMON>
2026-08-11T10:37:19.663913+02:00 mail postfix/pipe[520894]: 1ABE0A40002: 
to=<[email protected]>, orig_to=<[email protected]>, relay=spamassassin, 
delay=0.58, delays=0.18/0/0/0.4, dsn=2.0.0, status=sent (delivered via 
spamassassin service)
2026-08-11T10:37:19.663974+02:00 mail postfix/qmgr[3958735]: 1ABE0A40002: removed
2026-08-11T10:37:19.664835+02:00 mail postfix/cleanup[486649]: A1D22A40005: 
message-id=<[email protected]>
2026-08-11T10:37:19.667515+02:00 mail opendkim[3959515]: A1D22A40005: 
DKIM-Signature field added (s=mail, d=example.org)
2026-08-11T10:37:19.710306+02:00 mail postfix/qmgr[3958735]: A1D22A40005: 
from=<>, size=1329, nrcpt=1 (queue active)
2026-08-11T10:37:19.734125+02:00 mail postfix/pipe[499436]: A1D22A40005: 
to=<[email protected]>, relay=dovecot, delay=0.07, delays=0.05/0/0/0.02, 
dsn=2.0.0, status=sent (delivered via dovecot service)
2026-08-11T10:37:19.734191+02:00 mail postfix/qmgr[3958735]: A1D22A40005: removed
```

Source code of the delivered mail:
```
Return-Path: <MAILER-DAEMON>
X-Original-To: [email protected]
Delivered-To: [email protected]
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=example.org;
     s=mail; t=1786437439;
     bh=NaG/LzWHMLdnzEKLpTXZ+VNncWJXoEQ8/qRca2ZOKtc=;
     h=From:To:Subject:Date;
     b=MDSDffS8/yPZcsQi1DAMxyULeFKQcW1ryLouJmS/fFp6G4Ht6ei9Bk19M2Kg7X9Wv
      zrN2XjLro5hGo94bjnWUV8+KHltuYDI8KtSoy8bhR7Ytx7R3yN7xHePBwxjI9EtRCP
      lqxP/1oua/UajlMccZqsc1xnmJ3U3uGSgrA708TKvUckEF+INVJJBvvNss9o/46pek
      kIh01GrP1NmcM9ZsyzOgLNhMs2OZAI1arBnyt01HkBTqDhzhThcbV9/0G847ZJTHYQ
      ePdffxQrnmdFpD2nTowwTg/XO25xbFpBW4Vmzl1kg1FiXmS70PaK0gcyJDJBqOW0gr
      5r7rOcuiFs+tg==
Received: by mail.example.org (Postfix, from userid 131)
     id A1D22A40005; Tue, 11 Aug 2026 10:37:19 +0200 (CEST)
X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on mail.example.org
X-Spam-Level: *
X-Spam-Status: No, score=1.5 required=3.0 tests=PP_MIME_FAKE_ASCII_TEXT,
     RCVD_IN_ZEN_BLOCKED_OPENDNS,RDNS_NONE,SPF_HELO_NONE autolearn=no
     autolearn_force=no version=4.0.0
Authentication-Results: OpenDMARC; dmarc=fail (p=reject dis=none) 
header.from=example.org
Authentication-Results: mail.example.org; dkim=none; dkim-atps=neutral
Authentication-Results: mail.example.org; spf=none (no SPF record) 
smtp.helo=fakemail.txt (client-ip=2a02:8109:a09c:3a00:dd73:29e8:11b2:ddbd; 
helo=fakemail.txt; envelope-from=<>; receiver=example.org)
Received: from fakemail.txt (unknown [IPv6:2a02:8109:a09c:3a00:dd73:29e8:11b2:ddbd])
     by mail.example.org (Postfix) with ESMTP id 1ABE0A40002
     for <[email protected]>; Tue, 11 Aug 2026 10:37:19 +0200 (CEST)
From: Non Existent <[email protected]>
To: info <[email protected]>
Subject: Testmail for debugging
Message-Id: <[email protected]>
Date: Tue, 11 Aug 2026 10:37:19 +0200 (CEST)
```

So, the questions are:
Where in our setup lies the issue leading to wrongly DKIM-signed mails?
And how can we, selectively based on the recipient address, route mails over 
spamassassin without allowing for external mails to be mistakenly signed by our 
setup?

Solutions that I have considered:

One easy solution would probably be of course to use different domains for each 
purpose, i.e. App-managed mail accounts should live on a domain with lesser 
restrictions, and the human managed accounts should live on a domain with 
general spam filtering enabled. That is nothing we can do over night, though.

Also, as of my understanding of the milter protocol, just using spamass-milter 
via inet socket might not introduce this problem, but on the other side I don't 
see a possibility to do selective checking via milter based on the recipient 
address. Looking at https://www.postfix.org/FILTER_README.html#dynamic_filter I 
have the impression that our approach is somewhat in the right direction, but 
maybe badly implemented.

Any hints are much appreciated.

Thank you for your time and support,

Warm regards
Peymaneh (she/her)
_______________________________________________
Postfix-users mailing list -- [email protected]
To unsubscribe send an email to [email protected]
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.