Skip to content

Fix quadratic time in split_email on long input - #189

Merged
JoshData merged 1 commit into
JoshData:mainfrom
Keerthana-64:split-email-nfc-window
Nov 8, 2026
Merged

JoshData merged 1 commit into
JoshData:mainfrom
Keerthana-64:split-email-nfc-window

Conversation

@Keerthana-64

Copy link
Copy Markdown
Contributor

split_email decides whether each character combines with the ones after it by calling unicodedata.normalize("NFC", text[i:]), which copies and normalizes the rest of the string at every position, so parsing is quadratic and runs before any length check. on main (Apple M5, CPython 3.13), validate_email("́" * 100000 + "@example.com"), about 200 KB, takes 60 s of CPU to reject and 200,000 "é" take 18 s, an easy algorithmic-complexity denial of service for a signup form that hands a request field to validate_email the way WTForms' Email validator does. normalizing text[i:i + 32] brings those to 64 ms and 27 ms with linear growth; 32 is the character, the 30 combining characters in a row allowed by the unicode stream-safe text format (UAX #15), and one more. capping the input length up front would reject long display names, which validate today because they are not counted toward the 254-character limit. in about 80,000 differential runs against main with the allow_* options on, nothing changed between valid and invalid, and the only differences were error messages for inputs with more than 30 combining characters in a row. test_email_long_input_is_not_quadratic fails on main after about 15 s and passes here in 0.05 s; flake8 and the suite pass on 3.10 to 3.15, mypy on 3.10 to 3.14.

split_string_at_unquoted_special normalized text[i:] at every position
to see whether a character combines with the ones after it, which copies
and normalizes the rest of the string each time. limit the lookahead to
a 32-character window so parsing is linear in the length of the input.
@JoshData
JoshData merged commit ac2d67f into JoshData:main Nov 8, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants