Math.random() is a fast pseudo-random generator built for things like animations, not security. Its output can be predicted from prior values, so using it to mint a token, session id, password-reset code, or OAuth state parameter lets an attacker guess valid ones. The fix is a single call to a cryptographic random source.
Why it's a problem
Anything that protects access needs to be unguessable. Because Math.random() is seeded and sequential under the hood, an attacker who observes a few outputs can narrow down or reproduce the sequence, then forge a reset code or a session token that the server accepts as legitimate. The value looks random to a human and is trivially reproducible to a machine.
The pattern
// predictable — do not use for anything security-sensitive const token = Math.random().toString(36).slice(2); const resetCode = String(Math.floor(Math.random() * 1000000));
The fix
import { randomUUID, randomInt, randomBytes } from "node:crypto";
const token = randomBytes(32).toString("hex"); // 256-bit token
const sessionId = randomUUID(); // unguessable id
const resetCode = String(randomInt(100000, 1000000)); // 6-digit, secureWhy AI tools write this
Math.random() is the first random function most models reach for because it is the one that appears most often in training data, in overwhelmingly non-security contexts. When the surrounding task is 'generate a token,' the assistant still pattern-matches to the familiar call, producing code that runs and looks correct but is not safe for the job.
The quick fix
- Replace Math.random() with crypto.randomBytes, crypto.randomUUID, or crypto.randomInt for any security-sensitive value.
- In the browser, use crypto.getRandomValues() instead.
- Audit tokens, session ids, reset codes, and OAuth state parameters specifically.
Common questions
Where in my app is Math.random() actually a security problem?
Only where the random value guards something an attacker benefits from guessing: tokens, session ids, password-reset codes, OAuth state, or anything that proves identity or authorizes an action.
Is Math.random() fine for non-security purposes like animations or shuffles?
Yes. For display purposes like a game die, a shuffle, or a random color, Math.random is perfectly fine. The problem is using it for credentials or secrets.
Does crypto.randomUUID() work in both Node and the browser?
Yes. crypto.randomUUID() is available natively in Node.js 14.17+ and modern browsers. In older environments, use the uuid npm package or crypto.randomBytes(16).toString('hex').