Tett open redirect i login-next

next-parameteren godtok "//evil.com", som nettlesere tolker som en
ekstern URL. Nå godtas bare stier som starter med én skråstrek.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JcEy43fNYpwg6K6oTKakWR
This commit is contained in:
Ole-Morten Duesund 2026-08-26 12:16:44 +02:00
commit 227faff373
2 changed files with 15 additions and 1 deletions

View file

@ -129,7 +129,9 @@ def login():
session["uid"] = user.id
csrf_token()
nxt = request.form.get("next") or url_for("admin.index")
if not nxt.startswith("/"):
# Kun stier på dette nettstedet: "//evil.com" og "/\\evil.com"
# tolkes som skjema-relative URL-er av nettlesere.
if not nxt.startswith("/") or nxt.startswith("//") or "\\" in nxt:
nxt = url_for("admin.index")
return redirect(nxt)
flash("Feil brukernavn eller passord.", "error")

View file

@ -109,6 +109,18 @@ def test_guest_flow_and_isolation(client, cfg):
assert client.get("/nytt-innlegg/").status_code == 404
def test_login_next_no_open_redirect(client):
for bad in ("//evil.com", "/\\evil.com", "https://evil.com"):
r = client.post(
"/admin/login", data={"username": "eier", "password": "hemmelig123", "next": bad}
)
assert r.headers["Location"] == "/admin/", bad
r = client.post(
"/admin/login", data={"username": "eier", "password": "hemmelig123", "next": "/admin/users"}
)
assert r.headers["Location"] == "/admin/users"
def test_csrf_enforced(client):
login(client)
assert client.post("/admin/new", data={}).status_code == 403