Email trigger from rule: match the sender address
Found in the finish review of epic 9351 (supersedes the parentless draft #9574, which never dispatches).
(a) Reproduction (read on develop dd239284d): `apps/api/app/trigger_intake.py:695-710` `email_matches` returns `all(needle in value.lower() ...)`, so a `from` rule is a case-insensitive SUBSTRING of the From address. A rule `from: boss@victim.com` therefore also matches `boss@victim.com.evil.example`. The DMARC check at :704-706 does not help: the attacker owns `victim.com.evil.example`, so its mail passes DMARC legitimately and fires the sender-scoped trigger. Since Task 9431 (PR #6793) tenant orgs put `from` rules on their own hosted addresses and Gmail mailboxes, so any outside sender can reach this.
(b) Cause: `apps/api/app/trigger_intake.py:710` applies substring matching to the `from` field.
(c) Fix (no new surface): when the `from` rule is a whole address (contains `@` with a local part) compare the parsed From address for equality; when it is a domain (`@victim.com` or `victim.com`-shaped with a dot and no spaces) match the From address's domain exactly or as a subdomain (`domain == d or domain.endswith("." + d)`). Keep substring matching only for a rule that is neither, and say so in the email trigger editor's hint text in `apps/web`.
(d) Acceptance:
- AC1: `from: boss@victim.com` does NOT match `boss@victim.com.evil.example` (DMARC pass) — unit test in `apps/api/tests/test_ses_inbound.py` or a new suite.
- AC2: `from: boss@victim.com` still matches `Boss <BOSS@victim.com>` — same test file.
- AC3: `from: @victim.com` matches `a@victim.com` and `a@mx.victim.com`, not `a@victim.com.evil.example` or `a@notvictim.com` — test.
- AC4: a free-text rule (e.g. `billing`) keeps substring behaviour — test.
- AC5: the editor hint states the address/domain rule — web test next to the component.
Out of scope: To and Subject rules; system inbound routing; DMARC handling (already enforced); the SES rate-limit HELO question (draft #9576); any migration of existing trigger rows.
Done means:
- The tests for AC1–AC5 pass and fail on the pre-change code for AC1/AC3.
- `./dc check quick` green; PR merged to develop through the merge lane.
Required checks: ./dc check quick
Outcome
Email trigger From rule: an address now matches exactly and a domain matches itself and its subdomains; a From with several addresses matches neither. The editor hint states the rule. Quick gate passed; PR #6797 queued in the lane. Visual check OK. Filed draft #9592. Memory: none applied.
Artifacts
Activity
- Ready
- Runner started
- Runner ended (done)