Inside the Coldcard Flaw: What Went Wrong, and Why a Weak Seed Cannot Be Patched

AnalysisBlock · 960,7589 min read

This is analysis. It interprets events and their context, and it is not financial advice.

The reporting on the Coldcard theft, covered in our companion news report, answers what happened. This piece answers the harder question of why, and what the answer changes about how anyone should read a hardware wallet's security promise.

The short version is uncomfortable in how ordinary it is. Nothing in Bitcoin broke. No elliptic curve was solved, no secure element was cracked, no attacker touched a physical device. A single build setting quietly sent one of the most sensitive operations a wallet performs through the wrong piece of code, and it stayed there for years.

Start with what a seed actually is

When a Bitcoin wallet is created, it draws a very large random number. Every private key, address and signature the wallet will ever produce descends from that one number, called the seed. The security of the whole wallet rests on a single property of that number: that nobody else could have guessed it.

The measure of how hard a number is to guess is called entropy, counted in bits. A twelve word seed is meant to carry 128 bits of entropy. That number is not marketing. It describes a space of possible seeds so large that searching it is not merely expensive, it is physically out of reach, closer to counting atoms than to running a computer program.

This is the entire reason a hardware wallet exists. Its core job, above the screen and the airgap and the secure chip, is to pick that number from the full, unsearchable space. If it picks from a smaller space, everything built on top inherits the weakness, and none of the other features can compensate.

The bug: one setting, wrong branch

Coinkite designed the Coldcard to use a hardware random number generator, a physical source of noise on the chip. In 2021 the company moved its Bitcoin cryptography onto Bitcoin Core's libsecp256k1 library, a sound choice used by Bitcoin Core itself. That migration introduced a supporting library, libngu, and rerouted seed generation from the old hardware path to a new call, ngu.random.bytes().

Here the wiring went wrong. To decide which random source to compile in, the code checked a setting named MICROPY_HW_ENABLE_RNG. Coinkite had set that value to zero, intending to disable MicroPython's built in generator and use its own. The check used a form that tests only whether the setting exists, not whether it is switched on. Because the setting existed, even set to zero, the build silently bound seed generation to MicroPython's software fallback instead of the hardware source.

That fallback is a pseudo random generator, a formula that produces random looking output from a starting value. On the Mk2 and Mk3, that starting value came mostly from the chip's unique identifier and its timer registers. Those inputs look random but are fixed or narrowly bounded, which is why Coinkite now estimates the effective search space at about 40 bits rather than 128.

For an attacker, 40 bits is not a wall, it is a to do list. The space is small enough to walk through with ordinary computing power, deriving candidate seeds, checking each against known addresses, and keeping the ones that hold funds. A public address or extended public key tells the attacker instantly whether a guess was correct, which is exactly why weak entropy in a wallet is so much more dangerous than weak entropy in most other software.

Why the newer models were hurt too, just less

During Mk4 development Coinkite mixed extra randomness from two secure elements into the generator's state, as a backup to a backup. That is why the Mk4, Mk5 and Q are less exposed than the Mk3. It is also why they are not safe.

By Block's analysis, the reseed replaced only a 32 bit word of the generator's internal state, so for a fixed fallback state and call history the device produced at most about four billion distinguishable output streams. Coinkite puts the resulting search space at roughly 72 bits. Better than 40, still far below the 128 bit target, and still inside reach for a motivated attacker. The extra entropy raised the wall without ever closing the gap.

Why years of review missed it

The detail that should stay with anyone building or trusting these devices is how quiet the failure was. Both the correct hardware generator and the wrong software fallback had the same function signature, so the build completed without complaint. Reviewers could confirm that the intended hardware code was present in the firmware binary, and be right, without noticing that the seed path never actually reached it.

The flaw was not a line of bad cryptography that a careful reader could spot. It was a question of which of two identical looking functions the linker connected, two layers down in a submodule. That is a genuinely hard thing to catch by reading code, and it is a caution against treating an audit as a single pass or fail stamp.

The licensing subplot, and how much weight it can bear

There is a second story around this bug, and it deserves to be told carefully rather than as a verdict. Foundation Devices chief executive Zach Herbert laid out a timeline. In July 2020, Foundation announced its Passport wallet, built on Coldcard firmware that was then under the GPLv3 free software license. Coinkite's founder objected publicly. Coinkite then moved to a more restrictive source available license, and in March 2021 shipped a large commit that removed the last GPL code.

