Guard Point.from_string against ReDoS on very long inputs (#608) - #610
Merged
Conversation
POINT_PATTERN begins with '.*?' (to allow a coordinate embedded after some leading text) and matches whitespace in several overlapping places. On a long non-matching input such as '<' + ' ' * 3000 + 'X' this backtracks quadratically (CWE-1333): ~0.2s for 3 KB, growing with input size, so an endpoint that passes user input to geopy.Point() can be tied up with modest request volume. A valid coordinate string is short, so cap the input length before matching and reject longer strings with the usual ValueError. Atomic groups / possessive quantifiers would help but require Python 3.11+, while geopy supports 3.7+. Fixes geopy#608.
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.
Summary
Fixes #608 (ReDoS in
geopy.Point, CWE-1333).POINT_PATTERNstarts with.*?(so a coordinate can appear after some leading text, e.g.UT: N 39°20' 0'') and matches whitespace in several overlapping places. On a long non-matching input it backtracks quadratically:An endpoint that forwards user input to
geopy.Point()(as the docs suggest for coordinate strings) can be tied up with modest request volume.Fix
A valid coordinate string is short (the longest in the test suite is 46 chars), so cap the input length in
from_string()before matching and reject longer strings with the usualValueError. This bounds the worst‑case matching time to well under a millisecond.Atomic groups / possessive quantifiers would also help, but they require Python 3.11+ and geopy supports 3.7+; and because the leading
.*?scans every position, the match is inherently O(n²) regardless — so bounding the length is the reliable mitigation.The limit (256) is a generous ~5× the longest realistic coordinate string; happy to adjust it, or add a changelog entry, if you prefer.
Verification
test_point_from_string_rejects_overlong_input: a 100 000‑char adversarial string must raiseValueErrorin well under a second (it takes tens of seconds onmaster— the bound has a huge margin, so it isn't timing‑sensitive).test/test_point.pypasses (27); all documentedfrom_stringexamples (including theUT:‑prefixed one) still parse;flake8andisortclean.Disclosure: prepared with AI assistance; reviewed and verified locally.