Coldcard Exploit: The Timeline Is the Tell

A config flag nobody checked for five years cost Coldcard users $88 million. The bug is just a footnote. What matters is who got to decide when the rest of us found out.

#bitcoin#security#coldcard#self-custody#incentives#hardware-wallets

The Timeline Is the Tell

Five years, one unchecked config flag, and a disclosure policy written on the assumption that the vendor would always be the one holding the stopwatch.

Jonathan Goodman’s bitcoin lived in a safety deposit box. Not a laptop, not a phone, not an exchange account with a phone number attached to it. A Coldcard in a bank vault, seed generated offline, device never once connected to the internet.

It took seven minutes to empty. 18.25 BTC, around $1.6 million Canadian, drained out of a wallet that nobody ever physically touched.

“Perhaps the hardest part about this is that I did everything right,” he wrote afterward.

He’s not wrong, and that’s the sad part. He followed the advice; but that advice was sitting on top of a config flag that nobody had looked at since March 2021.

The switch that was never on

Here’s the mechanics for anyone who isn’t already up to speed:

Coldcards ship with a true hardware random number generator built into the STM32 chip. That’s most of the value prop: your seed comes from physical entropy, not from software guessing at randomness. In March 2021, during a migration of elliptic-curve operations over to Bitcoin Core’s libsecp256k1 library, Coinkite’s production board config set a macro called MICROPY_HW_ENABLE_RNG to zero. That was deliberate. They had their own hardware RNG wrapper and wanted the build to use that instead.

The supporting library, libngu, then asked the wrong question: it checked whether the macro was defined rather than whether it was enabled. The macro was defined. Its value was zero, but nobody asked about the value. So the check passed, no error fired, and seed generation silently fell to MicroPython’s software pseudorandom generator.

That fallback pulls its starting state from the device’s unique factory ID and its timer registers. A serial number that never changes, and a clock you can approximate with another unit off the same production line.

On Mk3 devices running firmware 4.0.1 through 5.0.3, effective entropy came out around 40 bits. A twelve word BIP-39 seed is supposed to carry 128. Mk4, Mk5, and Q landed closer to 72, which is better in the way that falling off a third story balcony is better than falling off a cliff.

Forty bits is a speed bump not a cryptographic barrier. You generate candidate seeds, derive the addresses, and check them against the public blockchain until something matches. The attacker didn’t need the device, the owner, didn’t need to send a phishing email or compromise a laptop. The chain told them they’d won the lottery with only a quarter of a ticket.

Three waves and counting

The first sweep hit on July 31: roughly 594 BTC out of about 500 single sig wallets in less than half an hour. Every drained wallet held more than 0.15 BTC and the coins spanned 2021 through 2026, which lines up with the firmware window exactly.

Galaxy Research revised that number twice in the next twenty four hours. A second wave brought the tally to 1,158 BTC across 2,673 addresses. A third wave announced August 1 put it at 1,367.05 BTC across 4,585 addresses; roughly $88.6 million.

None of it has moved. Every satoshi is sitting unspent in attacker controlled addresses. Galaxy’s Alex Thorn described the sweep as possibly LLM orchestrated and said the quiet part out loud: every vulnerable single sig address will eventually get drained.

The people who didn’t lose anything

Plenty of Coldcard owners came through this untouched. The clean list:

  1. Seeds generated before the vulnerable firmware shipped
  2. Seeds built with at least 50 fair, independent, private dice rolls, where the user’s own entropy dominates the device’s
  3. Seeds protected by a strong, unique BIP-39 passphrase aka 25th word
  4. Multisig setups where at least one key came from a device that wasn’t affected
  5. TAPSIGNER, OPENDIME, and SATSCARD, which run on a different codebase entirely

That list comes with the manufacturer’s own asterisks and you should take them seriously. Coinkite says a strong passphrase leaves you at minimal risk but still recommends migrating, and a short, reused, patterned, or quoted passphrase protects nothing. The dice exception only holds if the rolls were fair, independent, private, and you actually remember how many you entered; if you’re guessing, you’re not on the list. Even the firmware boundary is contested: Coinkite’s advisory starts Mk3 risk at 4.0.1 while Block’s analysis traces the regression back to 4.0.0.

If any of that describes you, migrate anyway. “Probably fine” is a bad place to store money you can’t replace.

The survivors did something the manufacturer treated as optional. Dice rolls are a power-user ritual. Passphrases are a checkbox most people skip because losing one means losing everything. Multisig is a headache you take on when the balance gets big enough to justify the headache.

The users who got wiped out are the ones who trusted the defaults, the ones who trusted Coinkite. Goodman’s seven minute loss is what that trust cost him.

