diff --git a/lambdas/po/email_processor/ses_auth.py b/lambdas/po/email_processor/ses_auth.py index bd54c13..db58ce6 100644 --- a/lambdas/po/email_processor/ses_auth.py +++ b/lambdas/po/email_processor/ses_auth.py @@ -104,6 +104,13 @@ def _strip_comments(value: str) -> tuple: outside any comment (depth 0) is an unmatched close and makes the value not well-formed, closing the ``)(`` clause-injection gap. + CFWS also means a comment abutting a token *ends* that token: + ``header.d=seahaven.com(note)`` reads as domain ``seahaven.com``, where + the pre-CFWS gluing behaviour read ``seahaven.comnote`` (rejected). + This is deliberate -- ``header.d`` is written verbatim by SES from a + *verified* signature's ``d=`` tag, so a comment in that position is + never attacker-controlled. + Returns ``(stripped_text, well_formed)``. ``well_formed`` is False when the value ends inside an unterminated comment or quoted-string, or when an unmatched ``)`` appears at the top level. Callers reject on diff --git a/lambdas/wo/email_processor/ses_auth.py b/lambdas/wo/email_processor/ses_auth.py index bd54c13..db58ce6 100644 --- a/lambdas/wo/email_processor/ses_auth.py +++ b/lambdas/wo/email_processor/ses_auth.py @@ -104,6 +104,13 @@ def _strip_comments(value: str) -> tuple: outside any comment (depth 0) is an unmatched close and makes the value not well-formed, closing the ``)(`` clause-injection gap. + CFWS also means a comment abutting a token *ends* that token: + ``header.d=seahaven.com(note)`` reads as domain ``seahaven.com``, where + the pre-CFWS gluing behaviour read ``seahaven.comnote`` (rejected). + This is deliberate -- ``header.d`` is written verbatim by SES from a + *verified* signature's ``d=`` tag, so a comment in that position is + never attacker-controlled. + Returns ``(stripped_text, well_formed)``. ``well_formed`` is False when the value ends inside an unterminated comment or quoted-string, or when an unmatched ``)`` appears at the top level. Callers reject on diff --git a/tests/test_ses_auth.py b/tests/test_ses_auth.py index e5ebf50..9537647 100644 --- a/tests/test_ses_auth.py +++ b/tests/test_ses_auth.py @@ -258,6 +258,17 @@ class TestParseAuthenticationResults: ) assert passing == frozenset() + def test_comment_after_header_d_ends_the_domain_token(self, ses_auth): + # CFWS: a comment abutting header.d ends the token, so the domain + # reads as "seahaven.com" (pre-CFWS gluing read "seahaven.comnote", + # rejected). Deliberate: header.d is written verbatim by SES from a + # *verified* signature's d= tag, so a comment in that position is + # never attacker-controlled. + _, passing = ses_auth.parse_authentication_results( + "amazonses.com; dkim=pass header.d=seahaven.com(note)" + ) + assert passing == frozenset({"seahaven.com"}) + def test_unbalanced_quote_fails_closed(self, ses_auth): # An unterminated quoted-string is malformed; refuse to parse it so a # dkim=pass clause "swallowed" by the runaway quote can't be salvaged