Skip to main content

Free 30-min security demo Book Now

Home / Knowledge Base / Insecure Randomness
Medium CWE-330 A02:2021 Cryptographic Failures

Insecure Randomness

Insecure randomness uses predictable generators for tokens, session IDs, and OTPs, letting attackers guess them. Learn which secure APIs to use.

Affects: C#JavaJavaScriptPHPPythonRubyGo

What is Insecure Randomness?

Insecure randomness occurs when an application uses a predictable or non-cryptographic random number generator (PRNG) to produce values that must be unpredictable for security, such as session tokens, password reset links, CSRF tokens, encryption keys, or one-time passwords.

Standard PRNGs like Math.random() (JavaScript), java.util.Random, random.random() (Python), and rand() (PHP/C) are designed for speed and statistical distribution, not for security. Their internal state can often be inferred from a small number of observed outputs, allowing an attacker to predict past or future values.

How exploitation works

A password reset token is generated with Math.random():

// 16 hex chars from Math.random() - ~53 bits, observable seed
const token = Math.random().toString(16).substr(2);

An attacker requests multiple password resets, observes the tokens, and uses them to reconstruct the V8 engine’s PRNG state, then predicts future tokens for other accounts. Tools like untwister automate Mersenne Twister state recovery from observed Math.random() outputs.

Vulnerable code examples

JavaScript / Node.js

// VULNERABLE: Math.random() is not cryptographically secure
function generateResetToken() {
    return Math.random().toString(36).substr(2, 16); // Predictable
}

Java

// VULNERABLE: java.util.Random is seeded from system time - predictable
import java.util.Random;

public String generateSessionId() {
    Random rng = new Random(); // Or new Random(System.currentTimeMillis())
    return Long.toHexString(rng.nextLong());
}

PHP

// VULNERABLE: rand() and mt_rand() are not cryptographically secure
$token = bin2hex(pack('N', mt_rand()));

Secure code examples

JavaScript / Node.js - crypto.randomBytes

// SECURE: Node.js crypto module uses OS entropy source (CSPRNG)
const crypto = require('crypto');

function generateResetToken() {
    return crypto.randomBytes(32).toString('hex'); // 256-bit secure token
}

Java - SecureRandom

// SECURE: java.security.SecureRandom uses OS entropy (e.g., /dev/urandom)
import java.security.SecureRandom;
import java.util.Base64;

public String generateSessionId() {
    SecureRandom secureRng = new SecureRandom();
    byte[] bytes = new byte[32];
    secureRng.nextBytes(bytes);
    return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);
}

Python - secrets module

# SECURE: secrets module is designed for security-sensitive values (Python 3.6+)
import secrets

def generate_otp():
    return secrets.token_hex(16)  # 128 bits of randomness

def generate_numeric_otp(digits=6):
    return str(secrets.randbelow(10**digits)).zfill(digits)

PHP - random_bytes

// SECURE: random_bytes() uses CSPRNG
$token = bin2hex(random_bytes(32)); // 256-bit token

What Offensive360 detects

  • Math.random() in security contexts - Usage of Math.random() for generating tokens, IDs, nonces, or keys
  • java.util.Random for security values - Use of non-secure Random class in token/session generation paths
  • rand()/mt_rand() in PHP - PHP pseudo-random functions used where cryptographic randomness is required
  • random.random()/random.randint() in Python - Python’s random module used in authentication or token flows
  • Short token lengths - Token generation producing fewer than 128 bits of entropy

Remediation guidance

  1. Use platform CSPRNG APIs - crypto.randomBytes() (Node.js), SecureRandom (Java), secrets module (Python 3.6+), random_bytes() (PHP 7+), crypto/rand (Go).

  2. Generate at least 128 bits (16 bytes) of entropy, For tokens, session IDs, and reset links. 256 bits is preferred for long-lived credentials.

  3. Never seed secure random with timestamps - new Random(System.currentTimeMillis()) or srand(time()) are as predictable as unseeded PRNGs.

  4. Store token hashes, not plaintext - Even with secure generation, store SHA-256 hashes of reset tokens in the database to prevent exposure in case of a database breach.

  5. Set short expiry windows - Limit the attack surface by expiring tokens quickly (e.g., 15 minutes for password reset tokens).

References

By Offensive360 Security Research Reviewed: March 2026

Detect Insecure Randomness automatically

Run Offensive360 SAST on your codebase to find this and 100+ other vulnerabilities.