Glossary

What is session fixation — making a victim log in with an ID the attacker already knows

Session fixation makes a victim log in with a session ID the attacker planted. How it works and the fix: regenerate the ID on login and set cookie flags.

Published 2026-06-11 Updated 2026-10-06 6 min read
On this page

Session fixation is when the victim logs in with an ID the attacker prepared. Here's how it works and how to reliably prevent it (no attack steps).

Why it works

The cause is a design where the session ID doesn't change across login. If it doesn't, an ID the attacker knew before login still works as "authenticated" after login.

1) Attacker gets the victim to use a known session ID (via a link, etc.)
↓ the victim logs in with that ID still set
2) The ID isn't regenerated = the same ID becomes "authenticated"
↓ the attacker knew that ID all along
3) Accessing with the same ID = impersonating the victim
If the ID doesn't change at login, an ID the attacker knew beforehand becomes authenticated as-is.

It can pair with CSRF or XSS, but the essence of fixation itself is a single thing: the ID wasn't regenerated at login.

Japan's IPA (Information-technology Promotion Agency) guide "How to Secure Your Website" treats this as one form of improper session management and says every website with a login function needs to watch for it. Its fundamental fix is to start a new session after a successful login.

Fixation vs. hijacking vs. CSRF

These three are easy to mix up. All of them abuse a logged-in state, but they differ in what the attacker has and which defense works.

ItemSession fixationSession hijackingCSRF
What the attacker hasAn ID they prepared (known from the start)A stolen, already-issued IDNo ID at all
What happens to the victimThey log in with the planted IDTheir issued ID is stolenThey're made to send an unintended request
Main defenseRegenerate the ID at loginHttpOnly/Secure, XSS prevention, short lifetimesCSRF tokens, SameSite

Fixation is the one that a single step — regenerating the ID at login — fixes at the root.

Defense: regenerate the ID at login

1

Regenerate the session ID on successful login (most important)

