Weak Random Number Generator in CryptoJS Led to $5.7M in Crypto Wallet Thefts
Translated by a model; the original is in Russian.
Coinspect, a firm specializing in blockchain security, has named the culprit behind the string of crypto wallet drainings that it itself dubbed “Ill Bloom” back in July. It turned out to be the CryptoJS.lib.WordArray.random() function from the popular JavaScript cryptography library. Introduced 12 years ago, it yielded far too little entropy — and it was on that basis that some wallets generated their recovery phrases.
The scale of the problem is plainly visible in the numbers. For 128- and 256-bit entropy, the brute-force space should amount to 2^128 and 2^256 possibilities. The vulnerable generator shrank it to roughly 2^39 and 2^47 — that is, to magnitudes that can be brute-forced on an ordinary computer. The researchers reproduced the attack: they enumerated the output values, turned them into BIP39 phrases, computed the addresses and cross-checked them against public blockchain data.
Five apps and money in two waves
Coinspect confirmed five affected applications: RRWallet (abandoned, no fixes), Bexo Wallet (fixed in 20.1.0, but the updated builds have not yet been published), NanChat (fixed in 1.3.0), Bitcoin Libre (fixed in version 4 back in July 2024) and Milo (abandoned). At the same time, the firm honestly acknowledges that a complete list of affected wallets cannot be established — some of them have already been removed from the app stores.
By Coinspect's estimate, the thefts occurred in two waves. On May 27, about $3.14M was drained from 431 accounts, and from May 30 through July 13, another $2.55M was taken from addresses tied to 522 seed phrases, including roughly 2.18M USDT from a single Tron account on July 4. In total, the measured losses came to $5,690,922, and this, the researchers stress, is only a lower bound. The analysis covered 2,114 seed phrases and addresses across the Bitcoin, Ethereum, Tron, Rootstock and Polygon networks.
An irony of history: a fix that was rolled back
The fate of the vulnerability itself deserves separate mention. The weak Multiply-With-Carry generator, seeded via Math.random(), made its way into the library in June 2014. Versions 3.2.0 and 3.2.1 switched to native cryptographic randomness — but in 3.3.0 the old code was brought back, the change having been deemed a breaking one. As a result, updating within the 3.x branch could carry a project away from the fixed version to the vulnerable one. The problem was finally closed only in version 4.0.0 in February 2020.
On August 5, CryptoJS maintainer Evan Vosberg published advisory GHSA-rg76-677x-56q9 with a critical rating and a CVSS score of 9.0. An important caveat: the mere presence of the dependency does not by itself make an application vulnerable — the danger lies only in generating sensitive values with this function.
The key takeaway for users: updating the app does not fix a phrase that has already been created. A recovery phrase generated by a vulnerable version remains guessable everywhere it is imported — including into a hardware wallet. Those whose phrases may have taken this path will have to create a new one and move their funds. Coinspect's public checker accepts addresses, but not the phrases or keys themselves.
Source: The Hacker News
Comments
Sign in, to comment.