Skip to content

fix quadratic backtracking in UrlValidator authority pattern - #1737

Open
fr-manvi wants to merge 1 commit into
apache:masterfrom
fr-manvi:urlvalidator-authority-redos
Open

fr-manvi wants to merge 1 commit into
apache:masterfrom
fr-manvi:urlvalidator-authority-redos

Conversation

@fr-manvi

Copy link
Copy Markdown
Contributor

UrlValidator's authority regex backtracks quadratically on an authority that contains no '@':

  • the userinfo group (.+(:.*)?@)? overlaps the outer .+ with the inner (:.*)?, so a value like http:// followed by tens of thousands of colons takes tens of seconds and scales O(n^2)
  • isValidAuthority gets the authority straight from the submitted URL, and a UrlValidator normally sits on a public, often pre-auth form field, so a few requests each pin a request thread
  • (:.*)? is redundant since .+ already matches :, and the group is never read, so (.+@)? accepts the identical set of URLs and parses the same host and port

The regression test submits http:// plus 50k colons and asserts it resolves well under a second; it times out against the old pattern and passes with the fix.

The userinfo part of AUTHORITY_PATTERN was (.+(:.*)?@)?. The outer .+ and
the inner (:.*)? are both greedy and overlap, so when the authority contains
no '@' the matcher explores every way of splitting the two quantifiers before
failing. isValidAuthority receives the authority straight from the submitted
URL, so an input like http:// followed by tens of thousands of colons drives
that into quadratic work: ~32KB of colons takes tens of seconds, and it scales
O(n^2). A UrlValidator is commonly attached to a public URL field, so a handful
of such requests exhaust a request thread each.

The inner (:.*)? is redundant: .+ already matches ':' and every other
character, and the group is never read. Rewriting the userinfo as (.+@)?
matches the exact same strings and captures the same host, port and extra
groups, while reducing userinfo matching to a single linear scan. The host,
port and extra group indices move from 3/4/5 to 2/3/4 to match.

Applications relying on the old behaviour see no change: the set of accepted
URLs and the parsed host and port are identical.
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.

1 participant