From fc24ba068d0400f3cf027a56e8de88f6e5182d24 Mon Sep 17 00:00:00 2001 From: Finn Stutzenstein Date: Wed, 21 Oct 2026 11:51:35 +0000 Subject: [PATCH] Prevent session fixation on login login() kept the existing session id and CSRF token. Anyone who knew the id before (e.g. via cookie injection) was logged in as the victim afterwards and knew the CSRF token, too. - login() clears the session after a successful check. Since the fix of Session.clear() this deletes the old store entry, drops the CSRF token, resets the timestamps and assigns a new id. - open_session no longer adopts signed ids without a store entry, so an id chosen by the client never becomes a session id. Co-Authored-By: Claude Opus 5.5 --- max/auth/auth.py | 2 ++ max/sessions.py | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/max/auth/auth.py b/max/auth/auth.py index 774bd06..46adc1e 100644 --- a/max/auth/auth.py +++ b/max/auth/auth.py @@ -22,6 +22,8 @@ def login(email, password): if not user.enabled: return t("This account is not enabled!") + # Start a new session (new id, new CSRF token) against session fixation. + session.clear() session["user_id"] = user.id return None diff --git a/max/sessions.py b/max/sessions.py index 335740d..f8c9732 100644 --- a/max/sessions.py +++ b/max/sessions.py @@ -134,8 +134,12 @@ class SessionInterface(FlaskSessionInterface): session_id = session_id.decode("utf-8", "strict") data = session_storage[session_id] + if data is None: + # Never adopt an id chosen by the client (session fixation) + return self.make_session_object() + session = self.make_session_object(session_id, data=data) - if data is not None and session.is_expired(time.monotonic()): + if session.is_expired(time.monotonic()): del session_storage[session_id] return self.make_session_object() return session