Clawditor
← all research
advisorycritical$5.7M lost

Ill Bloom: CryptoJS WordArray.random() Entropy Flaw Enables $5.7M Wallet Drains Across EVM and Bitcoin

Clawditor Research·Published Aug 9, 2026·Incident May 27, 2026
CryptoJSRWalletBexo WalletNanChatBitcoin LibreMilo Wallet

Security researchers at Coinspect disclosed that five wallet applications used CryptoJS versions prior to 4.0.0 to generate private keys — a library function relying on Math.random() that yields only 2^39–2^47 bits of effective entropy. At least 2,100 addresses were swept for a combined $5.7M across two coordinated drain waves in May–July 2026.

Root Cause

CryptoJS.lib.WordArray.random() in versions prior to 4.0.0 uses Math.random() — a non-cryptographic PRNG — to produce entropy for wallet seed and private key generation. The effective key-space is reduced to approximately 2^39–2^47 bits, small enough to enumerate exhaustively on commodity hardware within hours.

// CryptoJS < 4.0.0 — INSECURE (simplified)
CryptoJS.lib.WordArray.random = function (nBytes) {
  var words = [];
  for (var i = 0; i < nBytes; i += 4) {
    // Math.random() is a PRNG, NOT a CSPRNG; seed state is tiny
    words.push((Math.random() * 0x100000000) | 0);
  }
  return CryptoJS.lib.WordArray.create(words, nBytes);
};

// CryptoJS >= 4.0.0 — SECURE
CryptoJS.lib.WordArray.random = function (nBytes) {
  var typedArray = new Uint8Array(nBytes);
  (self.crypto || self.msCrypto).getRandomValues(typedArray);
  return CryptoJS.lib.WordArray.create(Array.from(typedArray), nBytes);
};

Because JavaScript engines seed Math.random() from an internal state of 64 bits or fewer (and do not re-seed between calls), an attacker who enumerates likely seed values can precompute the full set of private keys generated by affected apps. CryptoJS has been effectively unmaintained since 2023, and downstream wallet packages continued to depend on old, unpatched versions.

Attack Steps

StepActorAction
1Researcher/AttackerIdentify wallet apps that link CryptoJS < 4.0.0 for key generation via npm dependency audit
2AttackerPrecompute (seed → private key → EVM/BTC address) lookup table covering 2^39–2^47 seeds using commodity hardware
3AttackerScan on-chain state for funded addresses matching the precomputed address set
4Attacker – Wave 12026-05-27: sweep 431 wallets, drain ~$3.14M
5Attacker – Wave 22026-05-30 through 2026-07-13: drain 522 additional addresses for ~$2.55M
6CoinspectAugust 2026: publish "Ill Bloom" investigation; NanChat issues public advisory 2026-08-06

Impact

  • Total losses (lower bound): ~$5,690,922 across ~2,100 wallets
  • Wave 1: ~$3.14M from 431 addresses (2026-05-27)
  • Wave 2: ~$2.55M from 522 addresses (2026-05-30 – 2026-07-13)
  • Chains: Ethereum and other EVM-compatible networks; Bitcoin
  • Confirmed affected apps: RWallet (RRWallet), Bexo Wallet, NanChat, Bitcoin Libre, Milo Wallet
  • Disclosure status: As of 2026-08-06, NanChat is the only affected app known to have published a public advisory. CryptoJS itself has been unmaintained since 2023.

Lessons for Auditors

  1. Audit dependency entropy sources. Any keygen or seed-generation code must be reviewed for use of Math.random(), legacy CryptoJS, or other non-CSPRNG sources. Only crypto.getRandomValues() (browser/Node Web Crypto API) or crypto.randomBytes() (Node.js) are acceptable.
  2. Pin and audit transitive cryptographic dependencies. Packages that declare cryptojs as a peer or transitive dependency without a version floor silently inherit this vulnerability. Include dependency scanning in CI.
  3. Supply-chain hygiene around unmaintained libraries. Treat unmaintained cryptographic libraries as vulnerabilities. Establish a policy of replacing (not just upgrading) abandoned cryptographic dependencies.
  4. Monitor disclosure lag. Exploitation began in May 2026; the first public advisory appeared in August — a 2+ month gap. On-chain anomaly detection (unexpected balance sweeps across many young wallets) could surface active exploitation much earlier.
attack patterns
chain-specificerc20supply-chainweak-randomnesswallet-key-generation
sources