
OAK (On-Chain Attack Knowledge Base), insufficient entropy in key generation (T11.004) and coordinated asset withdrawal (T5.001).
Ill Bloom is a documented cryptocurrency wallet compromise in which BIP-39 mnemonics were generated from a non-cryptographic pseudorandom number generator. The first confirmed mass write-off on May 27, 2026, affected 431 accounts across Bitcoin, Ethereum, Tron, Rootstock, and Polygon; two waves of write-offs resulted in a measurable lower bound of damage of $5,690,922. The incident demonstrates that the cryptographic strength of secrets is determined not by the length of the seed phrase representing them, but by the min-entropy of the source before conversion to mnemonics.
The key cryptanalytic fact is the reduction of the search space: with nominal 128 or 256 bits of BIP-39 entropy, the actual space is estimated to be approximately 2^39 and 2^47, respectively. The attacker doesn’t solve ECDLP on secp256k1 and doesn’t reverse SHA-256 or PBKDF2: they enumerate a significantly smaller set of weak PRNG states offline, reproduce mnemonics and HD trees, and then match the derived addresses with on-chain data.
Keywords
BIP-39, BIP-32, HD wallets, entropy, CSPRNG, CryptoJS, Multiply-With-Carry, Math.random(), cryptanalysis, secp256k1, on-chain forensics, Bitcoin, Ethereum, Tron, Polygon, Solana, Rootstock, EVM L2.
The actual picture
| Parameter | Observation | Cryptanalytic interpretation |
|---|---|---|
| The first mass sweep | May 27, 2026: 431 accounts, approximately $3.14 million; Bitcoin, Ethereum, Tron, Rootstock, and Polygon. | Synchronicity across unrelated addresses and networks is consistent with a pre-prepared directory of weak keys and a multi-chain infrastructure. |
| Second wave | 30.05—13.07.2026: 522 seeds, about $2.55 million. | Periodic monetization of a pre-listed keyspace, not a one-off phishing attack. |
| Total measured damage | $5,690,922 is the lower estimate. | The address sets are incomplete; the absence of a match in the checker does not prove the absence of risk. |
| Root cause | CryptoJS.lib.WordArray.random(), CVE-2026-71851/GHSA-rg76-677x-56q9. | The random bytes user library function was mistakenly used as a source of key material. |
| Mechanism | A variant of Marsaglia Multiply-With-Carry, initialized Math.random()with , not a CSPRNG. | Predictability/small state replaces a 128-256 bit level problem with a search over a much smaller space. |
Statement of the problem
In the normal model, HD wallet security begins with uniform entropy ENT. BIP-39 merely encodes this entropy into checksum words; it does not create randomness. PBKDF2-HMAC-SHA512 then converts the mnemonic into a 512-bit seed, from which BIP-32 derives the extended keys and private keys of individual paths.
CS = MSB_(ENT/32)(SHA256(ENT)) M = bits(ENT || CS), split into 11-bit groups and mapped to BIP-39 words S = PBKDF2-HMAC-SHA512(password = M, salt = “mnemonic” || passphrase, c = 2048, dkLen = 64)
The corollary is fundamental: deterministic subsequent transformations increase the representation length, but not the min-entropy of the input unknown to the attacker. If the original generator had effective entropy h, then the practical security of the complete derived key set is limited to approximately h, not 128, 256, or 512 bits.
H_∞(S) ≤ H_∞(M) ≤ H_∞(ENT) = h W_attack ≈ 2^h For Ill Bloom: h ≈ 39 or 47, not 128 or 256.
An example from cryptanalytic practice. Milk Sad (CVE-2023-39910) used MT19937, seeded with a 32-bit system time, and limited the internal entropy to 32 bits. Historically, a different PRNG and a different product resulted in the same class error: the source of entropy, not the ECDSA cryptography, is attacked.
Compromise chain
- Vulnerable mobile app calls
WordArray.random()to obtain BIP-39 entropy. - A nominally correct mnemonic receives a valid checksum and is outwardly indistinguishable from a secure one.
- The attacker iterates over the states/seeds of the weak generator, reconstructing possible values
ENTand BIP-39 phrases. - For each candidate mnemonic, a BIP-39 seed and a set of HD branches for the target networks are output.
- The resulting public addresses are compared with UTXO indices, balances, tokens, and contract assets.
- For addresses with liquid assets, withdrawal transactions are prepared and broadcast to the relevant networks.
# Концептуальная, неэксплуатационная схема аудита
for state in candidate_prng_states:
entropy = reproduce_prng_output(state)
mnemonic = bip39_encode(entropy)
seed = bip39_pbkdf2(mnemonic, passphrase="")
addresses = derive_public_addresses(seed, approved_derivation_paths)
flag_if_matches_internal_inventory(addresses)
This fragment intentionally does not contain the implementation of the generator, paths, scanners, or spending logic: its purpose is to demonstrate the boundary between secure auditing and exploitation. For security purposes, such a process should only be applied to one’s own wallets, isolated test data, or addresses exposed by researchers.
Why PBKDF2 doesn’t save
PBKDF2 with 2048 iterations serves as the standard transformation of a BIP-39 mnemonic to a seed, but does not correct the predictable mnemonic. For an attacker who enumerates possible M, PBKDF2 becomes a known computable function: increasing the output length to 512 bits does not transform the space from 2^39 to 2^512.
If M = f(z), z ∈ Z, |Z| = 2^h, then S = PBKDF2(M) = PBKDF2(f(z)); searching for S reduces to searching for z, that is, O(2^h), not O(2^512).
A real-life example. When compromising passwords, key stretching helps only proportionally to the unknownness of the original password. If the initial secret value is chosen from a small, predictable dictionary, iterations slow down the search but do not restore the missing entropy; Ill Bloom applies the same logic to the seed.
Cross-compromise
A single mnemonic is the root of a deterministic tree, not a separate secret for each network. Therefore, an incident must be investigated across multiple derivation paths, address formats, and accounts, not just the balance of a single network: a single weak seed can generate keys for UTXO networks, EVM ecosystems, Tron, Solana, and other compatible implementations.
| Family | Typical cryptographic binding | Risk with a weak BIP-39 root |
|---|---|---|
| Bitcoin | BIP-32/44/49/84/86; secp256k1; UTXO. | All scanned addresses and change branches are compromised, not just the visible receiving address. |
| Ethereum, Polygon, Rootstock, EVM L2 | Typically secp256k1 and EVM accounts; paths may vary. | One derived private key controls the native balance, ERC-20 tokens, NFTs, and contract positions of a given account. |
| Tron | Account model and secp256k1, different address format. | The identity of the original mnemonic is preserved, although the address encoding and network operations differ. |
| Solana | Ed25519 and its own derivation agreements. | Compromise is possible if the wallet derived Solana keys from the same mnemonic and the attacker correctly reproduces the implementation. |
Precise wording. The confirmed first coordinated sweep in the original report explicitly lists Bitcoin, Ethereum, Tron, Rootstock, and Polygon. Solana appears in the description of the multi-chain research/risk area, but it cannot be automatically declared part of the first transaction wave without separate on-chain attribution.
Historical analog. Milk Sad also exhibited a cross-chain effect: a weak generator creates the root material, so changing the blockchain doesn’t fix the flaw. Key serialization and derivation agreements are different, but there is no fundamental loss of source secrecy.
On-chain features
For weak-key cohort-sweep forensics, it’s not just the final recipient addresses that are important. The signal is generated by a combination of temporal clustering, victim heterogeneity, repeatable spending patterns, pre-established network pipelines, and the simultaneous coverage of multiple blockchains.
| Observed feature | Interpretation | Output limitation |
|---|---|---|
| Simultaneous withdrawal from unrelated addresses | A pre-computed set of private keys is likely. | It does not in itself prove the common identity of the attackers. |
| Covering multiple networks with one wave | The operator has cross-chain derivation and operational execution tools. | Communication between networks requires verification of specific key/address matches. |
| Massive sweep after years of hidden vulnerability | Compatible with offline pre-calculation and asset value ranking. | Does not allow dating the moment of the first selection. |
| Empty result of public checker | There is no match with a known set of indicators. | Does not provide proof of security when the address set is incomplete. |
Chronology
| Date/period | Event |
|---|---|
| June 2014 | A weak implementation appears in CryptoJS 3.1.2-4. |
| 2017 (branches 3.2.0/3.2.1) | A temporary security fix has been released. |
| 3.3.0 | The fix was rolled back for backward compatibility; the weak implementation returned. |
| May 27, 2026 | First confirmed coordinated sweep: 431 accounts, approximately $3.14 million. |
| May 30—July 13, 2026 | Second wave: 522 seeds, about $2.55 million. |
| July 2026 | Public disclosure and checker; 2,114 risky wallets identified reported with incomplete coverage. |
| August 5, 2026 | GHSA-rg76-677x-56q9 / CVE-2026-71851 published; fix — CryptoJS 4.0.0. |
Affected software
| Application | Status according to original report | Practical conclusion |
|---|---|---|
| RRWallet | Discontinued, no fix. | Immediate migration to a new seed. |
| Milo | Discontinued, no fix. | Immediate migration to a new seed. |
| Bexo Wallet | Fixed in 20.1.0; as of 08/06/2026, the assemblies had not yet been downloaded. | Fixing the application does not cure already created mnemonics. |
| NanChat | Fixed in 1.3.0. | A new seed and asset transfer are needed. |
| Bitcoin Libre | Fixed in v4 July 2024 | You need to evaluate the version in which the seed was created. |
Methodology of scientific verification
A proper check must be reproducible, legally permitted, and prevent manipulation of other people’s secrets. You cannot export the mnemonic to web checkers, transfer it to third parties, or “check” the phrase by importing it into new services.
- Record the provenance: application name, exact version, platform, date, and mnemonic generation method.
- Build SBOM/lockfile analysis: determine if the key generation path ever reached CryptoJS 3.x, excluding 3.2.0/3.2.1, or another non-CSPRNG source.
- Check only public addresses against the official checker, treating a positive match as an indicator and a negative match as the absence of a known match.
- Conduct a local inventory of all native derivation paths and networks; include native coins, tokens, NFTs, staking, DeFi positions, and change addresses.
- Create a new wallet with an independent CSPRNG source, confirm the backup, and migrate assets.
- Preserve transaction IDs, times, amounts, and routes for forensics; do not publish seeds or private keys.
# Защитная проверка зависимости в проекте JavaScript
npm ls crypto-js
# затем вручную проверяется: использовалась ли зависимость именно
# в пути генерации BIP-39 ENT, а не в несекретной прикладной функции
A practical example. Auditing “crypto-js installed” is insufficient: the dependency can only be used to hash UI data. Proving the risk requires data-flow analysis from the mnemonic generation call to the actual source of the random bytes.
Countermeasures
| Level | Control | Justification |
|---|---|---|
| User | Create a new wallet and transfer funds; do not re-import the old phrase. | Entropy is irreversibly lost at the moment of generation. |
| Wallet developer | Use only platform CSPRNG: crypto.getRandomValues()or crypto.randomBytes() OS RNG. | This ensures cryptographic unpredictability, not just statistically “random” appearance of the bytes. |
| CI/CD | Add SCA, SBOM, vulnerable version blocking, and entropy source tests. | Not only the packet is identified, but also the dangerous data flow to generate secrets. |
| Library | Don’t provide an ambiguous “random” API without a CSPRNG guarantee; explicitly document the properties. | The risk of dangerous reuse by developers is reduced. |
| Change management | Disable rollback of security-fix for key generation without formal cryptographic review. | Backward compatibility of weak inference is not a valid property of custody code. |
Attribution limitations
The source material characterizes the attribution as pseudonymous: no specific operator has been publicly identified, and no connection to the tracked OAK actor has been established. A coordinated multichain sweep is a strong behavioral indicator of a planned campaign, but does not prove the identity of the perpetrators with the Milk Sad attackers or other incidents.
Conclusions
Ill Bloom is not an attack on the mathematical strength of secp256k1, SHA-256, HMAC-SHA512, or BIP-32. It is a pre-cryptographic failure: a weak random source reduced the set of possible HD tree roots to a brute-force level, after which all standardized transformations deterministically propagated a single flaw across multiple networks.
For cryptanalysis, the key lesson is this: the nominal key size and the number of mnemonic words are not a measure of security without assessing the entropy’s origin. For on-chain response, the key lesson is different: an incident must be limited by its seed origin and multiple derived paths, not by a single network, address, or application version installed today.
Sources
Ill Bloom — on-chain analytics of cross-compromise of networks: https://ctxc.ru/ill-bloom-on-chain-analytics-of-cross-compromise-of-networks/
- OnChainAttack.org (OAK). Ill Bloom – recovery phrases from less-common mobile wallets were generated by an insecure PRNG… Working example, 2026.
- GitHub Security Advisory. GHSA-rg76-677x-56q9: CryptoJS.lib.WordArray.random() uses a weak PRNG (Ill Bloom) ; CVE-2026-71851, 2026.
- Coinspect. Ill Bloom: Crypto Wallet Vulnerability , 2026.
- NIST. SP 800-90A Rev. 1: Recommendation for Random Number Generation Using Deterministic Random Bit Generators , 2015.
- NVD. CVE-2023-39910: Milk Sad/Libbitcoin Explorer weak entropy seeding , 2023.
- BIP-39. Mnemonic code for generating deterministic keys ; BIP-32. Hierarchical Deterministic Wallets .
