Weak RNG: predictable tokens
Session, password-reset, CSRF, API tokens: all must be unpredictable. A non-cryptographic PRNG (rand(), mt_rand(), Math.random()) is predictable after a few outputs.
The problem
mt_rand() has a reconstructable state; if the seed derives from time (srand(time())), the space is tiny. A reset token like that is brute-forced offline.
// WRONG
$token = md5(uniqid(rand(), true));
// RIGHT
$token = bin2hex(random_bytes(32));Defence
Use a CSPRNG: random_bytes (PHP), secrets (Python), crypto.randomBytes (Node), /dev/urandom. At least 128 bits of entropy. Compare tokens in constant time and expire them.