Skip to content

Commit 17d339e

Browse files
committed
Reject raw ASCII controls before parsing URLs
1 parent 6ffd862 commit 17d339e

2 files changed

Lines changed: 26 additions & 1 deletion

File tree

‎src/validators/url.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ def url(
231231
(Literal[True]): If `value` is a valid url.
232232
(ValidationError): If `value` is an invalid url.
233233
"""
234-
if not value or re.search(r"\s", value):
234+
if not value or re.search(r"[\s\x00-\x1f\x7f]", value):
235235
# url must not contain any white
236236
# spaces, they must be encoded
237237
return False

‎tests/test_url.py‎

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,3 +232,28 @@ def test_returns_failed_validation_on_invalid_private_url(value: str, private: O
232232
def test_returns_string_for_valid_file_url(value: str):
233233
"""Test returns true on valid file url. Ref: RFC 8089."""
234234
assert url(value)
235+
236+
237+
@pytest.mark.parametrize("control", [chr(code) for code in range(32)] + ["\x7f"])
238+
@pytest.mark.parametrize(
239+
"template",
240+
[
241+
"{control}https://example.com/",
242+
"https://user{control}@example.com/",
243+
"https://example.com/a{control}b",
244+
"https://example.com/?q=a{control}b",
245+
"https://example.com/#a{control}b",
246+
],
247+
)
248+
def test_url_rejects_raw_ascii_controls(control: str, template: str):
249+
"""Reject raw control characters before URL parsing can discard them."""
250+
assert isinstance(url(template.format(control=control)), ValidationError)
251+
252+
253+
@pytest.mark.parametrize("encoded", ["%00", "%09", "%0A", "%1F", "%7F"])
254+
@pytest.mark.parametrize(
255+
"template", ["https://example.com/a{encoded}b", "https://example.com/?q=a{encoded}b"]
256+
)
257+
def test_url_accepts_percent_encoded_controls(encoded: str, template: str):
258+
"""Keep escaped data valid while rejecting literal control characters."""
259+
assert url(template.format(encoded=encoded)) is True

0 commit comments

Comments
 (0)