Weak Session IDs
Also known as: Predictable session tokens, Low-entropy session identifiers, Session ID prediction, CWE-330
A web flaw in which session identifiers are generated from a predictable source or are too short, so a valid identifier for another user's session can be guessed instead of having to be stolen.
How it works
Weak session identifiers are a flaw in how an application creates the token that stands in for a signed-in user. The identifier is a bearer credential: whoever presents a valid one is treated as that user. Its only protection is that nobody else can produce a valid value, so any predictability or shortness in its generation weakens every account at once.
The weakness comes from the source of the value. A sequential counter, the current time, a hash of the username, or the output of a general-purpose random function all have structure that reduces the number of values that are realistically possible. A token that is also short leaves a small space that can be covered by volume alone. In each case the identifier is a guessable value rather than a secret.
The defence is to generate identifiers from a cryptographically secure random number generator, with at least 128 bits of entropy, and to let the framework's session manager do it rather than hand-rolling one. Cookies should carry Secure, HttpOnly and SameSite, the session should be rotated at login, and idle and absolute timeouts limit how long any value stays useful.
A reviewer's quickest test is to read the generation code for its source of randomness, then look at a sample of issued identifiers for patterns, such as increasing values or shared prefixes. Either finding stands on its own.
Walk through it
- 1Review the token generator
- 2Name the weak source
- 3State the correct generator
- Spot the other weak sources
- Harden and verify the fix
A pre-release review flags the sign-in module. Read how it builds the session token and note where the value comes from before you decide whether it is safe.
1// BEFORE: predictable source, short value2let nextId = 1000;3export function newSessionId(): string {4 nextId += 1; // sequential counter5 return String(nextId); // 4-6 digits, no randomness6}7 8// AFTER: CSPRNG, 256 bits, via the platform9import { randomBytes } from "node:crypto";10export function newSessionId(): string {11 return randomBytes(32).toString("base64url"); // 256 bits of entropy12}Spot it
- Session identifiers that increase, share long prefixes, or follow any visible pattern across successive logins.
- Short identifiers, such as a few digits or a few hex characters.
- Large numbers of requests presenting invalid or unknown session identifiers from one source.
- A burst of 401 or session-expired responses interleaved with occasional successes from the same client.
- A code review that finds a counter, timestamp, username-derived value or non-cryptographic RNG in token generation.
Application access log
ts=2026-10-11T08:02:11Z method=GET path=/account sid=1041 status=200 user=u_2210
ts=2026-10-11T08:02:12Z method=GET path=/account sid=unknown status=401 src=203.0.113.50
ts=2026-10-11T08:02:12Z method=GET path=/account sid=unknown status=401 src=203.0.113.50
ts=2026-10-11T08:02:13Z method=GET path=/account sid=unknown status=401 src=203.0.113.50Session store audit
ts=2026-10-11T08:00:00Z issued_ids=1041,1042,1043,1044 pattern=monotonic flag=low-entropysplSplunk: sources probing many invalid session ids
index=app sourcetype=access status=401 sid=unknown
| bin _time span=1m
| stats count by src, _time
| where count > 30Tune the threshold to normal traffic. Depends on the application logging unknown identifiers as a distinct value.
grepgrep: very short session identifiers in logs
grep -E 'sid=[0-9a-f]{1,12}( |$)' access.logStop it
Generate identifiers from a CSPRNG with at least 128 bits of entropy
Use the operating system's cryptographically secure random source, never a counter, timestamp, username hash or general-purpose random function, and make the value long enough that it cannot be covered by volume.
Use the framework's session manager and harden the cookie
Let a maintained session library generate and store identifiers instead of hand-rolling one. Mark the cookie Secure, HttpOnly and SameSite, and keep the value opaque with no user data inside it.
Rotate on login and bound the lifetime
Issue a new identifier at login and at any privilege change, apply idle and absolute timeouts, and destroy the session fully on logout so that no value stays useful for long.
Generate the session identifier from a secure random source
Vulnerable
let nextId = 1000;
export function newSessionId(): string {
nextId += 1;
return String(nextId);
}Hardened
import { randomBytes } from "node:crypto";
export function newSessionId(): string {
return randomBytes(32).toString("base64url");
}Prefer your framework's built-in session middleware, which already does this and handles storage and expiry.
Session cookie attributes
Hardened
Set-Cookie: sid=<opaque>; Path=/; Secure; HttpOnly; SameSite=Lax- Generate identifiers with a CSPRNG and at least 128 bits of entropy.
- Use the framework's session manager rather than a custom token scheme.
- Keep identifiers opaque: no user id, role or timestamp encoded in the value.
- Set Secure, HttpOnly and SameSite on the session cookie.
- Rotate the identifier at login and at every privilege change.
- Enforce idle and absolute session timeouts and destroy the session on logout.
If it already happened
Deploy the secure generator and invalidate every existing session, forcing re-authentication so no old guessable identifier remains valid.
Find every code path that issues tokens, replace custom generators with the framework's, and remove any identifier derived from user data.
Review account activity during the exposure window, notify users where activity looks unfamiliar, and confirm new identifiers show no pattern across a large sample.
Add a review checklist item for token entropy and source, a regression test that samples issued identifiers, and the detection above.
Check yourself
1. What makes session identifiers weak in this flaw?
2. Which generator is the correct primary fix?
3. Which review observation is a signal of weak session ids?