Repository navigation
Conversation
The local-part pattern lists the characters it allows explicitly: ASCII letters and digits, the RFC 5322 specials and U+00A0 to U+024F. Compiled with re.IGNORECASE but not re.ASCII, a character also matches when re treats one of its other-case forms as equal to a listed character. That admitted 31 characters outside those ranges, among them the Kelvin sign (U+212A, lowercase "k"), the Angstrom sign (U+212B, lowercase U+00E5), Greek mu, U+1E9E and IPA letters. The Kelvin and Angstrom signs render as "K" and "A with ring above", so a lookalike of "Kelvin@example.com" validated. With re.ASCII, case-insensitive matching applies to ASCII letters only. Every character inside the listed ranges still matches itself, so nothing inside them is lost; comparing both patterns over all code points drops exactly those 31 characters and adds none.
nandgator
force-pushed
the
fix-email-local-part-casefold
branch
from
October 22, 2026 16:04
e1263df to
4b013af
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
email()matches the local part against an explicit allowlist: ASCII letters and digits, the RFC 5322 specials, and U+00A0 to U+024F. The pattern is compiled withre.IGNORECASEbut notre.ASCII, so a character also matches whenretreats one of its other-case forms as equal to a listed character (Python docs). That admits 31 characters outside the listed ranges, in both dot-atom and quoted local parts. Among them are the Kelvin sign (U+212A), which renders asK, and the Angstrom sign (U+212B), which renders asÅ:The others are Greek mu (U+039C, U+03BC), capital sharp s (U+1E9E), 21 IPA letters (U+0253 to U+0292) and 5 Latin Extended-C and -D letters.
Change
Add
re.ASCII, so that case-insensitive matching applies to ASCII letters only. Every character inside the listed ranges still matches itself, so upper, lower and mixed-case local parts likeŁÓKAŚĆstill validate. I compared the old and new patterns over every code point: exactly those 31 characters are dropped and none are gained.Tests
The new rejection cases (five of the characters, each unquoted and quoted) fail on master and pass here. Positive cases cover upper, lower and mixed case inside the allowed ranges. The full suite (1589 tests),
ruff check,ruff format,pyrightand bandit pass, and the opengrep Unicode rule no longer reportsemail.py. A fuzz comparison against master over 60,000 random local parts found nothing newly accepted. Every newly rejected value contains a character outside ASCII and U+00A0 to U+024F.