CSPRNG vs PRNG: Why Math.random() Isn't Safe
Every secret you generate is only as unpredictable as the random number generator behind it. Two values can look equally "random" on screen yet differ enormously in safety. The dividing line is whether the generator is cryptographically secure. Get this wrong and an attacker can reproduce your "random" keys exactly.
What a PRNG does
A pseudo-random number generator (PRNG) starts from a seed and applies a fast mathematical formula to produce a stream of numbers that look random and pass basic statistical tests. PRNGs are great for simulations, games, shuffling a playlist, or picking a random color — anything where predictability isn't a security concern.
Why Math.random() is dangerous for secrets
Functions like JavaScript's Math.random(), C's rand(), or anything seeded from the current time share a fatal flaw: their output is deterministic. Given the internal state — or enough observed outputs — an attacker can recover the seed and predict every past and future value. Researchers have repeatedly shown that tokens, password-reset links, and session IDs built on Math.random() can be guessed. The numbers pass statistical randomness tests but fail the only test that matters for security: an adversary cannot predict them.
What makes a CSPRNG different
A cryptographically secure PRNG (CSPRNG) adds two guarantees a plain PRNG does not:
- Unpredictability. Even with many previous outputs, the next output cannot be predicted better than chance.
- State protection. If part of the internal state leaks, an attacker still cannot run it backwards to recover earlier outputs.
CSPRNGs are seeded from high-quality operating-system entropy (hardware noise, interrupt timings, and dedicated CPU instructions like RDRAND), and they're designed so the seed can never be reverse-engineered from the output.
The secure generator on each platform
- Browser JavaScript:
crypto.getRandomValues()andcrypto.randomUUID(). - Node.js:
crypto.randomBytes()/crypto.randomInt(). - Python: the
secretsmodule (notrandom). - Go:
crypto/rand(notmath/rand). - Java:
SecureRandom. - Linux/Unix:
/dev/urandomor thegetrandom()syscall.
A note on seeding
You should never manually seed a CSPRNG with a value like the timestamp — that reintroduces predictability. A correctly used CSPRNG seeds itself from the OS. Your job is simply to call it and use the bytes directly, then encode them. For why those bytes translate into real strength, see what entropy is and why it matters.
Generated the right way here
Every value on this site comes from the browser's crypto.getRandomValues() CSPRNG — never Math.random() — so the keys, passwords, and tokens you create are genuinely unpredictable.
Generate with a secure RNG. Create keys and tokens backed by the browser's CSPRNG, entirely on your device.
Open the generator