Skip to content

gh-159475: Make parseaddr() reject inline comments in strict mode - #159477

Closed
D3e4mlike wants to merge 1 commit into
python:mainfrom
D3e4mlike:gh-159475-parseaddr-inline-comment
Closed

D3e4mlike wants to merge 1 commit into
python:mainfrom
D3e4mlike:gh-159475-parseaddr-inline-comment

Conversation

@D3e4mlike

@D3e4mlike D3e4mlike commented Oct 15, 2026 •

Copy link
Copy Markdown

Fixes #159475.

Summary

email.utils.parseaddr() and getaddresses(), in strict mode (the default
since the CVE-2023-27043 fix), still silently drop a comment that is embedded
inside a dot-atom and splice the surrounding atoms together:

>>> from email.utils import parseaddr
>>> parseaddr('u(comment)ser@d.com', strict=True)
('comment comment', 'user@d.com')

email.headerregistry.Address('u(comment)ser@d.com') rejects this input
(local-part is not dot-atom / quoted-string / obs-local-part), so a caller that
validates or authorizes with parseaddr and then hands the original string to
a strict component gets a subject mismatch — the same class as CVE-2019-11340
(Matrix Sydent) and the motivation behind CVE-2023-27043.

Change

Add an internal _inline_comment flag to the lenient AddrlistClass parser in
Lib/email/_parseaddr.py. It is set when a comment is consumed immediately
before another atom inside an addr-spec (or its domain) — exactly the position
where the comment would be silently dropped and two atoms spliced. In strict
mode, parseaddr / getaddresses now return ('', '') / [('', '')] when
the flag is set.

  • Leading and trailing comments remain accepted (they are valid CFWS).
  • A comment inside a quoted string remains literal content (not a comment).
  • strict=False keeps the historical lenient behavior unchanged.
  • Existing strict rejections (domain-literal, multiple addresses, unbalanced
    parentheses) are unchanged.

Why it matters

parseaddr / getaddresses is not deprecated and is still widely used in
security-sensitive paths: CPython's own smtplib, Django, Sentry, Odoo (which
explicitly opts into strict=False), and Ansible all call it. "Legacy" here
means a compat API rather than an abandoned one. The minimal ask is that strict
mode fail closed instead of silently inventing an addr-spec that no strict
reader would accept.

Tests

Added test_parseaddr_inline_comment to Lib/test/test_email/test_email.py,
covering local-part and domain splicing, empty and nested comments,
getaddresses parity, and the still-accepted leading / trailing / quoted cases.

@D3e4mlike
D3e4mlike requested a review from a team as a code owner October 15, 2026 16:21
@python-cla-bot

python-cla-bot Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

All commit authors signed the Contributor License Agreement.

CLA signed

email.utils.parseaddr() and getaddresses(), in strict mode (the default),
silently dropped a comment embedded inside a dot-atom and spliced the
surrounding atoms together (e.g. 'u(comment)ser@d.com' -> 'user@d.com').
Strict mode now returns ('', '') for such addresses; strict=False keeps
the historical lenient behavior.

Signed-off-by: ZHOU Zijun <zijunzhou03222@gmail.com>
@bedevere-app

bedevere-app Bot commented Oct 17, 2026

Copy link
Copy Markdown

Most changes to Python require a NEWS entry. Add one using the blurb_it web app or the blurb command-line tool.

If this change has little impact on Python users, wait for a maintainer to apply the skip news label instead.

@D3e4mlike

Copy link
Copy Markdown
Author

Superseded by #159618. This PR was accidentally closed and could not be reopened (GitHub forbids reopening a closed PR whose head branch was later force-pushed), so it has been re-created as #159618 with the identical diff.

@hugovk

hugovk commented Oct 17, 2026

Copy link
Copy Markdown
Member

For next time, please don't force push PRs. We squash merge at the end, and it's easier to review without force pushes. Also force pushes can end up spamming all the CODEOWNERS like this :)

https://devguide.python.org/getting-started/pull-request-lifecycle/#don-t-force-push

@hugovk
hugovk removed request for a team, ambv, brettcannon and freakboy3742 October 17, 2026 10:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

email.utils.parseaddr(strict=True) silently splices inline comments in the local-part

2 participants