DEV Community

Sergei Palii
Sergei Palii

Posted on • Originally published at sepia.software

The audit confirmed the generator existed. It did — and it was never called

Since 30 July, roughly 2,000 BTC — about $130 million at current prices — has been drained out of Coldcard hardware wallets. No phishing, no malware, no stolen laptop. These devices never touch the internet, and nobody touched them. The attackers simply worked out the private keys.

One sweep took $70 million in 41 minutes. Galaxy Research confirms 1,596 BTC from around 7,300 addresses across three waves plus fourteen smaller incidents; with a suspected fourth wave the total reaches about 2,055 BTC. The manufacturer counts at least fifteen separate attackers — once the hole was known, everyone piled in.

What follows is not a chronicle of the theft. It is an account of why the reviews missed it, because they did not miss it through negligence. They missed it exactly the way reviews are built to work today.

One preprocessor directive

In March 2021, Coinkite moved Coldcard's cryptography onto libsecp256k1, the same library Bitcoin Core uses. That was a sound call: rolling your own crypto is worse than sharing everyone else's. The integration is where it came apart.

The migration quietly rerouted seed generation away from the hardware random number generator and onto MicroPython's software fallback — an algorithm called Yasmarang that exists for devices with no randomness chip at all. Coldcard has such a chip. It simply stopped being asked.

The cause is a single token. The build guard was written with #ifndef, and that directive checks whether a setting is defined, not whether it is on. Coinkite had defined the setting as zero, meaning "off". Zero is still a defined value, so the check passed and the build completed. Both versions of the function had identical signatures, so nothing looked broken to a human reader either.

The result: the key search space collapsed from 128 bits to roughly forty on older models. Forty bits is brute-forceable offline, without a single network request. Hence $70 million in 41 minutes.

Why nobody noticed for five years

Coldcard was reviewed. The reviews confirmed that the real hardware generator was present in the code and worked correctly. That was true. Here is Coinkite's own post-mortem, verbatim:

The bulk of randomness on the COLDCARD was coming from a PRNG that I didn't know was actually in the source code base. At the same time the carefully crafted TRNG code I wrote was being used, but just by chance, and only for less important things.

The correct generator existed, was correct, and was even being called. Just not where it mattered.

Nick Percoco, Kraken's chief security officer, put the gap most precisely: consumers are asked to trust a manufacturer's implementation of the single most critical function in the system, with no independent verification that the approved entropy path is the one actually executing.

This is not an abstraction. The rest of the security industry treats that check as standard: NIST SP 800-90B in the US and BSI AIS-31 in Germany specify how physical random number generators are designed, tested and validated. Hardware wallets have no equivalent. There is Common Criteria on secure elements, a handful of certifications and vendor-sponsored audits — and none of them systematically force anyone to demonstrate which code actually runs on the device in a buyer's hand.

We have written about preparing a smart contract for audit, and about why "we were audited" and "we have no holes" are different claims. Coldcard is that idea in its purest form: an audit can be diligent, thorough, and still be answering the wrong question.

"Does the component exist" and "does it execute" are two different questions. The first is answered by reading code. The second only by observing the built firmware.

The careful ones were hit first

The ugliest part of the story surfaced once people started looking at who had been losing coins before 2026.

Coldcard lets an owner mix in their own randomness with rolls of a physical die. The advice is sensible and has circulated in the community for years. The problem is the arithmetic: one roll of a six-sided die adds about 2.585 bits. To reach the 128 bits Coinkite itself treats as the minimum you need at least 50 rolls; for 256-bit security, 99. The device does not enforce that floor. Its own documentation says it does not limit the number of rolls, but will warn you if you apply too few.

It warns, and then lets you through.

Security researcher Taylor Monahan, who examined the earlier Coldcard losses, says that in almost all cases those victims were the dice rollers. A ritual performed halfway left a seed with so little entropy that cracking it was trivial — long before anyone knew the firmware had a defect at all.

The subtlety is that there are two paths. In the standard flow the rolls are hashed together with the device's own randomness, so extra rolls only add protection on top of the flawed generator. But Coldcard also offers a dice-only seed, where — in Coinkite's own description — the roll sequence is hashed directly and the device's generator is not used at all. Pick that path, roll twenty times and stop, and the entire security of the seed rests on those twenty rolls.

A safeguard applied halfway turned out to be more dangerous than no safeguard. That generalises well beyond wallets: a mechanism that warns but does not stop you hands the arithmetic to the user, and the user is not going to do the arithmetic.

What changed in 2026

Five years of going unnoticed used to be a price you could pay. It is not any more, and the numbers show it.

While this theft was under way, sixteen developers assembled a volunteer red team and pointed AI models at bitcoin wallets, cryptographic libraries and infrastructure. In twenty-four hours: 4,962 findings across 390 projects, of which 85 critical and 635 high severity. That works out to roughly one critical bug per person per hour, at around ten thousand dollars a day in compute.

What the participants say matters more than the totals. Most critical findings were confirmed quickly by project owners, because verifying them now costs almost nothing using the same tools. The bottleneck has moved: the hard part is no longer finding a hole, it is routing it to the right maintainer. And there is a stated reason to publish fast — people outside the red team will reach the same findings anyway.

That is why the argument over whether a human or a machine found the Coldcard flaw is beside the point. We covered how AI weakened a post-quantum signature in 60 hours that humans had studied for years. This is the same shift from the other side: the five-year head start that any long-untouched codebase quietly relied on is over.

What to do about it

If you hold keys on a Coldcard, the drill is known: check your model and firmware version against the manufacturer's advisory, generate a fresh seed on patched firmware, move the funds. The defect affects single-key setups; multisig is not touched. One detail for anyone being swept right now: in the latest wave the attackers opted into replace-by-fee, which means the transaction can be outbid — if you spot your address in the mempool, pay a higher fee and move your coins first. The window is minutes.

But the lessons run wider than wallets, and they are about how you verify your own code.

  • Verify the executing path, not the presence of code. "The function exists and is correct" does not mean "it is the one being called". For critical paths, write the test that fails when the source is swapped: not "the TRNG works" but "the seed came from the TRNG".
  • Treat definedness guards as suspect. #ifndef, defined(), if (config.FLAG) — zero, the empty string and false are all defined. Check the value, not the declaration.
  • Identical signatures on two implementations invite silent substitution. When the fallback and the primary share an interface, the compiler stays quiet and so does review. Give them different names so a swap shows up in the diff.
  • A mechanism that warns but does not forbid is not a mechanism. A threshold a user can skip is a threshold a user will skip.
  • Reconsider what your last audit actually established. If it was about presence and correctness rather than execution, its conclusions have aged — not because the auditors were wrong, but because finding things got an order of magnitude cheaper.

That last point is practical rather than rhetorical. Code that was considered reviewed for five years is now being taken apart in hours for ten thousand dollars a day. If you have contracts or firmware in production, it is cheaper to point those tools at them yourself than to wait for someone else to. We do security and teardown work on web3 products — but you can do this without us. What matters is doing it first.


This is the kind of work we do at Sepia Software.

Top comments (0)