Skip to content

gh-76787: Catch an injected header that pads the name with whitespace - #158157

Open
v0ropaev wants to merge 1 commit into
python:mainfrom
v0ropaev:gh-76787-embedded-header-whitespace
Open

v0ropaev wants to merge 1 commit into
python:mainfrom
v0ropaev:gh-76787-embedded-header-whitespace

Conversation

@v0ropaev

@v0ropaev v0ropaev commented Sep 25, 2026 •

Copy link
Copy Markdown

Closes #76787.

@bitdancer said what to do here in 2022 and nobody picked it up:

The regex in email/header.py should be fixed. The fix is pretty simple, just allowing for whitespace to appear before the colon.

The check is _embedded_header = re.compile(r'\n[^ \t]+:'), which needs the colon right after the name. Receivers are not that strict — as @bitdancer put it earlier in the thread, most MTAs and MUAs try hard to guess what a non-compliant message meant, and a space before the colon is one of the things they forgive. So the injected line gets read as a header at the far end while the guard here sees nothing. On main:

>>> msg['Dummy'] = 'dummy\nX-Injected-Header: test'   # caught
HeaderParseError
>>> msg['Dummy'] = 'dummy\nX-Injected-Header : test'  # not caught
>>> msg['Dummy'] = 'dummy\nX-Injected-Header\t: test' # not caught

The pattern is now r'\n[^ \t]+[ \t]*:'.

Folding is untouched. A continuation line begins with whitespace, and the pattern still requires a non-blank character straight after the newline, so 'dummy\n continued here: not a header' goes through as before. There is a test for that alongside the three injected forms, because widening a guard is exactly where you want to know you have not started rejecting valid input.

./python.exe -m test test_email is 1,821 passing, and test_smtplib test_email together 1,906. Reverting Lib/email/header.py while keeping the tests fails.

The issue is public and has been since 2018, with the proof of concept attached to the original report and the fix described openly on the thread, so I am treating it as an ordinary bug rather than something for security@python.org. main only.

…espace

The embedded-header check required the colon to follow the name directly,
so a line like "cc : injected@example.com" slipped past it.  Receivers
are lenient about that whitespace and read the line as a header anyway,
which is the bypass reported in the issue.

R. David Murray described the fix on the issue: allow whitespace before
the colon in the pattern.  Continuation lines are unaffected, since they
begin with whitespace and the pattern still requires a non-blank first
character after the newline.
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 Header Injection Protection Bypass

1 participant