The Bug: Math.random() Generating API Keys

A 44K-star open-source repository — react-native-elements — was found using Math.random() to generate integration API keys. This is a security vulnerability because Math.random() is a Pseudo-Random Number Generator (PRNG), not a Cryptographically Secure Pseudo-Random Number Generator (CSPRNG).

Why Math.random() Is Not Secure

Math.random() in JavaScript uses an algorithm like XorShift128+ in V8. Once an attacker recovers the internal state by observing a few outputs, they can predict all future outputs. For API keys, which are used for authentication, this predictability means an attacker could forge valid keys.

The Attack: Recovering the Internal State

The article describes a class of attack: by collecting a sequence of Math.random() outputs, an attacker can reverse-engineer the PRNG state. Tools like v8-randomness-predictor exist to do this. With the state known, the attacker can generate the same "random" keys the application would produce.

The Fix: Use crypto.randomBytes

The one-line fix is to replace Math.random() with crypto.randomBytes() (Node.js) or crypto.getRandomValues() (browser). These are CSPRNGs that are seeded from system entropy and are not predictable.

Example of the vulnerable code:

function generateApiKey() {
  return Math.random().toString(36).substr(2, 16);
}

Fixed version:

const crypto = require('crypto');
function generateApiKey() {
  return crypto.randomBytes(16).toString('hex');
}

ESLint Rule to Catch This

To prevent this pattern, use the ESLint plugin eslint-plugin-security with rule detect-unsafe-random. Alternatively, a custom ESLint rule can flag any use of Math.random() in non-trivial contexts. The article provides an example rule that forbids Math.random() in functions that generate secrets.

Codebase Impact

React Native Elements is a UI library with 44K stars. The issue was found in a utility function generating integration API keys for third-party services. The fix was merged after the report.

Why This Matters

Many developers assume Math.random() is random enough for security. This case proves otherwise. The same pattern appears in countless projects: generating IDs, tokens, or keys with Math.random(). Each instance is a potential backdoor.

Next Steps for Developers

  1. Audit your codebase for Math.random() usage, especially in functions that generate secrets, tokens, or IDs.
  2. Install eslint-plugin-security and enable detect-unsafe-random.
  3. Replace Math.random() with crypto.randomBytes() (Node) or crypto.getRandomValues() (browser) for any security-sensitive randomness.
  4. For UUIDs, use crypto.randomUUID() (Node 14.17+).
  5. Consider using a dedicated library like uuid with crypto backend.

Conclusion

Math.random() is not secure for secrets. The react-native-elements case is a wake-up call. The fix is trivial; the risk is not. Run the audit today.