Over two days starting July 30, 2026, coins left Coldcard-generated wallets in three coordinated waves. By August 2, on-chain clustering by Galaxy Research put the confirmed total near 1,367 BTC ($88.6M) across more than 4,500 addresses. The victims had done what the industry told them to do. They bought a well-regarded, security-focused hardware signer, generated the seed on the device, and kept it offline. Many had not touched those wallets in years. The attacker never touched a single device.
Update, 3 September 2026. Galaxy’s August 14 report puts high-confidence losses at 1,778.84 BTC ($112.7M) from more than 8,600 addresses, with at least 15 independent attackers. No confirmed activity after August 6. The August 2 figures above are left as written.
The cause, per Coinkite’s advisory and technical backgrounder, was a firmware regression that shipped in March 2021 and survived five years of releases and reviews: seed generation silently stopped using the hardware random number generator. I read the fix in the firmware repository to see what the bug and the repair look like at source level. Both are smaller than I expected.
One preprocessor semantic
Coldcard’s board configuration defines MICROPY_HW_ENABLE_RNG as 0 because Coinkite supplies its own hardware-RNG wrapper. That define is still there today in each board’s mpconfigboard.h. Downstream, the guard in MicroPython’s random module checked #ifndef MICROPY_HW_ENABLE_RNG: whether the macro exists, not whether it is enabled. Defined-as-zero passed the check, and the build quietly linked MicroPython’s software fallback, Yasmarang, a toy PRNG for chips with no hardware RNG at all, seeded from the chip’s unique ID and boot-time state and never fed fresh entropy again.
The fix commit, dated July 31, is eleven files and sixty lines. The board’s own rng.c now opens with #if MICROPY_HW_ENABLE_RNG followed by #error, a value check. The upstream fallback is compiled from /dev/null so it can never be built. And the compiler is passed -Dpyb_rng_yasmarang=error-do-not-want-this, so any surviving reference fails to link instead of failing silently. Two weeks later a boot-time self-test was added that proves rng_get() reaches the hardware and halts the device if it does not.
By Coinkite’s estimate, seeds on Mk2 and Mk3 (firmware 4.0.1 through 4.1.9) carried roughly 40 bits of effective entropy. Mk4, Mk5 and Q got an accidental partial rescue in 2022, a 32-bit reseed from the secure elements, bringing them to roughly 72 bits. The design target was 128. A 40-bit keyspace is a weekend project on commodity hardware, and the sweeps so far are consistent with exactly that. Seventy-two bits is far harder, and no public evidence yet shows one cracked, but Coinkite tells those users to migrate too rather than wait to find out.
Present, never called. The hardware-TRNG implementation existed in every affected binary, reviewed and intact. It was simply never called from the seed-generation path. Coinkite’s language is precise: reviews “did not verify end-to-end symbol resolution and call reachability.” The check confirmed the code existed. Nobody confirmed it was reachable. That is the same failure shape as an unverified backup: presence mistaken for function.
A mundane change. Per an independent reading of the commit history, the regression arrived while integrating a crypto library, as a workaround for a duplicate-symbol compile error. Nothing about it looked like a security decision.
Why nobody could see it
Keys derived from a broken RNG look exactly like keys derived from a perfect one. A seed with 40 bits of real entropy still expands into well-distributed, unique-looking addresses, and no test suite run against outputs can distinguish “unpredictable” from “deterministic but unexamined.” Entropy is not a property of the bytes. It is a property of the process that produced the bytes, and once generation is over, that process has left no trace unless you deliberately recorded one.
That separates key generation from almost everything else in custody. A backup can be verified after the fact. A recovery procedure can be drilled after the fact. Randomness is the one input you can only witness at the moment of creation. Whatever assurance you want about it has to be built into the ceremony and evidenced at generation time. Afterward is too late, structurally and permanently.
Who survived
Every surviving group made its decisive move at generation time. Dice-roll users survived: on affected firmware, 50+ user-supplied rolls were hashed together with the weak device entropy, and the rolls alone carry about 128 bits. The people teased for paranoia-theater dice ceremonies are the people whose funds never moved, and Coinkite has since made user-supplied entropy mandatory for every new seed. Multi-vendor multisig users survived, because a 2-of-3 across manufacturers loses one key to one vendor’s design failure and stays below threshold. Wizardsardine’s writeup names the property doing the work: dissimilar redundancy. Three devices of the same brand are redundancy against loss, not against design failure, and this failure was perfectly correlated across the brand. Passphrase users got a partial reprieve, a second factor bolted onto a broken first factor, and Coinkite still tells them to migrate.
There is also a group that thinks it survived and has not. A weak seed restored onto a different, perfectly good hardware wallet is still a weak seed. Neither a firmware update nor a change of vendor repairs a key that was already generated.
Everyone else is in a forced migration against parties who can enumerate the keyspace, and the race was rigged from the start. Galaxy’s clustering has the first wave already running on the morning of July 30, the day the advisory went out. The wave-1 collector address, bc1qnk4zh9qcnap2mycp56qjrgza3cc8ylrh8fecp0, shows 506 incoming payments totalling 594.48 BTC as of 3 September 2026, one address per victim, swept and consolidated by a script working through a precomputed list. When a key-compromise event goes public, your real recovery time is whatever the attacker’s schedule allows. And the advisory itself was a moving target: first scoped to the Mk3, widened to Mk4, Mk5 and Q a day later. Anyone who read the first version and stood down was wrong by the following afternoon.
What a key-generation record has to contain, then, is short. Where the randomness came from, what was added to it, how the two were combined, and two more items, about the quorum and about the migration path, that none of the ceremony templates I have seen has a line for. Backups earn their trust through later verification. Randomness never gets that chance. The ceremony record is the only witness entropy will ever have.