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. 🎲❓
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.
# accounts/utils.pyimport randomimport timedef 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))
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.
// filter/CsrfTokenFilter.javaimport java.util.Random;import java.math.BigInteger;public String generateCsrfToken() { // DANGEROUS: java.util.Random uses a linear congruential generator (LCG), // which is highly predictable. Random random = new Random(); return new BigInteger(130, random).toString(32); // 130 bits, base32}
Vulnerable Scenario 2: Predictable IV for Encryption
// service/EncryptionService.javaimport javax.crypto.Cipher;import javax.crypto.spec.IvParameterSpec;import java.util.Random;public byte[] encryptAesCbc(byte[] keyBytes, byte[] data) throws Exception { Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); byte[] iv = new byte[16]; // DANGEROUS: Using the weak Random for a cryptographic IV. new Random().nextBytes(iv); IvParameterSpec ivSpec = new IvParameterSpec(iv); // ... cipher.init(..., ivSpec) ...}
// Services/OtpService.csusing System;public class OtpService{ public string GenerateOtp() { // DANGEROUS: System.Random is not cryptographically secure. // Output can be predicted, especially if seeded predictably. var random = new Random(); return random.Next(100000, 999999).ToString("D6"); }}
Vulnerable Scenario 2: Predictable Salt Generation
// Services/AuthService.csusing System;using System.Security.Cryptography;public byte[] GenerateSalt(){ byte[] salt = new byte[16]; // DANGEROUS: Using the weak System.Random for a salt. var random = new Random(); random.NextBytes(salt); return salt;}
Review code for usages of new System.Random(). Ensure security-related randomness uses RandomNumberGenerator.Fill() or RandomNumberGenerator.GetInt32().
Vulnerable Scenario 1: Predictable Session ID with mt_rand()
// session_handler.php (Custom Session Handler)function generate_session_id() { // DANGEROUS: mt_rand() is a PRNG (Mersenne Twister) and not // cryptographically secure. Its state can be predicted. return bin2hex(pack('L', mt_rand()) . pack('L', mt_rand()));}
// controllers/PasswordController.phpfunction send_reset_link($email) { // DANGEROUS: uniqid() is based on the system time and is easily guessable. // Even with more_entropy=true, it's not considered secure enough. $token = uniqid('reset_', true); // ... save token and send email ...}
Use random_bytes() to generate cryptographically secure random bytes (for salts, keys, IVs, tokens). Use random_int() to generate cryptographically secure random integers within a range.
Review code for any usage of Math.random(). Replace it with crypto.randomBytes() or crypto.randomInt() in all security-sensitive contexts (token generation, key generation, IVs, salts).
Use SecureRandom for all security needs. SecureRandom.hex(n) for hex tokens, SecureRandom.urlsafe_base64(n) for URL-safe tokens, SecureRandom.random_bytes(n) for raw bytes.