Skip to content

Commit d76e23b

Browse files
Reject excessively nested URL encoding in paths and base URLs
Co-authored-by: Shri Sukhani <shrisukhani@users.noreply.github.com>
1 parent 677a576 commit d76e23b

4 files changed

Lines changed: 35 additions & 0 deletions

File tree

hyperbrowser/client/base.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ def _build_url(self, path: str) -> str:
9696
if next_decoded_path == decoded_path:
9797
break
9898
decoded_path = next_decoded_path
99+
else:
100+
raise HyperbrowserError("path contains excessively nested URL encoding")
99101
if "\\" in decoded_path:
100102
raise HyperbrowserError("path must not contain backslashes")
101103
if "\n" in decoded_path or "\r" in decoded_path:

hyperbrowser/config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ def normalize_base_url(base_url: str) -> str:
7373
if next_decoded_base_path == decoded_base_path:
7474
break
7575
decoded_base_path = next_decoded_base_path
76+
else:
77+
raise HyperbrowserError("base_url path contains excessively nested URL encoding")
7678
if "\\" in decoded_base_path:
7779
raise HyperbrowserError("base_url must not contain backslashes")
7880
if any(character.isspace() for character in decoded_base_path):
@@ -98,6 +100,8 @@ def normalize_base_url(base_url: str) -> str:
98100
if next_decoded_base_netloc == decoded_base_netloc:
99101
break
100102
decoded_base_netloc = next_decoded_base_netloc
103+
else:
104+
raise HyperbrowserError("base_url host contains excessively nested URL encoding")
101105
if "\\" in decoded_base_netloc:
102106
raise HyperbrowserError("base_url host must not contain backslashes")
103107
if any(character.isspace() for character in decoded_base_netloc):

tests/test_config.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from types import MappingProxyType
2+
from urllib.parse import quote
23

34
import pytest
45

@@ -436,3 +437,13 @@ def test_client_config_normalize_base_url_validates_and_normalizes():
436437
match="base_url path must not contain encoded query or fragment delimiters",
437438
):
438439
ClientConfig.normalize_base_url("https://example.local/%253Fapi")
440+
deeply_encoded_dot = "%2e"
441+
for _ in range(11):
442+
deeply_encoded_dot = quote(deeply_encoded_dot, safe="")
443+
with pytest.raises(
444+
HyperbrowserError,
445+
match="base_url path contains excessively nested URL encoding",
446+
):
447+
ClientConfig.normalize_base_url(
448+
f"https://example.local/{deeply_encoded_dot}/api"
449+
)

tests/test_url_building.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import pytest
2+
from urllib.parse import quote
23

34
from hyperbrowser import Hyperbrowser
45
from hyperbrowser.config import ClientConfig
@@ -142,6 +143,16 @@ def test_client_build_url_rejects_runtime_invalid_base_url_changes():
142143
):
143144
client._build_url("/session")
144145

146+
deeply_encoded_dot = "%2e"
147+
for _ in range(11):
148+
deeply_encoded_dot = quote(deeply_encoded_dot, safe="")
149+
client.config.base_url = f"https://example.local/{deeply_encoded_dot}/api"
150+
with pytest.raises(
151+
HyperbrowserError,
152+
match="base_url path contains excessively nested URL encoding",
153+
):
154+
client._build_url("/session")
155+
145156
client.config.base_url = "https://example.local%2Fapi"
146157
with pytest.raises(
147158
HyperbrowserError,
@@ -270,6 +281,13 @@ def test_client_build_url_rejects_empty_or_non_string_paths():
270281
HyperbrowserError, match="path must not contain encoded fragment delimiters"
271282
):
272283
client._build_url("/api/%23segment")
284+
nested_encoded_segment = "%2e"
285+
for _ in range(11):
286+
nested_encoded_segment = quote(nested_encoded_segment, safe="")
287+
with pytest.raises(
288+
HyperbrowserError, match="path contains excessively nested URL encoding"
289+
):
290+
client._build_url(f"/{nested_encoded_segment}/session")
273291
finally:
274292
client.close()
275293

0 commit comments

Comments
 (0)