Replace catastrophically backtracking email/URL patterns with safe alternatives #153
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix-redos-string-patterns"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
String.EMAILPATTERNandString.URLPATTERN(Scott Gonzalez, 2009) are textbook ReDoS vulnerabilities. Their domain-matching section used an alternation(A|B)where alternative B included.in its middle-character class:This made the label-separator
.ambiguous: a dot could be consumed either inside a label by alternative B, or between labels by the outer\.separator. For a hostname with n dot-separated labels, Rhino's backtracking NFA had to explore 2ⁿ distinct parse paths when the overall match failed (e.g. an invalid TLD). With ~15 labels the thread spins for days.See antville/antville#229, where 9 request threads were each stuck in
NativeRegExp.executeREBytecodefor up to 18 800 minutes (~13 days).Fix
Exclude
.from the label character classes. Each dot then has exactly one role (separator), the parse tree is linear, and backtracking is O(n).!is also excluded from domain/hostname labels — it is not a valid DNS label character (RFC 952/1123), though it remains permitted in the email local part (before@) per RFC 5322.The new patterns:
Unicode and IDN are fully supported:
[^\s@.!]passes every non-ASCII character unchanged. The.test()interface is preserved.Testing (verified on antville-test.de)
user@example.com,a@b.io,user+tag@sub.domain.co.uk→ valid ✓user!name@example.com(!in local part) → valid ✓用户@例子.广告(Chinese Unicode email) → valid ✓user@[1.2.3.4](IPv4 literal),user@10.0.0.1(bare IPv4) → valid ✓notanemail,user@,@domain,user@domain(no TLD) → invalid ✓user@[IPv6:2001:db8::1](IPv6 literal) → invalid ✓user@invalid!(!in domain) → invalid ✓http://example.com,https://例子.广告/path(IDN URL) → valid ✓http://example.com/path!here(!in path) → valid ✓javascript:alert(1),http://,http://exa!mple.com(!in host) → invalid ✓user@a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.invalid!→ 83 ms, correctly rejected ✓a54e8af67fto69cfc85f10