ColdCard Entropy IncidentSecurity write-up · nwfella
Status: ● Active threat
Updated Jul 31, 2026
⚠ Security Incident Analysis

ColdCard Entropy Incident —
the $38M RNG failure & how to remediate

In the early hours of July 30, 2026, ~594 BTC (~$38M) was swept from 500 single-signature wallets in about 25 minutes. Their keys were never leaked, their devices were never touched. The seeds themselves were born weak — a hardware-wallet random-number bug that shipped for over four years. This page explains exactly what happened, why it happened, and what every ColdCard owner needs to do.

Published: Jul 30–31, 2026 Last updated: Jul 31, 2026 Affected: ColdCard Mk2/Mk3/Mk4/Mk5 & Q Exploited: Yes — actively

01What happened — the 25-minute sweep

Between roughly 01:31 and 01:56 UTC on Thursday, July 30, 2026, an automated operation drained 500 separate single-signature Bitcoin addresses1,324 unspent outputs, approximately 594.48 BTC (~$38M) — across four consecutive blocks (960188 → 960191). The attacker then consolidated 562 BTC into a single address, where it still sat untouched as of this writing.

594.48
BTC swept (≈ $38M)
500
Wallets drained
1,324
UTXOs taken
~25 min
Total sweep window
0.044 BTC
≈ $2,800 in total fees
0
Multisig wallets touched

The fingerprint of the attack is the story:

Within hours, the community triangulated the cause: faulty entropy in wallet seed generation. Bitcoin Core developer instagibbs reproduced the vulnerability on a fresh Mk3 device and confirmed: "Mk2/3 vuln, I don't think mk4 is but can't be certain." By the end of July 30, Coinkite — the maker of ColdCard — had published a formal security advisory admitting the flaw was in its own firmware, in its own random-number handling. Total damage across the first 24 hours: ~1,000 BTC / $70M+ per industry reporting, as additional weak seeds were discovered and drained.

02Timeline of a four-year-old bug meeting reality

03Root cause — how a 40-bit seed got shipped for 4+ years

The mechanism is a small masterpiece of how huge disasters hide inside tiny mistakes. Here is the chain, in plain language.

The hardware TRNG that was never consulted

A Coldcard is supposed to generate your seed using a true hardware random number generator (TRNG) — a dedicated circuit in the STM32 chip producing genuine physical randomness. Coinkite wrote its own wrapper around that hardware, which is exactly the right practice. To avoid conflicts, the production build set a configuration flag, MICROPY_HW_ENABLE_RNG, to zero — telling the underlying MicroPython system: "don't use your built-in RNG, we have our own."

The off-by-one-thought bug

A separate library the firmware relies on — libNgU, added in the March 2021 migration to libsecp256k1 — needed to check whether that hardware RNG was available. It checked whether the flag was defined… not whether it was enabled. The flag was defined. Its value was zero, meaning "off" — but the check only asked "does this exist?" and the answer was yes. The build completed with no error and no warning, and quietly wired seed generation to MicroPython's software fallback instead of the hardware chip.

The exact guard

The relevant preprocessor guard used #ifndef — which tests whether MICROPY_HW_ENABLE_RNG is defined, not whether its value is nonzero. Coinkite defined the macro as zero, so the guard passed and the intended #error never fired. Seed generation resolved the rng_get() symbol to MicroPython's software fallback instead of Coinkite's board-specific TRNG.

What the fallback actually was

The software fallback is Yasmarang — a small, non-cryptographic pseudo-random generator, seeded from the chip's fixed factory serial number and a couple of timer registers. None of those are secrets. Feed a predictable input into a predictable algorithm and you get a predictable output that merely looks random. It passes the eye test. It fails reality.

~240
Effective entropy — Mk2/Mk3 (expected 2¹²⁸)
~272
Effective entropy — Mk4/Q/Mk5 (secure-element reseed)
2128
Intended for a 12-word seed
2256
Intended for a 24-word seed

On Mk3 hardware, Coinkite's own estimate puts the search space at ~2⁴⁰ (~1.1 trillion combinations). That number is comically small next to the 2¹²⁸ a 12-word seed is supposed to offer — small enough that a well-resourced attacker generates every possibility offline and checks each against funded addresses. On the current Mk4, Q and Mk5, a boot-time reseed pulls entropy from the secure elements (SE1/SE2), but the code keeps only 32 bits of it, capping the meaningful search space near 2³² (~4 billion) — around 2⁷² total once timing states are counted. Better. Still nowhere near the target. Coinkite calls this "a material improvement that still does not reach the target."

