SecureBlockLog inStart a pentest
Vulnerability Repository
HighAuthentication

Session Fixation

An attacker pre-sets a victim's session ID before authentication, then uses that known ID to hijack the session after the victim successfully logs in.

CVSS 8.0CWE CWE-384OWASP A07:2021 — Identification and Authentication Failures

Description

Session fixation (CWE-384) is an attack where the adversary establishes a known session identifier before the victim authenticates, then waits for the victim to log in. If the application reuses the same session ID across the authentication boundary — rather than issuing a new session ID upon successful login — the attacker can use the pre-established (fixed) session ID to access the now-authenticated session.

The vulnerability exists in applications that allow session IDs to be established before authentication and that fail to rotate the session ID when the user's privilege level changes. This falls under OWASP A07:2021 (Identification and Authentication Failures) and is distinct from session hijacking (which steals an already-authenticated session) because session fixation enables the attack before authentication occurs.

Session fixation is commonly exploited through URL-based session IDs (now rare but still found in legacy applications), applications that accept session IDs in query parameters, CRLF injection into Set-Cookie headers, subdomain-based cookie scope issues, and applications that allow session initialization via client-supplied values.

How It Works

The attack proceeds in three phases:

Phase 1 — Obtain a valid (but unauthenticated) session ID. The attacker visits the application and receives a session cookie:

GET / HTTP/1.1
Host: target.com

Response:
Set-Cookie: PHPSESSID=abc123xyz; Path=/; HttpOnly

Phase 2 — Fix the session ID in the victim's browser. The attacker must get the victim to use this specific session ID. Common methods:

  • URL injection: https://target.com/login?PHPSESSID=abc123xyz — if the application accepts session IDs from query parameters (common in PHP applications with session.use_trans_sid enabled)
  • CRLF injection: inject Set-Cookie: PHPSESSID=abc123xyz via a CRLF injection vulnerability in a redirect header
  • Subdomain XSS: execute JavaScript on sub.target.com that sets document.cookie = "PHPSESSID=abc123xyz; Domain=.target.com" — the cookie is then sent to all target.com subdomains

Phase 3 — Wait for the victim to authenticate. The victim visits the login page (their browser sends PHPSESSID=abc123xyz), enters their credentials, and is authenticated. If the application doesn't rotate the session ID:

POST /login PHPSESSID=abc123xyz
→ Authentication succeeds
→ Session abc123xyz is now authenticated as victim@example.com

The attacker uses PHPSESSID=abc123xyz in their browser and is logged in as the victim.

In modern applications, session fixation most frequently appears via subdomain cookie scoping issues, where a vulnerable subdomain (uploads.target.com) can set cookies for the parent domain (target.com), allowing an XSS on the subdomain to fix a session for the main application.

Impact

  • Authenticated Session Hijacking — Full access to the victim's account without stealing credentials or intercepting traffic
  • Privilege Escalation — If an administrator is tricked into using a fixed session, the attacker gains admin-level access
  • Account Takeover — Persistent session access until the victim explicitly logs out or the session expires
  • Cross-CSRF Exploitation — A fixed session can be used in conjunction with CSRF attacks to perform actions as the victim

Detection

  1. Test session ID rotation on login — obtain a pre-login session ID by visiting the application without authenticating. Log in and compare the session ID. If the ID is identical before and after authentication, session fixation is present.
  2. Test session ID acceptance from query parameters — attempt GET /login?PHPSESSID=testsessionid or ?sessionid=testsessionid. Then authenticate and check whether the application uses the provided ID.
  3. Test session ID acceptance in POST body — some applications accept _token or session_id in the request body. Submit a known value and check if it is used.
  4. Test subdomain cookie scope — check whether cookies set by a subdomain (test.target.com) are sent to the main application (target.com). If so, and if any subdomain has an XSS vulnerability, session fixation is possible.
  5. Test session ID reuse after privilege change — authenticate as a low-privilege user, note the session ID, escalate privileges within the app (e.g., become an admin), and verify the session ID changes at each privilege boundary.
  6. Inspect Set-Cookie attributes — use Burp Suite to examine the Domain and Path attributes of session cookies. An overly broad Domain=.target.com increases the session fixation attack surface.

Remediation

Regenerate the session ID immediately after authentication. This is the primary and most critical control:

// PHP
session_start();
// ... validate credentials ...
session_regenerate_id(true); // true = delete old session
$_SESSION['user_id'] = $authenticated_user_id;
// Express.js
req.session.regenerate(function(err) {
  req.session.userId = authenticatedUser.id;
  res.redirect('/dashboard');
});

Regenerate the session ID at every privilege escalation. Not just at login — also when a user elevates from regular to admin, when MFA is completed, and when sudo-style re-authentication occurs.

Reject server-side sessions from URL parameters and POST bodies. Configure your session library to only accept session IDs from cookies, not from query strings or request bodies. In PHP: session.use_only_cookies = 1.

Scope cookies to the exact hostname. Use Domain=target.com (without the leading dot) to prevent subdomains from setting cookies that apply to the main application.

Set short session timeouts. Limit the window during which a fixed session can be activated by giving unauthenticated sessions a short TTL (5-15 minutes).

Ready when you are
Scope a pentest in the next two minutes.
Start scoping