Skip to content

Commit 9662f67

Browse files
committed
Reject invalid percent-encoding in URL validator
1 parent 70de324 commit 9662f67

1 file changed

Lines changed: 17 additions & 15 deletions

File tree

src/validators/url.py

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@
1111
from .utils import validator
1212

1313

14+
def _validate_percent_encoding(value: str):
15+
"""Validate percent-encoding in a URL component."""
16+
return not bool(re.search(r"%(?![0-9A-Fa-f]{2})", value))
17+
18+
1419
@lru_cache
1520
def _username_regex():
1621
return re.compile(
@@ -138,25 +143,22 @@ def _validate_optionals(path: str, query: str, fragment: str, strict_query: bool
138143
"""Validate path query and fragments."""
139144
optional_segments = True
140145
if path:
141-
optional_segments &= bool(_path_regex().match(path))
142-
try:
143-
if (
144-
query
145-
# ref: https://github.com/python/cpython/issues/117109
146-
and parse_qs(query, strict_parsing=strict_query, separator="&")
147-
and parse_qs(query, strict_parsing=strict_query, separator=";")
148-
):
149-
optional_segments &= True
150-
except TypeError:
151-
# for Python < v3.9.2 (official v3.10)
152-
if query and parse_qs(query, strict_parsing=strict_query):
153-
optional_segments &= True
146+
optional_segments &= bool(_path_regex().match(path)) and _validate_percent_encoding(path)
147+
if query:
148+
optional_segments &= _validate_percent_encoding(query)
149+
if optional_segments:
150+
try:
151+
optional_segments &= bool(parse_qs(query, strict_parsing=strict_query, separator="&")) and bool(
152+
parse_qs(query, strict_parsing=strict_query, separator=";")
153+
)
154+
except TypeError:
155+
optional_segments &= bool(parse_qs(query, strict_parsing=strict_query))
154156
if fragment:
155157
# See RFC3986 Section 3.5 Fragment for allowed characters
156158
# Adding "#", see https://github.com/python-validators/validators/issues/403
157159
optional_segments &= bool(
158160
re.fullmatch(r"[0-9a-z?/:@\-._~%!$&'()*+,;=#]*", fragment, re.IGNORECASE)
159-
)
161+
) and _validate_percent_encoding(fragment)
160162
return optional_segments
161163

162164

@@ -254,4 +256,4 @@ def url(
254256
rfc_2782,
255257
)
256258
and _validate_optionals(path, query, fragment, strict_query)
257-
)
259+
)

0 commit comments

Comments
 (0)