Why the open-source audits missed it

ColdCard's firmware is fully open source and has been reviewed — including by Coinkite itself. The reviews confirmed the correct hardware TRNG was present in the compiled binary, but never verified which of the two identically-named rng_get() functions the seed-generation path actually reached — the end-to-end symbol resolution and call reachability. The good code was in the building. It just wasn't the code that answered the door. Present is not the same as used.

NVK's own admission in the technical backgrounder is disarmingly honest: most of the randomness on the Coldcard was coming from a software PRNG "that I didn't know was actually in the source code base" (inherited from a MicroPython submodule), while the hand-built hardware TRNG "was still running, but just by chance, and only for less important things." Two functions shared the same name, and the wrong one quietly won.

The fix — the blind spot is now a build error

The hotfix does something almost poetic: the build now explicitly excludes MicroPython's fallback PRNG object and adds a compile-time RNG symbol check that fails unless the board-specific object defines the global rng_get() symbol and the upstream fallback object defines no symbols. The exact blind spot that let this ship for four years is now a build failure. The hotfixes add no new features — they just generate entropy correctly.

Same poisoned well

The weak generator did not only touch seeds. Coinkite confirmed it also affected paper-wallet keys, seed XOR masks, cloning & USB encryption, Key Teleport, Web2FA, and Secure Notes passwords — plus ephemeral keys for Clone/Key Teleport and BIP-85 seeds derived from a compromised seed. The rot ran deep because everything drank from the same well.

The AI angle

Coinkite says it has to assume the attacker used AI to comb through old versions of the open-source firmware and find the flaw. The gut-punch: the company ran one of the best available AI models over its own code weeks earlier, and it "did not find this bug or anything serious." Same tools, both sides of the fight. In NVK's words: "it did not help us, and only helped the bad guys." He warns every open-source developer: "If your firmware is open-source or has ever been public, assume it's already being read by attackers and defenders alike." Independent researchers (LLFOURN, Block, and others) have since published their own attack-cost models and analyses.

04Scope — what's affected, what isn't

The early headlines fixated on the Mk3, which is misleading. This is a Coldcard problem, not an Mk3 problem. Every current model generated weakened seeds too — the Mk3's near-deterministic worst case just happened to be what got hit first. Exposure depends on which firmware generated your seed, not the age of your device or its current firmware.

DeviceFirmware that generated the seedEffective entropyStatus
Mk34.0.1 → 4.1.9 (Mar 2021 → 4.2.0)~2⁴⁰ — near-deterministic for a known device/startup stateCRITICAL
Mk2v4 firmwareEssentially no real cryptographic entropy (Block analysis)CRITICAL
Mk4 / Mk5Before standard 5.6.0 or Edge 6.6.0X~2⁷² (32-bit secure-element reseed)SERIOUS
QBefore standard 1.5.0Q or Edge 6.6.0QX~2⁷²SERIOUS
Mk1Any— (predates the bug)CLEAR
Mk2/Mk3 on pre-4.0.0 firmwareAny seed made before v4.0.0Used the real hardware generatorCLEAR
Mk3 on 4.2.0+Seeds generated after updateCorrectedCLEAR
TAPSIGNER / OPENDIME / SATSCARDAnyDifferent codebases entirelyNOT AFFECTED
Block (Bitkey) / Trezor productsIndependent implementations; no Block products affectedCLEAR
Important correction

You'll see an "eight-year-old bug" figure in some coverage. That's the age of the vulnerable MicroPython fallback code (added upstream May 2018) — not how long Coldcard seed generation was affected. The regression entered in a single commit dated March 1, 2021, shipped in v4.0.0 on March 17, 2021, and the partial Mk4 reseed arrived in March 2022 without ever fixing the root cause. Affected seeds span a little over four years, not eight.

The dice & passphrase exceptions

The bug affects only the device-generated portion of the entropy. Two things you may have supplied yourself are unaffected:

A bad seed follows you everywhere

A seed created on an affected Coldcard stays weak even if you restore it onto a different brand of device — a Trezor, a Ledger, a new Coldcard. The weakness lives in the numbers, not the hardware. You cannot launder a bad seed by moving it. The fix is a genuinely new seed, not a migration of the old one.

