This commit is contained in:
wheelman 2026-05-25 15:42:28 +00:00 committed by GitHub
commit 58ed3d9801
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 18 additions and 6 deletions

View file

@ -330,9 +330,11 @@ async def asgi_send_html(send, html, status=200, headers=None):
async def asgi_send_redirect(send, location, status=302):
# Prevent open redirect vulnerability: strip multiple leading slashes
# //example.com would be interpreted as a protocol-relative URL (e.g., https://example.com/)
location = re.sub(r"^/+", "/", location)
# Prevent open redirect vulnerability: collapse leading slashes and
# backslashes into a single slash. Browsers treat a backslash as a slash,
# so //example.com, /\example.com and /\/example.com would all otherwise be
# interpreted as a protocol-relative URL (e.g. https://example.com/).
location = re.sub(r"^[/\\]+", "/", location)
await asgi_send(
send,
"",

View file

@ -99,8 +99,18 @@ def test_custom_route_pattern_404(custom_pages_client):
assert ">Oh no</" in response.text
def test_custom_route_pattern_with_slash_slash_302(custom_pages_client):
# https://github.com/simonw/datasette/issues/2429
response = custom_pages_client.get("//example.com/")
@pytest.mark.parametrize(
"path",
(
# https://github.com/simonw/datasette/issues/2429
"//example.com/",
# https://github.com/simonw/datasette/issues/2680
# Browsers treat backslashes as slashes, so these are also open redirects
"/\\example.com/",
"/\\/example.com/",
),
)
def test_custom_route_pattern_open_redirect_302(custom_pages_client, path):
response = custom_pages_client.get(path)
assert response.status == 302
assert response.headers["location"] == "/example.com"