Prevent open redirect via backslash in path (#2680)

asgi_send_redirect() only collapsed leading forward slashes, so a path
like /\example.com/ produced a Location of /\example.com. Browsers
normalise backslashes to forward slashes, turning that into the
protocol-relative //example.com and redirecting off-site. Collapse any
run of leading slashes and backslashes to a single slash.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Simon Willison 2026-06-10 23:17:16 -07:00
commit 1c514d69f6
2 changed files with 26 additions and 3 deletions

View file

@ -104,3 +104,24 @@ def test_custom_route_pattern_with_slash_slash_302(custom_pages_client):
response = custom_pages_client.get("//example.com/")
assert response.status == 302
assert response.headers["location"] == "/example.com"
@pytest.mark.parametrize(
"path",
(
"/\\example.com/",
"/\\\\example.com/",
"/\\/example.com/",
),
)
def test_redirect_does_not_allow_backslash_open_redirect(custom_pages_client, path):
# https://github.com/simonw/datasette/issues/2680
# Browsers normalise backslashes to forward slashes, so a Location of
# /\example.com would be treated as the protocol-relative //example.com
response = custom_pages_client.get(path)
assert response.status == 302
location = response.headers["location"]
assert location == "/example.com"
# Must not start with anything a browser reads as protocol-relative
assert not location.startswith("//")
assert not location.startswith("/\\")