SES sender domain injection through HELO argument
The SES inbound rate limit counts by `ses_inbound.sender_domain`, which reads DKIM-pass signer domains from SES's own Authentication-Results header (`_ses_dkim_domains`). That header also echoes sender-chosen text: the SPF comment, `envelope-from=` and `helo=`. Since Task 9431 the parser splits clauses outside comments and quoted strings, reads only raw (never RFC 2047-decoded) values and yields nothing when any quote appears. One case is not covered. If SES accepts and echoes an unquoted HELO argument containing `;` (e.g. `a;dkim=pass()header.i=@victim.example`), that becomes a clause of its own. With `From:` that domain, `sender_domain` charges the victim domain's 50/day quota in that org. This only affects the rate limit; trust decisions use SES's notification verdicts. It is unconfirmed whether SES accepts such a HELO.
Requirement: first confirm SES's behaviour with a real send on dev (`helo` containing `;`). If it is echoed, derive the rate-limit domain without re-parsing echoed text: use the From domain when SES's `dmarcVerdict` is PASS, else the SPF-pass MAIL FROM domain from the notification's `source`, else the shared unauthenticated bucket. Update `tests/test_ses_inbound.py::test_the_sender_domain_is_dkim_then_spf_then_one_unauthenticated_bucket` accordingly.
Out of scope: Gmail receive (`app/tenant_gmail/receive.py`); trigger matching.
Done means:
- A recorded or live SES header with an injected `helo=` never makes `sender_domain` return the injected domain (test).
- `./dc check quick` green.
Outcome
SES sender_domain now uses DMARC-pass From → SPF source → unauthenticated, never echoed A-R (helo injection test added); DMARC reports trusted on DMARC pass only. Quick gate + 185 tests green; PR #6808 queued. Live SES HELO probe not run: outbound :25 blocked. Memory: none applied.
Artifacts
Activity
- Created
- Run
- Runner started
- Runner ended (done)