That same roughly 120 file commit is where seed generation changed and the faulty random path entered. Herbert frames the bug as possible collateral damage of that rewrite.

Read as an author's interpretation, the timing is hard to ignore: the licensing dispute was the visible trigger for the rewrite, and the rewrite is where the flaw was born. The honest counter reading matters just as much. Coinkite has said the same migration pursued real technical goals, chiefly adopting Bitcoin Core's libsecp256k1, and there is no evidence that the license change alone caused the bug. A rewrite of that size can introduce a subtle fault for reasons that have nothing to do with why it was started. This reading would weaken considerably if it turned out that the specific broken check predated the March 2021 commit, or appeared in a change with no connection to the license work.

What the flaw actually costs the user

The most important consequence is also the least intuitive. A seed generated by affected firmware cannot be repaired.

Updating the firmware does not help, because the update only changes how future seeds are made. Reimporting the same seed into a new Coldcard, a BitBox or a Trezor does not help either, because the weakness is inside the seed itself and travels with it. Resetting the device and restoring the same words does nothing. The only path Coinkite describes is to generate a genuinely new seed on fixed firmware and move the funds to fresh addresses derived from it.

Two mitigations soften the picture without fixing it. Coinkite says a seed created with at least fifty independent, private dice rolls is not at risk from this issue alone, because the user supplied entropy the firmware could not undermine. And a strong, unique passphrase, the optional secret that combines with the seed words to produce a separate wallet, forces an attacker to guess that secret on top of the weak seed. Both buy safety or time. Neither restores the missing randomness, which is why the underlying seed still has to be replaced.

The narrative that took the real damage

For years, Coldcard was sold in part on being airgapped, meaning it never connects to a computer over USB and moves data through a MicroSD card or QR codes instead. In parts of the Bitcoin community that hardened into a simpler claim, that airgapped wallets are the secure choice and effectively unhackable.

This case is a clean demonstration of why that shorthand was always too strong. The airgap did its job. No data leaked over a cable, and the attacker never needed the device at all, because the weakness was baked into the seed at the moment of creation. A gap in the wiring is worth nothing when the number underneath was predictable from the start.

A wallet has to do many things well at once: generate a truly random seed, store keys securely, display transaction details honestly, verify its own updates, implement cryptography cleanly, resist physical attack, and protect its supply chain. "No USB" or "secure element" describes one property on that list, not the whole of it. There is even a small irony here, noted by Coinkite's own account: the airgap is part of why the device could not pull extra entropy from a connected host, a source some other designs lean on.

This is where a structural point earns its place, offered as reasoning rather than instruction. Designs that blend several independent entropy sources, so that one faulty component cannot decide the outcome alone, are more robust against exactly this class of single point failure. That is an argument about architecture, not about which product anyone should buy, and it is only as good as how cleanly those sources are combined in practice.

The part that will not go away

Two threads make this more than a fixed bug. Coinkite has said it assumes an attacker used an AI model to review its open firmware and surface the flaw, and that its own AI assisted review weeks earlier had missed it. The same tools now sit on both sides of the table. And the operator's use of a paid account at a blockchain data provider, which Block traced through the provider's own logs, is the kind of ordinary operational trail that a careful attacker would have avoided, and the strongest current lead for investigators.

The lasting lesson is not that one company failed a test. It is that the security of self custody is a chain that runs from the very first random number to the final line on the screen, and that a wallet deserves to be judged on the whole chain, not on the one word printed largest on the box.

Sources

  1. 1.Block Engineering: Predictable RNG Fallback and 32-Bit Reseed in Coldcard Firmware
  2. 2.Coinkite: Technical Deep Dive into the Entropy Issue
  3. 3.Zach Herbert (Foundation Devices) on the firmware and licensing timeline
  4. 4.CryptoSlate: A flaw in Coldcard seed generation lets attackers recreate private keys
  5. 5.Bitcoin Magazine: Coinkite releases fixed firmware after Coldcard bug; AI likely involved
  6. 6.CoinDesk: How bitcoin cold wallets lost $70 million in an attack that never touched the devices