Weak Random Function
debt(d5/e3/b3/t7)
Closest to 'specialist tool catches it' (d5). The detection_hints list semgrep, psalm, and phpstan — all specialist/SAST tools that can flag mt_rand(), rand(), uniqid(), and shuffle() in security contexts. These are not default linter catches; they require deliberate configuration of specialist static analysis tools.
Closest to 'simple parameterised fix' (e3). The quick_fix states: replace every security use of mt_rand(), rand(), array_rand(), and shuffle() with random_bytes() or random_int(). This is a pattern-replacement refactor — find all security-sensitive call sites and swap the function. It's slightly more than a single-line patch because there may be multiple call sites across the codebase, but each replacement is a straightforward swap with no architectural changes needed.
Closest to 'localised tax' (b3). The burden is real but contained. Security-sensitive random calls tend to cluster in auth, token generation, and session code — not spread across every file. Once identified and replaced, the rest of the codebase is unaffected. The applies_to covers web/cli/queue contexts but the actual usage of PRNG for tokens is typically localised to a small number of components.
Closest to 'serious trap' (t7). The misconception field captures it precisely: 'mt_rand() is secure because it uses Mersenne Twister' — Mersenne Twister sounds cryptographically sophisticated, and its state can be fully reconstructed from 624 outputs, making all future values predictable. This directly contradicts the assumption that a named algorithm with mathematical sophistication implies security. Developers familiar with PRNG in other contexts (e.g., game randomness) are especially likely to be misled. A score of t7 reflects that this contradicts reasonable assumptions from adjacent domains.
Also Known As
TL;DR
Explanation
PHP's rand() and mt_rand() are Mersenne Twister-based PRNGs — fast and deterministic, suitable for simulations and games, but predictable given enough outputs. For security: tokens, session IDs, password reset links, CSRF tokens, and API keys must use cryptographically secure randomness. PHP 7+ provides random_bytes() and random_int() which use the OS CSPRNG (/dev/urandom on Linux). Never use weak PRNGs for anything an attacker must not be able to predict.
Common Misconception
Why It Matters
Common Mistakes
- rand() or mt_rand() for password reset tokens, CSRF tokens, or session IDs.
- uniqid() for security tokens — uses microtime(), highly predictable.
- base64_encode(mt_rand()) — encoding does not add entropy.
- str_shuffle() for token generation — relies on mt_rand() internally.
Avoid When
- Never use rand(), mt_rand(), or uniqid() for security tokens — they are predictable.
- Do not use microtime() or time() as a seed for token generation — trivially guessable.
When To Use
- Use random_bytes() for any security-sensitive random value — tokens, nonces, CSRF values, API keys.
- Use random_int() for cryptographically secure random integers within a range.
Code Examples
// Predictable — never use for security:
$token = md5(uniqid(mt_rand(), true)); // Both predictable
$resetToken = rand(100000, 999999); // 900000 possibilities — brute-forceable
$apiKey = base64_encode(mt_rand()); // Predictable state
// Cryptographically secure:
$token = bin2hex(random_bytes(32)); // 256 bits of entropy
$resetUrl = bin2hex(random_bytes(16)); // 128 bits — URL-safe
$pin = random_int(100000, 999999); // Secure integer range
$apiKey = base64_encode(random_bytes(32)); // Secure API key