Safeguard
Application Security•

What is session fixation and how do you spot it in code review?

Session fixation works when an app keeps the same session ID across login. See a constructed example, the code smell to grep for, and the fix to apply.

Safeguard Security Team
4 min read

Session fixation is an attack where the attacker plants a known session ID in a victim's browser before login, then uses that same ID after the victim authenticates. It works only if the application keeps the ID across the login. The fix is to issue a new session ID whenever privilege changes.

How does the attack work?

OWASP describes it this way: the application, when authenticating a user, does not assign a new session ID, so an existing one stays valid. The attacker obtains a valid session ID, induces a victim to authenticate with it, and then hijacks the now-authenticated session using the ID they already know. It differs from session hijacking in timing: the attack starts before the user logs in.

OWASP lists several ways to plant the ID: a session token in a URL argument sent as a link, a hidden form field, a cookie set through client-side script after an XSS flaw, a meta tag injection, or a Set-Cookie value in a response header the attacker can influence.

What does a constructed example look like?

A small web shop creates a session for every visitor on the first request and stores the cart in it. The login handler checks the password and then sets one field on the existing session.

def login(request):
    user = check_password(request.form["email"], request.form["password"])
    if user:
        request.session["user_id"] = user.id
        return redirect("/account")

An attacker visits the shop, receives session ID A, and sends the victim a link that carries ID A, or uses a related flaw to set the cookie. The victim logs in. The handler writes the user id into session A. The attacker, who also holds A, now loads the account page as the victim. No password was stolen.

What is the code smell in review?

Look at every place where a login, role switch, password change or step-up authentication succeeds. Ask one question: is the session ID replaced at that moment? Red flags:

  • A login handler that only sets fields on the current session.
  • A custom session store that lets the client choose the ID.
  • Session IDs accepted from a URL parameter or form field as well as from cookies.
  • A framework's session regeneration call that is absent, or wrapped in a condition that is skipped for some login paths such as single sign on callbacks or remember-me flows.

OWASP's Session Management Cheat Sheet says to renew the session ID after any privilege level change, and to accept session IDs only through cookies, noting that a web app can accept other exchange mechanisms too, so you must test what it actually accepts.

What is the fix?

def login(request):
    user = check_password(request.form["email"], request.form["password"])
    if user:
        request.session.regenerate_id()
        request.session["user_id"] = user.id
        return redirect("/account")

The exact call depends on the framework. The point is that the old ID dies at login and a fresh one is issued, so a value planted earlier is useless. Most mature frameworks provide this and often do it by default, which is why OWASP recommends built-in session management over home-made versions, while warning that frameworks have had flaws as well. Check, do not assume.

What else reduces risk?

Cookie attributes help against related attacks: the Secure attribute keeps the cookie off plain HTTP. Do not switch a session between HTTP and HTTPS. Add idle and absolute timeouts, and destroy the session on logout. Fixing XSS closes one route for planting cookies from script.

How to check or apply this

  1. Find every authentication and privilege change path in the code base, including SSO callbacks and API token exchange.
  2. Confirm each one regenerates the session ID and discards the old one on the server.
  3. Test by hand: note the session cookie before login, log in, and confirm it changed.
  4. Confirm that IDs in URLs or form fields are rejected.
  5. Add an automated test that fails if the cookie value is unchanged after login.
  6. Review cookie attributes and timeouts.

Quick check

Does HTTPS prevent session fixation?

No. HTTPS protects the ID in transit but does not stop an attacker from planting a known ID that the application keeps after login.

When must the session ID change?

Per OWASP, after any privilege level change, with login the most important case.

Sources

Last reviewed: 18 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.