05Are you affected? A five-minute checklist

  1. Did you generate the seed on a Coldcard after March 2021?

    If the seed was made on any Coldcard (Mk2/Mk3/Mk4/Mk5/Q) after March 2021, keep reading. If it was made on an Mk1, or on an Mk2/Mk3 running firmware before 4.0.0, or on a non-Coldcard device — you're clear on this specific issue.

  2. Check the firmware version that was installed at seed-creation time.

    On the device: AdvancedUpgradeShow Version. Exposure depends on the firmware in use when the seed was generated — not the device's age, not its current firmware.

  3. Did you add at least 50 independent, private dice rolls?

    50–98 rolls ≈ ≥128 bits from dice alone; 99+ ≈ 256 bits. Only counts if the rolls were fair, independent, private, and actually entered via Add Dice Rolls. If you're unsure how many, or whether they were private — treat the seed as affected.

  4. Is the wallet protected by a strong, unique BIP-39 passphrase?

    A genuinely strong passphrase (long, random, never reused, never stored digitally) is an independent barrier — minimal risk from this bug alone. A short, common, patterned, quoted or reused one is not protection. Still migrate when practical.

  5. Does the wallet still hold funds?

    Empty wallet or already migrated to a fresh seed elsewhere? You're done — the risk lives only in wallets still holding funds under a seed the broken firmware produced.

When in doubt, migrate

The single most dangerous phrase in self-custody right now is "I think I'm fine." The downside of a wrong "fine" is total loss; the cost of migrating is an afternoon of careful work. Coinkite, Block, Shinobi and the whole industry agree: if you can't prove the dice/passphrase exception, assume exposure.

06Remediation — step by step

First: calm

Coinkite's advice is the most important sentence in this whole affair: "Rushing a wallet migration can create a more immediate risk than the issue you are trying to address." Verify every backup, every address, every fingerprint. Send a small test transaction before you move the rest. A careful hour beats a panicked ten minutes.

Option A — fastest: move funds to a different hardware wallet

If you have (or can get) a hardware wallet that is not a Coldcard — Trezor, Bitkey, Foundation, etc. — send your funds there. This is the quickest, simplest way to get coins someplace secure. Caveat: the destination wallet must have a new seed generated on the new device. Restoring your old Coldcard seed into it does nothing but move the weakness.

Option B — interim: passphrase wallet on the existing device (temporary)

If you need breathing room before a full migration, a strong unique passphrase creates an entirely separate wallet that the attacker cannot compute from your weak seed alone:

  1. Generate a strong passphrase. Shinobi's guidance: at minimum six random words from the BIP-39 word list, chosen with a proper source of randomness — do not pick words yourself. Coinkite's official passphrase instructions are linked in the sources below.
  2. Set it on the device and verify. Enter the passphrase on the Coldcard, check the wallet fingerprint (or a receive address), power-cycle the device, re-enter the passphrase, and confirm the fingerprint matches. A typo'd passphrase silently creates a different wallet.
  3. Move funds to the passphrase wallet. Send your funds there. Keep the passphrase written down and stored separately from the seed words.
  4. Understand this is temporary. This buys you enough security to plan — it is not the destination. Continue to Option C (or A) for the permanent fix.

Option C — the proper fix: update firmware, generate a new seed, migrate

  1. Update the firmware first. Mk3 → 4.2.0+; Mk4/Mk5 → standard 5.6.0+ or Edge 6.6.0X+; Q → standard 1.5.0Q+ or Edge 6.6.0QX+. (Full procedure in section 07.) Remember: standard and Edge are separate release tracks — do not assume an older Edge 6.x release is fixed just because its number is higher than the standard release.
  2. Do not generate any new seed until the fixed firmware is confirmed installed.
  3. Generate a completely new seed on the updated device. The fixed firmware's device-generated seed is sufficient — dice are optional now. If you use a passphrase, back it up exactly and store it separately.
  4. Record and verify the new backup. Write the words down, re-verify them on-device, and record the wallet fingerprint (XFP). Power-cycle and confirm the fingerprint is stable.
  5. Verify a receive address on the device's own screen. Never trust an address shown only on your computer.
  6. Send a small test transaction to the new wallet and confirm it arrives. Even better: test sending from the new wallet too, so you know the seed works in both directions.
  7. Only then move the remaining funds. Sweep the old wallet(s) to the new address(es).
  8. Keep the old backup until the migration is fully confirmed — the complete balance arrived and is confirmed. Then destroy it carefully (shred paper, and understand steel backups can only be physically destroyed).