The clock nobody thought about

Coinkite’s responsible disclosure policy is public, and it reads like every other vendor policy on the internet. Researchers are asked to give a “reasonable amount of time” before publishing. Keep the report private until a disclosure date has been coordinated. And notably the policy publishes no fixed first response deadline and no fixed remediation deadline; the disclosure date gets chosen after Coinkite understands the impact and the fix path.

That’s not unusual. It’s also not neutral. Every clause in the policy assumes the vendor holds the timer. Somebody finds a flaw, emails security@coinkite.com, waits politely, and Coinkite decides when the world hears about it. The entire framework is built around one scenario: the good guys get there first.

But this time they didn’t. The bug went public because money started moving. Coinkite has said it had no idea the flaw existed until the day of the sweep, which is a remarkable admission about five year old code that has been publicly readable the entire time. Block’s Bitcoin engineering team and Coinkite both pushed out their analysis before finishing empirical testing, specifically because exploitation was already live. That’s the correct call under the circumstances. It’s also an admission that the coordinated disclosure timeline had already been taken away from them.

Rodolfo Novak “NVK” apologized publicly on July 31, said Coinkite took full accountability for the firmware bug, and acknowledged the internal review had missed it. “I’m sorry and I’m devastated.” An apology costs nothing and moves no incentive. The thing that would move an incentive is a disclosure policy that doesn’t quietly optimize for the vendor’s preferred news cycle: and he’s oddly not proposed one of those as of yet.

The convenient explanation

Coinkite floated a theory alongside the apology: because the firmware has been public for years, someone may have used AI to comb through old versions and surface the weak randomness path. Novak framed it as a warning to other developers about the new paradigm.

That could be what happened but there’s not really proof either way, but it’s a plausible read of how a five year old flaw in public code suddenly gets found by a stranger in 2026.

It’s also the most flattering possible story for Coinkite. In that version nobody at the company failed: the tooling changed underneath everyone at once, and Coldcard just happened to be standing there when the world turned.

Except the same writeup carries a second admission, and it’s the one worth sitting with. Coinkite had recently run AI over their own code. It missed this entirely.

So both sides had the tool. Only one side found the bug. A vendor running a review pass has a checklist, a release date, and a strong prior that the code is fine. An attacker grinding through five years of public firmware has $88 million of reasons to keep going after the first pass comes back clean. Same technology, different motivation, and the motivation is what produced the result.

An alternative version is duller and harder for NVK to say publicly: the code was open the whole time and the flaw was reachable by anyone who read it carefully. The only thing that changed is that somebody finally bothered.

Both can be true. But when a company reaches first for the explanation that redistributes blame from its review process to the march of technology that’s reaching and it’s worth noting the lack of real accountability.

What’s left to do

The emergency firmware is out for every affected model: Mk2 and Mk3 to 4.2.0, Mk4 and Mk5 to 5.6.0 or later, Q to 1.5.0Q or later. Installing it doesn’t repair a seed that was already generated badly. If your seed came off a vulnerable device, restoring that seed anywhere carries the weakness with it. You need a new seed on patched firmware, preferably a totally different piece of hardware. Make a test transaction first, and then move everything over.

Do that today if it applies to you, because the attacker has no deadline and you do.