The instant auth succeeds, discard the old ID and issue a new session ID (most frameworks' session regenerate/renew). Any pre-planted ID is invalidated immediately. Regenerate on privilege escalation (e.g. becoming admin) too.
2

Don't accept session IDs via the URL

Handle the session ID in a cookie and ignore an ID specified in a URL parameter. Close the path an attacker uses to make a victim adopt a 'fixed' ID.
3

Set cookie flags

Set session cookies HttpOnly (JS can't read), Secure (HTTPS only), and SameSite (curbs cross-site sending). Weakens related hijacking paths together.
4

Expire sessions sensibly

Expire on idle timeout, logout, and password change so a fixed ID doesn't stay valid indefinitely.

The OWASP Session Management Cheat Sheet recommends regenerating the ID on every privilege change and using a "strict" mechanism that only accepts IDs the server itself generated. A "permissive" mechanism that adopts an unknown ID brought in from outside leaves room for an attacker-chosen ID to be accepted.

What common frameworks do by default

Most frameworks regenerate the ID automatically if you use their standard login. The risk comes when you write the login yourself or turn the default protection off.

EnvironmentDefault behaviorWhat to check if you write it yourself
PHP (plain sessions)Doesn't regenerate on its own; session.use_strict_mode defaults to 0Call session_regenerate_id(true) on successful login; set use_strict_mode to 1
LaravelRegenerated automatically on auth when you use a starter kit or FortifyIf you hand-write login, call $request->session()->regenerate()
Spring SecurityOn by default (changeSessionId on Servlet 3.1+)Make sure nobody set sessionFixation().none()

In PHP, the settings that pass session IDs in URLs (enabling session.use_trans_sid, disabling session.use_only_cookies) were deprecated in PHP 8.4. If you carry an old config file forward, review them.

How to check your own site

On a site you manage, check these four things. Developer tools are all you need.

  1. In developer tools under "Application" (Firefox: "Storage"), note the session cookie value, then look again after logging in. If it hasn't changed, the ID isn't regenerated at login
  2. Check that the login page and post-login URLs carry no session ID such as PHPSESSID= or ;jsessionid=
  3. In the same panel, check the session cookie has HttpOnly, Secure and SameSite
  4. After logging out, put the old cookie value back and reload; confirm you are not logged in again

Cookie attributes are also covered by the site security audit, which checks sites whose ownership you have verified. Putting check 1 into an automated test whenever you touch the login flow means you notice immediately if the regeneration gets dropped.

This site's view: don't disable the framework's 'regenerate'

Session fixation is mostly prevented by a single step: regenerating the ID at login, not by elaborate custom code. The key is to not accidentally disable or forget to call the mechanism your framework already provides. Using a proven implementation's safe defaults beats hand-rolling your own session management. On this site we hold to "don't build auth/key handling yourself; don't disable the safe defaults." As with IDOR, authentication/authorization should be enforced by a mechanism on every request.

Sources (primary)

  • IPA, "How to Secure Your Website", 1.4 Improper session management — ipa.go.jp (start a new session after login; don't put IDs in URLs; Japanese)
  • OWASP Session Management Cheat Sheet — cheatsheetseries.owasp.org (regeneration on privilege change, strict mechanism, cookie attributes)
  • MITRE CWE-384: Session Fixation — cwe.mitre.org
  • PHP Manual, "Runtime Configuration" (sessions) — php.net (defaults such as use_strict_mode; 8.4 deprecations)
  • Laravel docs, "HTTP Session" — laravel.com / Spring Security, "Authentication Persistence and Session Management" — docs.spring.io

Classification

CWE classifies the types of weakness behind vulnerabilities; MITRE ATT&CK classifies attacker techniques. Both are maintained by MITRE and widely used to label vulnerability reports and detection rules.

CWE (weakness type)

CWE™: Copyright © 2006–2026, The MITRE Corporation. CWE is a trademark of The MITRE Corporation. The MITRE Corporation hereby grants you a non-exclusive, royalty-free license to use CWE for research, development, and commercial purposes. Any copy you make for such purposes is authorized on the condition that you reproduce MITRE’s copyright designation and this license in any such copy. CWE Terms of Use

FAQ

QHow is fixation different from session hijacking?
A

Hijacking steals someone's already-issued session ID. Fixation is the reverse: the attacker gets the victim to use an ID the attacker already knows, then waits for the victim to log in with it. It doesn't steal; it gets an attacker-known ID authenticated.

QWhat's the top defense?
A

Regenerate the session ID at the moment of login. Most frameworks/session libraries have this (session regenerate/renew): on successful auth, discard the old ID and issue a new one. That alone invalidates any ID the attacker planted in advance. Regenerate on privilege changes (e.g. becoming admin) too.

QWhy is putting a session ID in the URL dangerous?
A

An ID in the URL leaks easily via shared links, the Referer header, logs, and browser history, which gives an attacker a way to get the victim to use a 'fixed' ID. Handle session IDs in cookies, not URL parameters, and don't accept an ID specified via the URL.

QHow do I check whether my site is vulnerable to session fixation?
A

On your own site, open the browser's developer tools and compare the session cookie value before and after logging in. If the value is the same after login, the ID isn't being regenerated and you need to fix it. Also check that no session ID appears in the URL and that the cookie has HttpOnly, Secure and SameSite set.

QWhich PHP settings prevent session fixation?
A

Call session_regenerate_id(true) on successful login to switch to a new ID. In php.ini, set session.use_strict_mode to 1 so the server rejects IDs it didn't issue (the default is 0). Keep session.use_only_cookies at its default of 1 and session.use_trans_sid at its default of 0 so IDs are never passed in URLs.

QIf I use JWTs, can session fixation still happen?
A

If you don't use a server-side session ID and you issue a fresh token on successful login, the 'get a pre-chosen ID authenticated' attack is hard to pull off. But if a token issued before login keeps being used after login, the same problem can occur. Whatever the mechanism, the rule is to issue a new identifier at the moment of login.