
Research article. Based on The Hacker News publication “CryptoJS Weak RNG Behind $5.7 Million in Drains Affects Five Crypto Wallet Apps” (August 2026) and initial technical disclosures from Coinspect/GitHub Advisory.
Abstract. The Ill Bloom incident demonstrates that the security of a crypto wallet is determined not only by the properties of SHA-256, PBKDF2, BIP39, and elliptic curves, but primarily by the quality of the underlying entropy. In a number of applications, this function CryptoJS.lib.WordArray.random() was used to generate mnemonic phrases. Instead of the nominal 128 or 256 bits of unpredictability, it yielded effective spaces of about 239 and 247 bits . This transformed seed search from a cryptographically infeasible task into a brute-force one, after which an attacker could deterministically obtain addresses and private keys, verify addresses against the public blockchain history, and withdraw assets.
Keywords: CSPRNG, entropy, CryptoJS, BIP39, PBKDF2, HD wallet, MWC, Math.random(), cryptanalysis, brute force, dependency management, secret rotation.
1. The fact of the incident
According to a Coinspect investigation, two waves of withdrawals, beginning on May 27, 2026, resulted in a measurable lower limit of damage of $5,690,922 by July 13. The first wave affected 431 accounts/addresses, worth approximately $3.14 million; the second, which occurred from May 30 to July 13, affected addresses associated with 522 seeds, worth approximately $2.55 million. The analysis linked 2,114 identified seeds and derived addresses to Bitcoin, Ethereum, Tron, Rootstock, and Polygon.
Confirmed applications that used the vulnerable generator as a source of entropy for their recovery phrase include RRWallet, Bexo Wallet, NanChat (versions prior to 1.3.0), Bitcoin Libre, and Milo. This list should be interpreted as a confirmed minimum: an application’s absence from it does not prove the security of the historical generation method.
| Object | Disclosure status | Cryptographic investigation |
|---|---|---|
| RRWallet | Discontinued; no fix | Historically generated phrases should be considered compromised. |
| Bexo Wallet | Hotfix 20.1.0 has been announced; build availability has not been confirmed at the time of this post. | The update does not change the old seed; migration to the new one is required. |
| NanChat | Vulnerable before 1.3.0; fixed in 1.3.0 | Users of older versions are advised to generate a new seed and transfer funds. |
| Bitcoin Libre | The fix is announced in version 4 (July 2024) | The risk applies to previously generated secrets, not just the current version. |
| Milo | Discontinued; no fix | Independent and secure creation of a new wallet and transfer of assets is required. |
2. Root cause
The issue was localized in CryptoJS.lib.WordArray.random() and assigned the identifier CVE-2026-71851/GHSA-rg76-677x-56q9. The vulnerable branch used a variant of George Marsaglia’s Multiply-With-Carry (MWC) pseudorandom generator, which was initially initialized with Math.random(), rather than the system’s cryptographically strong random number generator (CSPRNG).
It’s important to distinguish between “pseudo-randomness” for modeling and cryptographic unpredictability. A program can produce statistically plausible values but be unusable for keys if its internal state is small, predictable, or brute-forceable. It is the reduction in the actual set of achievable outputs, rather than the weakness of the BIP39 hash function, that has become the target of cryptanalysis.
Nominal space of 128-bit entropy: |Ω nom | = 2 128 . Effective space in the vulnerable path: |Ω eff | ≈ 2 39 . Entropy loss: ΔH ≈ 128 − 39 = 89 bits.
For a 256-bit query: |Ω nom | = 2 256 , |Ω eff | ≈ 2 47 , ΔH ≈ 256 − 47 = 209 bits.
LaTeX-compatible notation:
\[
|\Omega_{\mathrm{nom}}|=2^{128},\qquad |\Omega_{\mathrm{eff}}|\approx2^{39},\qquad \Delta H\approx89\ \text{bits}.
\]
\[
|\Omega_{\mathrm{nom}}|=2^{256},\qquad |\Omega_{\mathrm{eff}}|\approx2^{47},\qquad \Delta H\approx209\ \text{bits}.
\]
A historical cryptanalytic example
A precedent is Debian OpenSSL (2006–2008): erroneous removal of entropy initialization strings radically reduced the set of possible keys. The RSA and DSA cryptographic algorithms were not “broken” mathematically; the key generation process was compromised. Ill Bloom belongs to the same class: reliable subsequent primitives cannot compensate for the lack of randomness in the input.
3. Version chronology
| Period/version | Change | Risk assessment |
|---|---|---|
| June 2014, 3.1.2-4 | The MWC pathway was introduced in response to the discussion of insufficiency Math.random() | Vulnerable when generating secrets. |
| 3.2.0 and 3.2.1 | Temporary transition to native cryptographic randomness of the platform | Exclusion from the vulnerable line as described by the researchers. |
| 3.3.0 | Change canceled as breaking change | The weak MWC path has returned. |
| February 2020, 4.0.0 | The native cryptographic randomness source has been restored. | Corrected branch. |
| August 2026 | Public GHSAs and Ill Bloom Disclosure | An audit of historically created secrets and migration are needed. |
This timeline illustrates the risk of semantic dependency updates: a “newer” version within the 3.x branch could again have a weak implementation. Therefore, an audit shouldn’t be limited to comparing the version number with a threshold; it must examine the actual resolved lockfile, build artifact, and specific API call.
4. Compromise chain
The attack doesn’t require hacking the Bitcoin network, ECDSA, secp256k1, PBKDF2, or cryptographic hashes. It exploits wallet determinism after the attacker has enumerated too few candidates for the initial entropy.
- The vulnerable application receives bytes to generate mnemonics via
WordArray.random(). - The attacker reproduces the compatible behavior of the generator and lists its reachable outputs.
- Each candidate is encoded as a valid BIP39 mnemonic with a checksum.
- The seed is derived from the mnemonic via PBKDF2-HMAC-SHA512; then, BIP32/BIP44 paths generate private keys and addresses.
- Derived addresses are verified against public blockchain data.
- By finding an address with a balance, the attacker already has the same private key as the owner and can sign transactions.
BIP39 seed = PBKDF2-HMAC-SHA512( password = mnemonic, salt = “mnemonic” || passphrase, c = 2048, dkLen = 64).
\[
\mathrm{seed}=\operatorname{PBKDF2\!\text{-}\!HMAC\!\text{-}\!SHA512}
(\mathrm{mnemonic},\,\texttt{"mnemonic"}\parallel\mathrm{passphrase},\,2048,\,64).
\]
If the initial entropy is taken only from the set Ω eff , then the deterministic transformation f does not expand it:
seed = f(E), E ∈ Ω eff ⇒ |{f(E)}| ≤ |Ω eff |.
\[
\mathrm{seed}=f(E),\quad E\in\Omega_{\mathrm{eff}}\quad\Rightarrow\quad
|\{f(E)\}|\leq|\Omega_{\mathrm{eff}}|.
\]
Therefore, PBKDF2 increases the cost of verifying a single candidate but does not return missing entropy bits. This is a fundamental property of deterministic information transformations.
Audit pseudocode
Below is a safe, illustrative template for identifying a dangerous path in source code. It does not generate keys or implement an attack.
# Anti-pattern: Prohibited for seeds, keys, tokens, and nonces entropy = CryptoJS.lib.WordArray.random(16) # Preferred browser path: Web Crypto API bytes = new Uint8Array(16) crypto.getRandomValues(bytes) # Node.js: crypto.randomBytes(16) # Policy: Then write the assembly version, CSPRNG source, and self-test fact to the audit log.
Real-world engineering context: the upstream package bip39 used a path randombytesdelegating to crypto.randomBytes in Node.js and crypto.getRandomValues the browser. In the fork ferrumnet/bip39adapted for React Native, this path was replaced with CryptoJS—an example of how a portability solution can change the cryptographic threat model.
5. Complexity assessment
With a full pipeline testing R candidates per second, the expected time to find an equiprobable target state is approximately half the space divided by the speed:
T avg ≈ 2 h−1 / R, where h is the effective entropy in bits.
\[
T_{\mathrm{avg}}\approx\frac{2^{h-1}}{R}.
\]
| Effective entropy | Average number of candidates | Cryptanalytic meaning |
|---|---|---|
| 39 bits | 2 38 | A finite, engineeringly feasible space for parallel enumeration and filtering by public addresses. |
| 47 bits | 2 46 | Substantially larger, but many orders of magnitude smaller than the design target of 256 bits, the researchers qualify it as enumerable on commodity hardware. |
| 128 bits | 2 127 | Almost impossible to achieve by brute force. |
| 256 bits | 2,255 | It is practically impossible to achieve by direct enumeration with a huge margin. |
Reducing from 128 to 39 bits represents a space reduction factor of approximately 2.89 ; for 256 to 47 bits, it’s 2.209 . Address verification is especially convenient for an attacker because the blockchain acts as a public oracle: the balance, history, and existence of an address are available without contacting the victim.
Historical analogues
- Netscape SSL (1995). The predictability of key generation, based on timing and process IDs, became a classic example of how weak RNG initialization undermines the security of a protocol under formally strong symmetric cryptography.
- Android SecureRandom / Bitcoin (2013). The flawed nonce randomness in ECDSA led to the extraction of the private key when the nonce was repeated or predictable. In Ill Bloom, it’s not the signature nonce that’s vulnerable, but the underlying secret of the HD wallet, but the general principle is the same: secrecy doesn’t survive a failure of the random number generator.
- PS3 ECDSA (2010). Nonce reuse allowed algebraic recovery of the private key. This is a contrasting example: there, the key was extracted from signatures; here, the attacker replicates the mnemonic generation before the signatures were created.
6. Why hashing doesn’t cure
A common mistake is to assume that SHA-256, HMAC, or PBKDF2 will “strengthen” weak random input. Cryptographic one-wayness makes it difficult to reverse an arbitrary hash, but the attacker in this model doesn’t reverse the hash. They simply enumerate a small set of inputs, apply the same public algorithm, and compare the results.
H ∞ (f(X)) ≤ H ∞ (X) for a deterministic function f.
\[
H_{\infty}(f(X))\leq H_{\infty}(X)\qquad\text{for deterministic }f.
\]
Here, H ∞ is the min-entropy, defined as H∞(X) = −log2(max_x Pr[X=x]). It directly characterizes the complexity of the optimal guessing attack; for a small candidate space, the subsequent KDF chain remains reproducible.
7. Limits of applicability
The presence of a dependency crypto-js < 4.0.0 alone does not prove exploitation. The risk is determined by the use of a vulnerable function for security-sensitive values: the entropy of a mnemonic, key, token, salt with security requirements, or similar material.
In contrast, importing a weak seed into a hardware wallet doesn’t solve the problem: the hardware device correctly generates the same keys from predictable input. The hardware wallet protects key transactions but is unable to increase the entropy of the previously generated seed.
Operational security. Only the public address is allowed for the public verifier. Never share your mnemonic, private key, password, keystore, or backup file with the website, support, scanner, bot, or researcher.
8. Forensics methodology
For the wallet owner, the primary goal is not to “check the reliability of the words,” but to establish the origin of the seed: the application, version, OS, creation date, migration path, and import. A negative result from the address checker merely indicates the absence of the address in the published set, not cryptographic proof of security.
| Stage | Action | Artifacts |
|---|---|---|
| Inventory | Identify all applications, versions, dependency lockfiles, and mnemonic generation date | APK/IPA, package-lock.json, yarn.lock, SBOM, release logs. |
| Data tracing | Check if the secret generation call reached WordArray.random() | Source code, source maps, dependencies, unit tests. |
| Exposure assessment | Match addresses with published sets, but do not enter seeds | Only public addresses, txid, derivation paths. |
| Containment | Create a new wallet on a trusted CSPRNG and withdraw assets | New mnemonics, new addresses, confirmed transactions. |
| Documentation | Preserve the timeline and evidence for investigation | Timestamps, artifact hashes, txid; no secrets published. |
9. Recommendations for developers
- Upgrade to CryptoJS 4.0.0 or later, but for generating secrets, it is preferable to directly use system APIs: Web Crypto
crypto.getRandomValues(), Node.jscrypto.randomBytes(), native cryptographic APIs of mobile OS. - Build SBOM and trace transitive dependencies, including forks for React Native; inspect not only the manifest, but also the lockfile and the actual bundle.
Math.random()Disable the use of weak PRNGs in key generation, mnemonics, nonces, reset tokens, and session secrets using linters, code reviews, and SAST .- Introduce entropy origin tests: the test should assert a specific CSPRNG API, not just the length of the byte array or the statistical distribution of the result.
- If a RNG defect is detected, treat it as a secrets lifecycle incident: identify the affected time window, notify owners, and ensure automated migration.
- Do not replace a CSPRNG by “mixing” several weak sources without a strict model: a correct systemic CSPRNG is simpler, more verifiable, and more reliable.
10. Recommendations for owners
- If the seed was created by an affected version or the origin cannot be reliably excluded, consider it potentially compromised.
- On a separate trusted device, create a new wallet and a new recovery phrase using a current, verified product or hardware wallet that generates a seed locally.
- Transfer all assets to addresses derived from the new seed: consider all networks, accounts, tokens, and alternative derivation paths.
- Don’t import the old phrase into an “updated” wallet in hopes of fixing it: importing keeps the same cryptographically weak root.
- After migration, stop using old addresses and do not send new receipts to them.
11. Conclusion
Ill Bloom is not an attack on BIP39, PBKDF2 , or blockchain consensus, but a practical demonstration of the axiom of cryptographic engineering: the quality of secrets is no better than the quality of the entropy source. The drop in space from 2128/2256 to approximately 239/247 changes the nature of the problem from impossible cryptanalysis to reproducible search over a finite set.
The main lesson for the ecosystem is that a dependency patch stops the creation of new weak secrets, but does not invalidate existing ones. The only complete response to a historically weak seed is cryptographic rotation: a new secret, new derived keys, new addresses, and a transfer of funds.
Sources
CryptoJS Weak RNG and Ill Bloom: cryptanalytic parsing: https://douban.ru/cryptojs-weak-rng-and-ill-bloom-cryptanalytic-parsing/
- The Hacker News. CryptoJS Weak RNG Behind $5.7 Million in Drains Affects Five Crypto Wallet Apps , August 2026. https://thehackernews.com/2026/08/cryptojs-weak-rng-behind-57-million-in.html
- GitHub Advisory Database. GHSA-rg76-677x-56q9: Insufficient Entropy in Cryptographic Secret Generation via Vulnerable CryptoJS Dependency Chain . https://github.com/advisories/GHSA-rg76-677x-56q9
- Ill Bloom/Coinspect. Technical Disclosure: The CryptoJS Randomness Vulnerability . https://illbloom.org/articles/cryptojs-vulnerability/
- BIP-0039. Mnemonic code for generating deterministic keys . https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki
- BIP-0032. Hierarchical Deterministic Wallets . https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