Fact check me bro

  1. Coldcard is built by Coinkite, a Canadian hardware wallet manufacturer. [VERIFIED]
  2. The flaw traces to a March 2021 firmware change during migration to Bitcoin Core’s libsecp256k1 library. [VERIFIED, Block Engineering + Coinkite backgrounder]
  3. Production config set MICROPY_HW_ENABLE_RNG to zero, intending a separate hardware RNG wrapper. [VERIFIED, Block Engineering Blog]
  4. The libngu library checked whether the macro was defined, not whether it was enabled. [VERIFIED, Block Engineering Blog] ⚠️ Coinkite’s own backgrounder describes the same failure as two functions sharing a name, allowing the wrong one to be silently selected. Compatible framings, not identical. Post currently uses Block’s version.
  5. Seed generation fell back to MicroPython’s non-cryptographic PRNG (Yasmarang). [VERIFIED, Block Engineering Blog]
  6. Fallback was seeded from the device’s unique ID and timer registers, and collected no fresh entropy after initialization. [VERIFIED, TheHackerNews citing Block]
  7. Effective entropy on Mk3 (firmware 4.0.1 through 5.0.3) around 40 bits. [VERIFIED, Coinkite backgrounder + coldcardentropy.org]
  8. Mk4, Mk5, Q around 72 bits, against 128 for a 12-word BIP-39 seed; extra entropy came from the SE1/SE2 secure elements. [VERIFIED, Coinkite backgrounder]
  9. Attacker can reproduce candidate seeds offline and check derived addresses against public chain data; no device access required. [VERIFIED, Block Engineering Blog, TheHackerNews]
  10. Wave one: 594 BTC ($38M) from ~500 single-sig wallets in under 30 minutes. [VERIFIED, CoinDesk]
  11. CoinDesk gives the wave-one window as 01:31 to 01:56 UTC. [VERIFIED, CoinDesk] Sources split between July 30 and July 31; pick one and footnote it.
  12. Every drained wallet in wave one was single-signature and held more than 0.15 BTC; coins spanned 2021 to 2026. [VERIFIED, CoinDesk]
  13. Wave two: 1,158.66 to 1,158.81 BTC across 2,673 addresses. [VERIFIED, Galaxy Research via CryptoTimes]
  14. Wave three (Aug 1): 1,367.05 BTC (~$88.6M) across 4,585 addresses. [VERIFIED, Galaxy Research via CryptoTimes / Decrypt / AMBCrypto]
  15. Stolen funds remain entirely unspent in attacker-controlled addresses. [VERIFIED, AMBCrypto, Galaxy Research]
  16. Alex Thorn (Galaxy) described the sweeps as likely LLM-orchestrated and warned every vulnerable single-sig address will eventually be drained. [VERIFIED, Decrypt]
  17. Unaffected: pre-firmware-window seeds, 50+ dice rolls, unique BIP-39 passphrase, multisig with a non-vulnerable key, TAPSIGNER / OPENDIME / SATSCARD. [VERIFIED, Coinkite advisory]
  18. Coinkite recommends migrating even with a strong passphrase; a short, common, patterned, quoted, or reused passphrase may be guessable and does not qualify. [VERIFIED, Coinkite advisory + backgrounder]
  19. Dice exception requires at least 50 fair, independent, private rolls; 99+ contributes roughly 256 bits. If the count or privacy is uncertain, Coinkite says migrate. [VERIFIED, Coinkite advisory] Note: at least one secondary summary reports Coinkite advising certainty of 100 rolls. Coinkite’s own pages say 50 and 99. Use Coinkite’s numbers.
  20. Coinkite’s advisory starts Mk3 risk at 4.0.1; Block’s preliminary analysis traces the Mk2/Mk3 regression to 4.0.0. [VERIFIED, coldcardentropy.org documents both claims side by side]
  21. Coinkite’s disclosure policy asks for a “reasonable amount of time” before publication and coordinated disclosure dates. [VERIFIED, coinkite.com/responsible-disclosure]
  22. The policy publishes no fixed first-response or remediation deadline; disclosure date set after impact and fix path are understood. [VERIFIED, coldcard.com security page]
  23. Coinkite said it was unaware of the bug until the day of the sweep. [VERIFIED, TechTimes] Confirm original Coinkite wording before publishing.
  24. Coinkite and Block published analysis before completing full empirical testing because exploitation was already active. [VERIFIED, Block Engineering Blog, Cryptonomist]
  25. Novak apologized July 31, said Coinkite took full accountability, acknowledged internal review failure, and said “I’m sorry and I’m devastated.” [VERIFIED, Bitcoin.com, Cryptopolitan]
  26. Coinkite advanced the theory that someone may have used AI on old public firmware to find the flaw. [VERIFIED as a claim made; the claim itself is UNPROVEN]
  27. Coinkite acknowledged it had recently used AI to review its own code and that the review missed the issue entirely. [SOURCED to a TFTC thread summarizing Coinkite’s technical backgrounder] ⚠️ Highest-priority verification item in this list. Read the backgrounder directly and pull Coinkite’s exact wording before publishing, because this sentence is doing real work in the argument and it is currently one source deep.
  28. Firmware fixes do not repair existing seeds; affected users must generate a new seed and migrate. [VERIFIED, Coinkite backgrounder]
  29. Fixed firmware: Mk2/Mk3 to 4.2.0, Mk4/Mk5 to 5.6.0+, Q to 1.5.0Q+. Edge track: 6.6.0X for Mk4/Mk5 and 6.6.0QX for Q. [VERIFIED, Coinkite backgrounder] Edge versions omitted from the post body; add if the audience skews technical.
  30. Jonathan Goodman said 18.25 BTC (~$1.6M CAD) was swept in seven minutes on July 29 from a device in a safety deposit box that never touched the internet. [VERIFIED, Decrypt quoting his X post] His July 29 date predates the widely reported wave-one date; verify or drop the date.