milter: the sender check keeps two From: and two Sender: values (audit M5)

Security audit 2026-10-17, finding M5 (low), stage 0. senderSession.Header
appended every From:/Sender: value; Postfix bounds one header at 60 000
bytes but not their number, and the signer's 1 MiB cap runs after the
sender check, so an application could make it hold megabytes per
connection (the reader's test: a hundred lines, 6 MB). judge needs only
none / one / more, so two of each are kept; the refusal text joins what is
kept, as before.

Tests: "a hundred From: lines" in the judgement table (refused, more than
one From: line); TestSenderKeepsTwoFromAndSenderLines. go test
./internal/milter.

Docs: security.md (the sentence "a few headers each"); CHANGELOG; plan.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
mix
2026-10-17 21:33:53 +03:00
co-authored by Claude Opus 5.5
parent 683fdafc6d
commit da2e8b2ffe
5 changed files with 40 additions and 5 deletions
+2 -2
View File
@@ -704,8 +704,8 @@ the argument.
tail may hold none of the neutered characters and each SASL field is one
word (a `.*` SASL tail would have let a quoted sender spell the whole
tail); TestInboundRecipientCannotWriteTheRow.
- [ ] **M5.** Keep at most two `From:`/`Sender:` values; security.md:810
reworded. — **Opus**, 0.5 h.
- [x] **M5.** Keep at most two `From:`/`Sender:` values; security.md:810
reworded. — **Opus**, 0.5 h. *Done 2026-10-17:* TestSenderKeepsTwoFromAndSenderLines.
- [ ] **A4.** Duplicate-cookie line through `loggedPath`. — **Sonnet**, 0.25 h.
- [ ] **S6.** `smtpd_etrn_restrictions = reject`, `smtpd_discard_ehlo_keywords
= etrn` in postfix-config.sh; architecture.md § Postfix one line. Done when
+4 -1
View File
@@ -824,7 +824,10 @@ deferred item from the roadmap.
`headerLimit`; `2.8.0`): it keeps no more than that and drops its list
once the block it signs is built. No mail program writes such a section,
and the refusal is permanent, so a sender is told rather than retried.
The other milters keep a few headers each (From, Sender, Subject).
The other milters keep a few headers each: the sender check two `From:`
and two `Sender:` values at most - it needs only none, one or more - and
the first Subject (until `2.14.4` it kept every `From:`/`Sender:` line,
which Postfix bounds in length but not in number; audit 2026-10-17, M5).
Until `2.8.0` the milter library itself added every header of a message
to a map of its own in each milter - up to the port's message size limit,
from strangers on port 25 - which none of the milters read; the panel