testing-session-management-flaws
$
npx mdskill add xalgord/xalgorix/testing-session-management-flaws- During authorized penetration tests when assessing how an application creates, transports, and destroys sessions - When the application issues cookies or tokens after login and you need to verify they are bound, scoped, and invalidated correctly - For validating that logout, password change, email change, and 2FA activation revoke existing sessions - When testing multi-device / multi-IP scenarios where stolen or replayed cookies must be detected - During bug bounty programs targeting broken authentication and session handling (OWASP A07:2021)
SKILL.md
.github/skills/testing-session-management-flawsView on GitHub ↗
---
name: testing-session-management-flaws
description: Identifying and exploiting weaknesses in session handling including fixation, weak token entropy,
missing cookie flags, improper invalidation on logout/password change, and client-side session tampering.
domain: cybersecurity
subdomain: web-application-security
tags:
- penetration-testing
- session-management
- session-fixation
- cookies
- access-control
- owasp
- burpsuite
- web-security
version: '1.0'
author: xalgorix
license: Apache-2.0
nist_csf:
- PR.PS-01
- ID.RA-01
- PR.DS-10
- DE.CM-01
---
# Testing Session Management Flaws
## When to Use
- During authorized penetration tests when assessing how an application creates, transports, and destroys sessions
- When the application issues cookies or tokens after login and you need to verify they are bound, scoped, and invalidated correctly
- For validating that logout, password change, email change, and 2FA activation revoke existing sessions
- When testing multi-device / multi-IP scenarios where stolen or replayed cookies must be detected
- During bug bounty programs targeting broken authentication and session handling (OWASP A07:2021)
## Prerequisites
- **Authorization**: Written penetration testing agreement for the target application
- **Burp Suite Professional**: Proxy + Repeater + Sequencer (token randomness analysis)
- **Two test accounts**: User A (attacker) and User B (victim), ideally on two browsers/profiles
- **Two network egress points**: e.g. home IP + VPN/cloud box, to test IP-bound sessions and replay
- **curl / httpie**: For manual cookie crafting and replay outside the browser
- **Browser DevTools**: Application > Storage to inspect cookies, flags, and expiry
## Critical: Checks Most Often Missed
Session bugs are missed when testers only confirm "login works." For every
session, work through this checklist:
- **Find the REAL session cookie first**: apps set many cookies (analytics, CSRF,
consent). Delete cookies one at a time and re-request a protected page — the one
whose removal logs you out is the session cookie. Test only that one for the
flaws below.
- **No invalidation on security events** (the highest-signal miss): capture a
valid cookie, then in another session perform **logout**, **password change**,
**email change**, or **2FA activation**. Replay the OLD cookie afterwards. If it
still works, sessions are not revoked — critical for stolen-session scenarios.
- **Session fixation**: record the cookie value BEFORE authenticating, log in,
then compare. If the session identifier does NOT change on privilege elevation,
a pre-set cookie survives login and can be fixed onto a victim.
- **Replay from a different IP / machine / User-Agent**: paste the cookie into a
request from a second egress IP. If it is accepted with no re-auth or alert, the
session is not bound to client context.
- **Concurrent logins**: log in as the same user from two machines simultaneously.
Both staying valid with no notification is often in-scope for sensitive apps.
- **Client-side session data**: base64/JSON-decode the cookie. If it contains
`user=`, `role=`, `email=`, `isAdmin=` etc., tamper with another user's value and
replay — server may trust the cookie blindly.
- **Token entropy**: flip ONE bit/byte at a time across the token and replay to
find which segment is actually validated; a short validated segment = brute
forceable. Run Burp Sequencer on 5,000+ tokens for true randomness.
- **Missing cookie hardening**: check every session cookie for `HttpOnly`,
`Secure`, `SameSite`, an over-broad `Domain`, and an excessive/`Max-Age=∞` expiry.
- **Token leakage to third parties**: look for the session value in the URL, in
`Referer` headers sent to external hosts, or in analytics/error beacons.
## Workflow
### Step 1: Identify the Real Session Cookie Among Many
Enumerate all cookies and determine which one actually maintains the session.
```bash
# Capture the full Set-Cookie set right after login
curl -s -i -X POST "https://target.example.com/login" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data "username=userA&password=Passw0rd!" | grep -i '^set-cookie:'
# Typical output — only ONE of these is the session:
# Set-Cookie: SESSIONID=8f2a...; Path=/; HttpOnly
# Set-Cookie: _ga=GA1.2.123; Path=/
# Set-Cookie: csrftoken=abc; Path=/
# Set-Cookie: cookieconsent=1; Path=/
# Isolate the session cookie: remove one at a time and hit a protected page.
SESSION="SESSIONID=8f2a9c...; csrftoken=abc; _ga=GA1.2.123"
# Drop _ga -> still authenticated? (expected yes)
curl -s -o /dev/null -w "%{http_code}\n" \
-H "Cookie: SESSIONID=8f2a9c...; csrftoken=abc" \
"https://target.example.com/account"
# Drop SESSIONID -> logged out / 302 to /login => SESSIONID is the session cookie
curl -s -o /dev/null -w "%{http_code}\n" \
-H "Cookie: csrftoken=abc; _ga=GA1.2.123" \
"https://target.example.com/account"
```
### Step 2: Audit Cookie Security Flags, Scope, and Expiry
Inspect HttpOnly / Secure / SameSite, the Domain scope, and lifetime.
```bash
# Pull just the session Set-Cookie line and eyeball the attributes
curl -s -i -X POST "https://target.example.com/login" \
--data "username=userA&password=Passw0rd!" \
| grep -i 'set-cookie:.*SESSIONID'
# Findings to flag:
# - Missing HttpOnly -> readable via document.cookie (XSS can steal it)
# - Missing Secure -> sent over plain HTTP, sniffable
# - SameSite=None (no Secure) or absent -> CSRF / cross-site send
# - Domain=.example.com -> shared with every subdomain (broad theft surface)
# - Expires far future / Max-Age huge / no expiry -> long-lived stolen sessions
# Confirm the cookie is actually sent over cleartext HTTP (Secure missing)
curl -s -i "http://target.example.com/account" \
-H "Cookie: SESSIONID=8f2a9c..." | head -n1
# 200 over http:// with private data = Secure flag missing / not enforced
# Confirm HttpOnly from the browser console (should be inaccessible):
# document.cookie // session value must NOT appear here
```
### Step 3: Test Session Fixation (Pre/Post-Auth Comparison)
Verify the session identifier rotates on authentication.
```bash
# 1) Get a pre-auth (anonymous) session cookie by visiting the login page
curl -s -i "https://target.example.com/login" | grep -i 'set-cookie:.*SESSIONID'
# -> SESSIONID=PRE_AUTH_VALUE_1111
# 2) Authenticate USING that same cookie (simulate a planted/fixed value)
curl -s -i -X POST "https://target.example.com/login" \
-H "Cookie: SESSIONID=PRE_AUTH_VALUE_1111" \
--data "username=userA&password=Passw0rd!" \
| grep -i 'set-cookie:.*SESSIONID'
# 3) Compare:
# - New value issued after login => SAFE (rotation happens)
# - SESSIONID still = PRE_AUTH_VALUE_1111 => SESSION FIXATION
# An attacker who plants PRE_AUTH_VALUE_1111 on a victim (via link/XSS)
# gains the victim's authenticated session after they log in.
# Confirm exploitability: replay the pre-auth value AFTER victim login
curl -s -o /dev/null -w "%{http_code}\n" \
-H "Cookie: SESSIONID=PRE_AUTH_VALUE_1111" \
"https://target.example.com/account" # 200 with victim data = confirmed
```
### Step 4: Test Token Entropy by Bit/Byte Mutation
Find which part of the token is actually validated and measure randomness.
```bash
# Original token
TOK="A1B2C3D4E5F6G7H8I9J0"
# Mutate one character/byte at a time and replay; record which positions
# break the session vs. which are ignored (ignored = not part of secret).
for i in $(seq 0 $((${#TOK}-1))); do
mutated="${TOK:0:$i}X${TOK:$((i+1))}"
code=$(curl -s -o /dev/null -w "%{http_code}" \
-H "Cookie: SESSIONID=$mutated" \
"https://target.example.com/account")
echo "pos $i -> $code"
done
# If only positions 0-7 affect validity, the effective secret is 8 chars
# -> dramatically smaller keyspace, possibly brute forceable.
# Measure true randomness across many freshly issued tokens with Burp Sequencer:
# Burp > send a login response to Sequencer > "Live capture" 5000+ tokens
# > Analyze. Look for low effective entropy bits, structure, timestamps,
# or incrementing counters embedded in the token.
```
### Step 5: Test Invalidation on Logout, Password/Email Change, and 2FA
Confirm security-relevant events revoke existing sessions.
```bash
# Capture a known-good cookie for User A
COOKIE="SESSIONID=8f2a9c..."
# --- Logout test ---
# In a SECOND session/browser, click Logout for User A. Then replay COOKIE:
curl -s -o /dev/null -w "after-logout: %{http_code}\n" \
-H "Cookie: $COOKIE" "https://target.example.com/account"
# 200 = session NOT invalidated on logout (server only cleared client cookie)
# --- Password change test ---
# Change User A's password in another session, then replay the OLD cookie:
curl -s -o /dev/null -w "after-pw-change: %{http_code}\n" \
-H "Cookie: $COOKIE" "https://target.example.com/account"
# 200 = old sessions survive password reset (critical for compromised creds)
# --- Email change & 2FA activation tests (same pattern) ---
curl -s -o /dev/null -w "after-email-change: %{http_code}\n" \
-H "Cookie: $COOKIE" "https://target.example.com/account"
curl -s -o /dev/null -w "after-2fa-enable: %{http_code}\n" \
-H "Cookie: $COOKIE" "https://target.example.com/account"
# Any 200 after these events = stale session remains usable.
```
### Step 6: Test Concurrent / Cross-IP Replay and Client-Side Session Data
Check binding to client context and whether the cookie carries trusted data.
```bash
# --- Concurrent login ---
# Log in as User A from machine 1 and machine 2 at the same time.
# Both sessions valid + no notification = no concurrent-session control.
# --- Replay from a different IP / User-Agent ---
# Take a cookie issued from IP1 and replay it from IP2 (VPN/cloud box):
curl -s -o /dev/null -w "%{http_code}\n" \
-A "Mozilla/5.0 (different-UA)" \
-H "Cookie: SESSIONID=8f2a9c..." \
"https://target.example.com/account"
# 200 from a new IP/UA with no step-up = session not bound to context.
# --- Client-side session data tampering ---
# Decode a stateless/looking cookie:
echo "eyJ1c2VyIjoidXNlckEiLCJyb2xlIjoidXNlciJ9" | base64 -d
# -> {"user":"userA","role":"user"}
# Re-encode another user / elevated role and replay:
NEW=$(echo -n '{"user":"admin","role":"admin"}' | base64)
curl -s -H "Cookie: session=$NEW" "https://target.example.com/account" | head
# Accepted with admin context = server trusts unsigned client-side session data.
# --- Token leakage to third parties ---
# Look for the session value in URLs and Referer to external hosts:
# - grep Burp history for the token in query strings
# - load a page with an external <img>/<script> and check the outbound
# Referer header carries ?sessionid=... to a third-party domain.
```
## Key Concepts
| Concept | Description |
|---------|-------------|
| **Session Fixation** | Identifier set before login is not rotated, letting an attacker fix a known value onto a victim |
| **Token Entropy** | Amount of unpredictability in a session token; low entropy enables guessing/brute force |
| **HttpOnly** | Cookie flag preventing JavaScript (`document.cookie`) access, mitigating XSS-based theft |
| **Secure** | Cookie flag restricting transmission to HTTPS only, preventing cleartext sniffing |
| **SameSite** | Cookie flag (Strict/Lax/None) controlling cross-site sending; defends against CSRF |
| **Cookie Scope** | `Domain`/`Path` attributes; an over-broad `Domain=.example.com` shares the cookie with all subdomains |
| **Session Invalidation** | Server-side destruction of a session on logout or credential/security changes |
| **Stateless Session** | Session data stored client-side (cookie/JWT); must be signed or it can be tampered |
| **Concurrent Session Control** | Policy limiting or alerting on simultaneous active sessions for one account |
## Tools & Systems
| Tool | Purpose |
|------|---------|
| **Burp Suite Professional** | Proxy to capture cookies, Repeater to replay, Sequencer to measure token randomness |
| **Burp Sequencer** | Statistical analysis of token entropy across thousands of samples |
| **EditThisCookie / browser DevTools** | Inspect and edit cookies, view flags, domain scope, and expiry |
| **curl / httpie** | Manual cookie crafting, cross-IP replay, and flag verification |
| **jwt_tool** | Decode and tamper with JWT-based session tokens when used as sessions |
| **OWASP ZAP** | Free proxy alternative with session management testing add-ons |
## Common Scenarios
### Scenario 1: Session Survives Password Reset
After a user changes their password (often because they suspect compromise), the application generates a new session but leaves all previously issued sessions active. An attacker with a stolen cookie retains access indefinitely.
### Scenario 2: Pre-Auth Cookie Fixation
The login flow reuses the anonymous `SESSIONID` issued on the login page instead of rotating it. An attacker plants a known `SESSIONID` on a victim via a crafted link; once the victim logs in, the attacker's pre-known value is now authenticated.
### Scenario 3: Trusted Client-Side Role Cookie
A `session` cookie is base64-encoded JSON `{"user":"bob","role":"user"}` with no signature. Editing `role` to `admin` and replaying grants administrative access because the server trusts the cookie contents.
### Scenario 4: Missing HttpOnly Enables Cookie Theft
The session cookie lacks `HttpOnly`, so a reflected XSS payload reads `document.cookie` and exfiltrates the session, allowing full account takeover without credentials.
## Output Format
```
## Session Management Finding
**Vulnerability**: Session Not Invalidated on Password Change
**Severity**: High (CVSS 8.1)
**Location**: POST /account/change-password and session store
**OWASP Category**: A07:2021 - Identification and Authentication Failures
### Reproduction Steps
1. Log in as User A and capture session cookie SESSIONID=8f2a9c...
2. In a second browser, change User A's password
3. Replay the original SESSIONID against GET /account
4. Observe HTTP 200 with full account access using the pre-change cookie
### Affected Behaviors
| Event | Old Session After Event | Expected |
|-------|-------------------------|----------|
| Logout | Still valid (200) | Invalidated |
| Password change | Still valid (200) | All sessions revoked |
| Email change | Still valid (200) | All sessions revoked |
| 2FA activation | Still valid (200) | Re-authentication required |
### Cookie Hardening Gaps
| Flag/Attribute | Observed | Risk |
|----------------|----------|------|
| HttpOnly | Missing | XSS cookie theft |
| Secure | Missing | Cleartext interception |
| SameSite | Absent | CSRF / cross-site send |
| Domain | .example.com | Shared across all subdomains |
### Impact
- Stolen or leaked sessions remain valid after the victim takes remediation steps
- Account takeover persists through password reset, defeating incident response
- Token entropy reduced to effective 8 characters, enabling offline guessing
### Recommendation
1. Rotate the session identifier on every authentication and privilege change
2. Destroy all server-side sessions on logout, password change, email change, and 2FA enrollment
3. Set HttpOnly, Secure, and SameSite=Lax/Strict on the session cookie; scope Domain tightly
4. Generate session tokens from a CSPRNG with >=128 bits of entropy
5. Bind sessions to client context and enforce concurrent-session limits with alerting
```
More from xalgord/xalgorix
- abusing-hop-by-hop-headersTesting proxies, load balancers, and CDNs for improper handling of HTTP hop-by-hop headers, where an
- analyzing-macos-persistence-and-autostartEnumerating, planting, and hunting macOS persistence and auto-start (ASEP) locations during authorized
- api-discoveryAPI endpoint discovery including OpenAPI/Swagger detection, hidden versioning, REST/GraphQL enumeration, and content negotiation
- bypassing-binary-exploitation-mitigationsMethodology for identifying and defeating common binary hardening mitigations during authorized exploitation —
- bypassing-captcha-protectionsIdentifying weaknesses in CAPTCHA implementations and bypassing them via replay, field removal,
- bypassing-macos-gatekeeper-tcc-and-sipAssessing and bypassing macOS userland and platform security controls during authorized engagements -
- bypassing-restricted-shellsEscaping restricted shells (rbash, rksh, lshell), chroot jails, and language sandboxes (Lua, Python)
- bypassing-two-factor-and-otpIdentifying and exploiting flaws in two-factor authentication and one-time password verification
- deepExhaustive security assessment with maximum coverage, depth, and vulnerability chaining
- exploiting-ai-model-file-rceTesting machine-learning model files and model-loading services for remote code execution caused by insecure