Lion Cipher Lab
Exploit and fix predictable password-reset tokens (weak randomness)
- AppSec / DevSecOps
- Intermediate
- ~45 min
- Free · no account required
Why it matters
Almost every application hands out secret strings that are supposed to be unguessable: password-reset tokens, session identifiers, API keys, email-verification links, 'remember me' cookies, one-time codes. The security of all of them rests on a single, quiet assumption — that an attacker cannot predict the next value. And the most common way that assumption fails is not a broken algorithm or a leaked key; it is a developer reaching for the FIRST random function their language offers. `random` in Python, `Math.random()` in JavaScript, `rand()` in C, `mt_rand()` in PHP — these are…
What you'll learn
- defining the difference between a general-purpose PRNG and a cryptographically secure one (CSPRNG), and why it is the whole ballgame for anything secret
- recognising the weak-randomness anti-pattern in code: Python's random / rand() / Math.random() / mt_rand() used to mint a token, id, or password
- building a tiny self-contained 'app' that issues a password-reset token from a time-seeded Mersenne Twister, entirely on your own machine
- playing attacker: brute-forcing the small time-seed space to regenerate an exact reset token and take over an account without ever seeing the email
- measuring the break honestly: the number of candidate seeds tried and the time to reproduce the token
- applying the fix with secrets.token_urlsafe / os.urandom (a CSPRNG) and re-running the identical attack to show it now faces an intractable keyspace
- naming what a CSPRNG does NOT fix — token expiry, single-use, rate limiting, and binding the token to the user — so you harden the whole reset flow, not just the generator
- judgment: when random is the right tool (simulations, shuffles) and when reaching for it is a security bug, so you never confuse 'statistically random' with 'unpredictable to an attacker'
Steps in this lab
- PRNG vs CSPRNG: the one distinction the whole lab rests on
- Build the vulnerable 'app': a time-seeded reset token
- Attack it: brute-force the seed and regenerate the exact token
- Fix it: mint the token with a CSPRNG
- Re-measure: run the identical attack against the fixed token
- What a CSPRNG does NOT fix — harden the whole reset flow
- Do it better — spotting weak randomness in the wild