Skip to main content

Overview

This vulnerability occurs when an application uses random number generators (RNGs) that produce predictable or easily guessable outputs for security-sensitive purposes. This includes generating session IDs, CSRF tokens, password reset tokens, cryptographic keys, salts, or nonces/IVs. Using weak RNGs (often called pseudo-random number generators or PRNGs) means an attacker might be able to predict future “random” values, compromising security mechanisms. 🎲❓

Business Impact

Predictable random values can lead to various attacks:
  • Session Hijacking: If session IDs are predictable, attackers can guess valid IDs and take over user sessions.
  • CSRF Token Bypass: Predictable CSRF tokens can be guessed, nullifying CSRF protection.
  • Password Reset Poisoning: Predictable password reset tokens allow attackers to reset passwords for arbitrary users.
  • Cryptographic Weaknesses: Predictable keys, salts, IVs, or nonces weaken encryption and hashing significantly, potentially allowing decryption or cracking.

Reference Details

CWE ID: CWE-330 (Includes CWE-331, CWE-335, CWE-336, CWE-337, CWE-338, CWE-340) OWASP Top 10 (2021): A02:2021 - Cryptographic Failures Severity: High

Framework-Specific Analysis and Remediation

Modern operating systems and language runtimes provide access to cryptographically secure pseudo-random number generators (CSPRNGs). These are designed to produce unpredictable outputs suitable for security purposes. The vulnerability arises when developers use non-cryptographic PRNGs (like Python’s random module, Java’s java.util.Random, or Math.random() in JS/PHP) for generating security-sensitive values. The fix is to always use the system’s CSPRNG for anything security-related.
  • Python
  • Java
  • .NET(C#)
  • PHP
  • Node.js
  • Ruby

Framework Context

Using the standard random module for security tokens instead of secrets or os.urandom.

Vulnerable Scenario 1: Predictable Session ID

# custom_session_backend.py
import random
import string

def generate_session_id():
    # DANGEROUS: random.choice uses Mersenne Twister, a non-cryptographic PRNG.
    # Its output can be predicted after observing enough previous outputs.
    length = 32
    chars = string.ascii_letters + string.digits
    return ''.join(random.choice(chars) for _ in range(length))

Vulnerable Scenario 2: Predictable Password Reset Token

# accounts/utils.py
import random
import time

def generate_reset_token():
    # DANGEROUS: Seeding with time makes the output somewhat predictable,
    # especially if the attacker knows roughly when the token was generated.
    # Even without time, `random.randint` is not cryptographically secure.
    random.seed(time.time())
    return str(random.randint(1000000000, 9999999999))

Mitigation and Best Practices

Use the secrets module (Python 3.6+) for generating tokens, keys, etc. For generating random bytes (e.g., salts, IVs), use os.urandom().

Secure Code Example

# custom_session_backend.py (Secure)
import secrets
import string

def generate_session_id():
    # SECURE: secrets.choice uses os.urandom() or equivalent CSPRNG.
    length = 32
    chars = string.ascii_letters + string.digits
    return ''.join(secrets.choice(chars) for _ in range(length))

# accounts/utils.py (Secure)
import secrets

def generate_reset_token():
    # SECURE: Generates a cryptographically strong URL-safe text string.
    return secrets.token_urlsafe(32) # e.g., 32 bytes gives ~43 chars

Testing Strategy

Review code for usage of the random module. Ensure any security-sensitive value generation uses secrets or os.urandom. Static analysis tools can often detect use of weak PRNGs.