Weakness reference
CWE-336

Same Seed in Pseudo-Random Number Generator (PRNG)

This weakness occurs when a program initializes a pseudo-random number generator PRNG with the same seed value every time it runs, causing it to produce…

01Summary

This weakness occurs when a program initializes a pseudo-random number generator (PRNG) with the same seed value every time it runs, causing it to produce identical sequences of "random" numbers. Any security feature that depends on unpredictability—such as session tokens, password reset links, or cryptographic nonces—becomes predictable and can be forged or guessed by an attacker.

02How It Happens

PRNGs are deterministic by design: given the same starting seed, they will always produce the same sequence of numbers. This is useful for testing and reproducibility, but dangerous for security. The weakness arises when developers either hardcode a seed value, use a non-random seed (like the current time rounded to seconds), or fail to seed the generator at all, relying on a default seed. An attacker who knows or can predict the seed can reproduce the entire sequence of "random" values the application will generate, defeating any security mechanism built on that randomness.

03Real-World Impact

An attacker can predict security-critical values such as session IDs, CSRF tokens, password reset tokens, or temporary authentication codes. This enables account takeover, session hijacking, or privilege escalation. For example, if a password reset link is generated using a predictable PRNG, an attacker can forge valid reset links for any user account. Similarly, predictable session tokens allow attackers to impersonate legitimate users without knowing their credentials.

04Vulnerable & Fixed Patterns

Vulnerable pattern
import random

def generate_session_token():
    random.seed(12345)  # Same seed every time
    token = ''.join(random.choice('abcdef0123456789') for _ in range(32))
    return token

# Every call produces the same token
token1 = generate_session_token()
token2 = generate_session_token()
# token1 == token2 — predictable and reusable

Why it's vulnerable:
The seed is hardcoded, so the PRNG produces the same sequence every time the function is called. An attacker can predict all tokens in advance.

Fixed pattern
import secrets

def generate_session_token():
    # secrets module uses the OS entropy source, no seed needed
    token = secrets.token_hex(16)  # 32 hex characters
    return token

# Each call produces a different, cryptographically secure token
token1 = generate_session_token()
token2 = generate_session_token()
# token1 != token2 — unpredictable
Vulnerable pattern
<?php
function generate_reset_token() {
    mt_srand(1234);  // Same seed every time
    $token = '';
    for ($i = 0; $i < 32; $i++) {
        $token .= dechex(mt_rand(0, 15));
    }
    return $token;
}

// Every call produces the same token
$token1 = generate_reset_token();
$token2 = generate_reset_token();
// $token1 === $token2 — predictable
?>

Why it's vulnerable:
The seed is hardcoded, making the output deterministic. An attacker can generate the same tokens offline.

Fixed pattern
<?php
function generate_reset_token() {
    // random_bytes() uses the OS entropy source
    return bin2hex(random_bytes(16));  // 32 hex characters
}

// Each call produces a different, cryptographically secure token
$token1 = generate_reset_token();
$token2 = generate_reset_token();
// $token1 !== $token2 — unpredictable
?>

05Prevention Checklist

Use cryptographically secure random generators (secrets in Python, random_bytes() in PHP) for all security-sensitive values; never use general-purpose PRNGs like random.random() or mt_rand().
Never hardcode or manually set a seed for security-critical randomness; let the OS entropy source initialize the generator.
Avoid seeding with predictable values like time(), microtime(), or process IDs.
Audit all token, nonce, and session ID generation code to confirm it uses a cryptographically secure source.
If you must use a general-purpose PRNG for non-security purposes (e.g., shuffling a list), document that it is not suitable for security and isolate it from security-critical code paths.

06Signs You May Already Be Affected

Check application logs for repeated session IDs, CSRF tokens, or password reset tokens across different users or time periods. If you can generate a token, wait a few seconds, and generate another that is identical or follows a predictable pattern, the application is likely using a weak or improperly seeded PRNG. Review source code for hardcoded seed() calls or use of random / mt_rand in token generation functions.