Weakness reference
CWE-331

Insufficient Entropy

Insufficient entropy occurs when software generates security-critical values—such as tokens, session IDs, or cryptographic keys—using a method that doesn't…

01Summary

Insufficient entropy occurs when software generates security-critical values—such as tokens, session IDs, or cryptographic keys—using a method that doesn't produce enough randomness or unpredictability. An attacker can guess or brute-force these values, bypassing authentication, hijacking sessions, or forging credentials. This weakness is particularly dangerous because the code may appear to work correctly in normal use, but the underlying randomness is weak enough to be exploited at scale.

02How It Happens

Entropy is the measure of unpredictability in a generated value. When an application needs to create a security token, it should use a cryptographically secure random source that produces values an attacker cannot feasibly predict or enumerate. Common mistakes include:

- Using weak random sources like random() or Math.random() instead of cryptographic RNGs. - Seeding the random generator with predictable values (e.g., current time, process ID, or user ID). - Generating tokens from a small pool of possible values, reducing the search space. - Reusing the same random seed across multiple token generations.

The result is that an attacker can either predict the next token mathematically, or brute-force the entire space of possible tokens in reasonable time.

03Real-World Impact

Weak token generation has led to session hijacking, account takeover, and privilege escalation in real applications. An attacker who can predict or enumerate valid session tokens can impersonate legitimate users without knowing their passwords. Similarly, weak password-reset tokens or API keys can be guessed, allowing unauthorized access to sensitive functions or data. The impact scales with the number of active sessions or tokens in use—the more tokens an attacker can test, the higher the probability of a successful guess.

04Vulnerable & Fixed Patterns

Vulnerable pattern
import random
import string

def generate_session_token():
    # Weak: uses non-cryptographic random
    random.seed()  # seeded with current time
    token = ''.join(random.choice(string.ascii_letters) for _ in range(16))
    return token

def generate_reset_token(user_id):
    # Weak: predictable based on user_id and time
    return f"{user_id}_{int(time.time())}"

Why it's vulnerable:
random.choice() is not cryptographically secure and can be predicted if the seed is known. The reset token is entirely deterministic based on user ID and timestamp, making it trivial to enumerate.

Fixed pattern
import secrets
import string

def generate_session_token():
    # Strong: uses cryptographic random source
    token = ''.join(secrets.choice(string.ascii_letters + string.digits) for _ in range(32))
    return token

def generate_reset_token(user_id):
    # Strong: unpredictable random component, sufficient length
    random_part = secrets.token_urlsafe(32)
    return f"{user_id}_{random_part}"
Vulnerable pattern
<?php
function generate_session_token() {
    // Weak: uses mt_rand, not cryptographically secure
    $token = '';
    for ($i = 0; $i < 16; $i++) {
        $token .= chr(mt_rand(65, 90));
    }
    return $token;
}

function generate_reset_token($user_id) {
    // Weak: predictable based on time
    return $user_id . '_' . time();
}
?>

Why it's vulnerable:
mt_rand() is a general-purpose PRNG, not designed for cryptographic use, and its output can be predicted. The reset token is entirely deterministic.

Fixed pattern
<?php
function generate_session_token() {
    // Strong: uses random_bytes, cryptographically secure
    $token = bin2hex(random_bytes(32));
    return $token;
}

function generate_reset_token($user_id) {
    // Strong: unpredictable random component, sufficient length
    $random_part = bin2hex(random_bytes(32));
    return $user_id . '_' . $random_part;
}
?>

05Prevention Checklist

Use cryptographically secure random sources: secrets module in Python, random_bytes() in PHP, or equivalent in your language.
Generate tokens with at least 128 bits of entropy (32+ characters of base64 or hex output).
Never seed a cryptographic RNG with predictable values like timestamps or user IDs.
Avoid custom token generation logic; use well-tested libraries (e.g., secrets.token_urlsafe(), bin2hex(random_bytes())).
Store tokens securely (hashed, salted) in the database; never store them in plaintext.
Implement rate limiting on token validation endpoints to slow brute-force attempts.

06Signs You May Already Be Affected

Review your codebase for calls to random(), Math.random(), mt_rand(), or rand() in security-critical contexts (session generation, password reset, API key creation). Check whether tokens are generated with sufficient length and randomness—if a token is fewer than 20 characters or is based on predictable inputs like timestamps or sequential IDs, it is likely vulnerable. Examine logs for unusual patterns of failed authentication attempts or token validation errors, which may indicate an attacker testing guessed tokens.

07Related Recent Vulnerabilities