1

Vulnerability

Attack Flow

⚠️

Vulnerability

The defining feature of fixation, compared to most session attacks, is that the attacker doesn't need to intercept or steal anything from the victim. They control the session ID from the very beginning, before the victim ever logs in.

Attacker visits the target site
        ↓
Server issues a valid, pre-authentication session ID
        ↓
Attacker now holds a session ID the server will recognize

Some applications make even this step unnecessary:

Application accepts any session ID it has never seen before
   (rather than only recognizing IDs it issued itself)
        ↓
Attacker doesn't need to visit first — they simply invent an ID

Next, the attacker gets the victim to start a session using that specific ID.

Attacker crafts a link:
   https://example.com/login?PHPSESSID=attacker-chosen-value
        ↓
Sent to victim via phishing email, forum post, or message
        ↓
Victim clicks the link
        ↓
Victim's browser is now carrying the attacker's chosen session ID

Where the application only accepts session IDs via cookie, the delivery has to go a different way:

Application accepts session IDs via cookie only
        ↓
Attacker needs another way to set that cookie in the victim's browser
        ↓
   XSS elsewhere on the same site or a related subdomain
        OR
   A response-splitting bug injecting a Set-Cookie header
        ↓
Victim's browser now holds: Session ID = attacker-chosen-value

Then the victim, unaware anything is wrong, logs in normally:

Victim enters real credentials on the real site
        ↓
❌ Application authenticates WITHOUT generating a new session ID
        ↓
The attacker-planted ID is now marked as fully authenticated
        ↓
Attacker already knows this ID
        ↓
Attacker uses it directly → logged in as the victim

No password, token, or credential theft required at any point.

2

Vulnerability

Login State Reuse

⚠️

Vulnerability

The single behavior that makes this whole attack possible and the reason it's worth naming as its own concept rather than folding it entirely into "weak session IDs" is login state reuse.

Pre-authentication session created
        ↓
Same underlying session object carried across the login boundary
        ↓
Login only adds an "authenticated" flag to it
        ↓
❌ The session IDENTIFIER itself never changes

The correct model treats authentication as the boundary where a genuinely new session begins:

Pre-authentication session created
        ↓
Authentication event occurs
        ↓
✅ A new session identifier is issued
        ↓
Session DATA migrates to the new ID
   (cart contents, partially filled form, UTM params, CSRF token)
        ↓
Old identifier is destroyed

This pattern is often chosen for good, ordinary reasons that have nothing to do with security it's simpler to keep one session object alive across the login boundary so that data collected before authentication doesn't need to be explicitly migrated. But that convenience is exactly the vulnerability: whatever identity the session ID represented before login quite possibly one the attacker deliberately seeded is preserved through login instead of being replaced.

The distinction to hold onto is between session data and the session identifier. It's fine, and often desirable, to carry data forward across login. It is not fine to carry the identifier forward the ID itself needs to change at the authentication boundary, even while the data attached to it is preserved under the new ID.

3

Vulnerability

Session Rotation Failures

⚠️

Vulnerability

Given that the fix is well known regenerate the session ID at login most fixation vulnerabilities found in real applications today aren't cases where nobody attempted the fix. They're cases where the regeneration was implemented in a way that doesn't actually close the hole.

Regenerating the cookie value but not the server-side record.

New-looking session ID set in the response cookie
        ↓
❌ Server-side session store still keys the same data to BOTH the old and new ID
        ↓
Attacker's originally-planted ID never actually stops being valid

Rotating on some login paths but not others.

Username/password login   →   regenerates session ID
Remember-me auto-login    →   regeneration forgotten
SSO / social login callback →   regeneration forgotten
Magic-link login          →   regeneration forgotten
Password-reset auto-login →   regeneration forgotten

Each authentication path is a separate opportunity for this bug to exist independently — regeneration needs to be centralized (a single function every login path calls) rather than reimplemented per flow, precisely so it can't be forgotten on the path nobody thought to check.

Failing to invalidate the old ID after issuing the new one.

New session ID issued
        ↓
Session data copied across to the new ID
        ↓
Old ID's entry in the session store is never explicitly destroyed
        ↓
Old ID remains technically valid if presented
        ↓
Attacker's planted ID still authenticates successfully
        ↓
The "fix" just added a second valid credential alongside the first

Session IDs carried in the URL.

Session ID transmitted via URL rewriting instead of a cookie
        ↓
Old ID persists in:
   bookmarks · browser history · cached pages · any shared link
        ↓
All of these keep referencing the pre-rotation ID indefinitely

This is one of several reasons cookie-based session transport is strongly preferred over URL-based session identifiers.

Conditional or best-effort regeneration.

Regeneration gated behind a condition, 
e.g. "only regenerate if the session doesn't already have a user ID set"
        ↓
Attacker's fixation attempt happens to carry some unrelated pre-existing attribute
        ↓
Condition doesn't hold → regeneration silently skipped

The throughline across all of these is that regeneration needs to be unconditional, centralized, and complete a new ID issued, the old one actually destroyed server-side, applied identically across every path that can result in an authenticated session, and done as a mandatory step in the authentication flow rather than a conditionally triggered one.

Capture the session ID BEFORE login
        ↓
Log in
        ↓
Compare pre-login and post-login session IDs

ID unchanged                     → fixation vulnerability present
Pre-login ID still works after   → rotation is incomplete
ID changed AND pre-login ID dead → correctly fixed

You've completed Session Management

Great work — explore other topics to keep learning.