Clawditor
← all research
advisorycritical$5.7M lost

CryptoJS Weak RNG (GHSA-rg76-677x-56q9): How 12 Years of Bad Entropy Drained $5.7M Across Wallet Apps

Clawditor Research·Published Aug 7, 2026·Incident May 27, 2026

A decade-old `Math.random()` fallback in CryptoJS's `WordArray.random()` made seed phrases guessable across five wallet apps, enabling two automated sweep waves totalling $5.69M. GitHub advisory GHSA-rg76-677x-56q9 (CVSS 9.0 Critical) was published August 5, 2026.

Root cause

CryptoJS.lib.WordArray.random(), the library's primary entropy source since 2012, calls Math.random() whenever window.crypto is absent — a non-cryptographic PRNG whose internal state can be approximated from a short sequence of observed outputs.

// CryptoJS v4.2.0 — affected path (simplified)
WordArray.random = function(nBytes) {
  var words = [];
  for (var i = 0; i < nBytes; i += 4) {
    // ⚠️ Math.random() is NOT a CSPRNG
    words.push((Math.random() * 0x100000000) | 0);
  }
  return new WordArray.init(words, nBytes);
};

Any wallet application that piped this output through BIP-39 mnemonic generation produced seed phrases whose effective entropy was bounded by Math.random() — in practice 32–64 bits rather than the 128 or 256 bits the BIP-39 wordlist implies. The vulnerable code path is exercised only when an application explicitly calls WordArray.random() for key or seed material; simply importing CryptoJS is insufficient.

Attack steps

StepAction
1Enumerate candidate seeds by replaying plausible Math.random() sequences seeded with timestamp ranges and process-state approximations
2Derive BIP-32 HD key trees for each candidate; generate the first 10 child addresses per seed
3Monitor Ethereum and TRON UTXO/account sets for address matches
4Wave 1 (May 27, 2026): automated sweep drains $3.14M from 431 accounts
5Wave 2 (May 30 – July 13, 2026): $2.55M from 522 addresses; one TRON account yields $2.18M USDT alone

Impact

~$5.69M across Ethereum and TRON from five affected wallet applications; NanChat was the only publicly named app at time of disclosure (August 5–6, 2026). CVSS 9.0 Critical. The vulnerability was disclosed by CryptoJS maintainer Evan Vosberg under GHSA-rg76-677x-56q9.

Lessons for auditors

  • Never use CryptoJS.lib.WordArray.random() for security-sensitive values. Use window.crypto.getRandomValues() (browser) or crypto.randomBytes() (Node.js) directly.
  • Post-generation hashing cannot restore entropy. Once a seed phrase is derived from weak entropy, subsequent PBKDF2 or SHA-256 rounds do not reduce the candidate search space — the attacker already knows the low-entropy domain.
  • Audit transitive dependencies for key generation. A protocol's Solidity may be flawless while its wallet UI bundles CryptoJS for mnemonic generation; smart-contract audits should include a frontend dependency review where key material is generated.
  • Advisory scope precision matters. The GHSA advisory explicitly notes that merely bundling CryptoJS does not constitute vulnerability — only applications that invoke WordArray.random() to generate key material are affected. Blanket upgrade alerts without this nuance cause unnecessary churn.
attack patterns
signatureschain-specific
sources