One-device Mk3 migration

If the affected Mk3 is your only device, firmware 4.2.0 lets it generate a replacement seed correctly — you don't need newer hardware. But you must carefully alternate between the old and new seeds on one device: verify the old seed's written backup and fingerprint → install 4.2.0 → generate the new seed, record and verify it → restore the old seed and send a small test to the new address → restore the new seed and confirm receipt → restore the old seed and move the rest → restore the new seed and confirm. If a second device with fixed firmware is available, use it instead — it's far less error-prone.

Option D — advanced: dice-only seed (zero device RNG trust)

For those who want a replacement seed that never touches the device's random-number generator at all — after updating to 4.2.0, use Import ExistingDice Rolls and enter at least 99 rolls of a fair six-sided die. This dedicated dice-only path hashes the roll sequence directly; it does not use the device's generator. This is explicitly an advanced procedure:

Special case — multisig with affected Coldcards (Peter Todd's warning)

No multisig wallet was drained in the sweep — but that's not a free pass. Core contributor Peter Todd flagged a specific edge case: a 2-of-3 with two affected Coldcards and a third uncompromised device. The moment you move funds, your script is revealed for the first time (it was previously hidden behind the address hash) — and the attacker now knows enough to race you using the two compromised keys. If you haven't reused addresses, MARA mining pool's private-mempool service (Slipstream) can mine your transaction privately, keeping pubkeys secret until they're in a block. If you've already reused addresses, just move funds ASAP — and afterwards, rebuild the wallet with healthy keys.

What does NOT protect you

07Upgrading firmware — and verifying it

Official upgrade path, from Coinkite's docs (last updated July 31, 2026 — the day the hotfixes shipped):

What you'll need

The procedure

  1. Check your current version. Power on, enter PIN, then AdvancedUpgradeShow Version. Compare against the latest on coldcard.com/docs/upgrade.
  2. Download the correct firmware. The 20xx-…-coldcard.dfu file for your model and release track (standard vs. Edge), from the official downloads page only. Mk3: 4.2.0 · Mk4/Mk5: 5.6.0 (std) / 6.6.0X (Edge) · Q: 1.5.0Q (std) / 6.6.0QX (Edge).
  3. Verify the hash (strongly recommended). Compare the SHA-256 of the downloaded file against the value in the official signatures.txt next to your version. Windows: certutil -hashfile <file>.dfu SHA256 · macOS: shasum -a256 <file>.dfu · Linux: sha256sum <file>.dfu.
  4. Verify the PGP signature (strongly recommended). Coinkite signs signatures.txt with key 4589779ADFC14F3327534EA8A3A31BAD5A2A5B10 (Peter D. Gray / DocHex). On Windows, use Kleopatra (Gpg4win); expect "Good signature from…". The "key is not certified with a trusted signature" warning is normal.
  5. Load it. Copy the file to the microSD, eject, insert into the unlocked Coldcard: AdvancedUpgradeFrom MicroSD, select the file. The red LED lights during install — do not power off during the upgrade (interrupting an Mk4 upgrade puts it into recovery mode).
  6. Confirm. After reboot, enter your PIN prefix, verify the two hardware-specific words shown, complete the PIN, and watch for the green GENUINE LED. Re-check Show Version.
  7. Red LED still lit after restart? Bless the firmware: AdvancedUpgradeBless Firmware. That confirms to the device that you approve the change.
Then, and only then

With fixed firmware confirmed, go back to section 06, Option C: generate the new seed, verify, test, migrate. Firmware update ≠ remediation. It's step one of it.

08Hardening — never rely on one vendor's randomness again

This is not Coldcard's unique curse. Milk Sad (2023) exposed wallets built with a tool that used a timestamp as its only entropy. Randstorm exposed millions of browser wallets from 2011–2015. Ill Bloom — disclosed just three weeks before this incident — hit five separate wallet implementations with weak seed generation. Different vendors, same failure mode, again and again. Harden in ways that don't depend on any one company getting it perfect:

09The stolen coins & the ongoing investigation

There is a strange, quiet coda to all of this. As of July 31, the stolen 594 BTC has not moved: ~562 sit in the consolidation address, ~32 on an intermediate hop, and not a single satoshi has gone to an exchange or mixer. The attacker is sitting on $38M in the open — and the next time those coins twitch will be the first real clue to who holds them.

10Sources & further reading

Primary sources first. Verify everything yourself before acting — that's the whole lesson.