Weakness reference
CWE-339

Small Seed Space in PRNG

This weakness occurs when a pseudo-random number generator PRNG is seeded with a value drawn from a small set of possibilities, allowing an attacker to predict…

01Summary

This weakness occurs when a pseudo-random number generator (PRNG) is seeded with a value drawn from a small set of possibilities, allowing an attacker to predict or reproduce the "random" output. If an attacker can guess or enumerate the seed, they can predict every number the PRNG will generate, defeating any security mechanism that relies on that randomness.

02How It Happens

PRNGs are deterministic: given the same seed, they always produce the same sequence of numbers. Security-sensitive operations—such as generating session tokens, password reset links, or cryptographic keys—depend on the attacker being unable to predict these values. When a seed is chosen from a limited pool (for example, the current time in seconds, a small counter, or a low-entropy system value), an attacker can feasibly try all possible seeds, observe which one produces the observed output, and then predict future values. This is especially dangerous in cryptographic contexts, where even a small reduction in entropy can be catastrophic.

03Real-World Impact

An attacker who can predict a PRNG's output can forge session tokens, bypass authentication, predict password reset links, or compromise cryptographic operations. For example, if a session ID is generated using a PRNG seeded with the current Unix timestamp, an attacker who observes one session ID can narrow the seed to a small window of time, test all possibilities, and generate valid session IDs for other users. In cryptographic applications, this can lead to complete loss of confidentiality and integrity.

04Vulnerable & Fixed Patterns

Vulnerable pattern
import random
import time

# Seed PRNG with current time (low entropy)
random.seed(int(time.time()))

# Generate a "random" session token
session_token = str(random.randint(100000, 999999))

Why it's vulnerable:
The seed is derived from the current Unix timestamp, which changes only once per second. An attacker observing a token can test all possible seeds within a narrow time window and predict future tokens.

Fixed pattern
import secrets

# Use a cryptographically secure random source
session_token = secrets.token_hex(32)
Vulnerable pattern
<?php
// Seed with current time (low entropy)
mt_srand(time());

// Generate a "random" token
$token = mt_rand(100000, 999999);
?>

Why it's vulnerable:
mt_srand(time()) seeds the Mersenne Twister with the current Unix timestamp, which has only ~86,400 possible values per day. An attacker can enumerate all seeds in that window.

Fixed pattern
<?php
// Use cryptographically secure random bytes
$token = bin2hex(random_bytes(32));
?>

05Prevention Checklist

Use cryptographically secure random sources (secrets in Python, random_bytes() in PHP) for all security-sensitive operations, never general-purpose PRNGs.
Never seed a PRNG with low-entropy values like timestamps, process IDs, or sequential counters.
If you must use a PRNG for non-cryptographic purposes, document that assumption clearly and ensure it is never used for security decisions.
Audit code that generates tokens, session IDs, nonces, or keys to confirm they use high-entropy sources.
Test your random generation by collecting samples and verifying they cannot be reproduced by seeding with common values (time, PID, etc.).

06Signs You May Already Be Affected

Look for code that calls srand(), mt_srand(), or random.seed() with arguments derived from time, process IDs, or other low-entropy sources. Check logs for repeated or predictable session IDs, password reset tokens, or other security-critical values. If you can reproduce a token by guessing the seed, the system is vulnerable.