Full incident report · 16 sources · Anzen Lab

Four lines of code.
1,596+ BTC gone.

In March 2021 a COLDCARD firmware build stopped asking its hardware chip for random numbers and had ordinary software work them out instead. Nobody caught it for five years. In July 2026 attackers did the arithmetic and started emptying the wallets.

What the setting cost
5 years
the flaw sat in fully public code, unnoticed1
1,596+ BTC
confirmed stolen from about 7,300 addresses, and still rising7
41 min
the largest single sweep: 1,083 BTC, around $70 million at the time9
1 in a trillion
the odds an attacker had to beat on a Mk3. The design called for one chance in a number with 78 digits1
What went wrong

A safety check that was there, and did nothing

01

Everything else assumes this one number

A hardware wallet does several jobs. It shows you what you are actually signing instead of asking you to trust the screen of an infected computer, and it keeps your key inside a chip built to resist being opened. Every one of those defences assumes the number your key came from could not have been guessed. If it could, an attacker never has to get past any of them. The pool a 24-word phrase is drawn from holds roughly one number for every thousand atoms in the observable universe. A pool that size cannot be searched. That is the whole security model.

Technical detail

12 words carry 128 bits of entropy, 24 carry 256, plus a checksum from the SHA-256 of that entropy. BIP-39 stretches the result into the BIP-32 master key.

Technical detail

12 words carry 128 bits of entropy, 24 carry 256, plus a checksum from the SHA-256 of that entropy. BIP-39 stretches the result into the BIP-32 master key.

02

COLDCARD stopped drawing from that pool

A 2021 firmware change quietly stopped the wallet asking its dedicated randomness chip for that number, and had ordinary software calculate one instead. Side by side, this is the entire incident:

That is not security cut by two thirds. Each bit doubles the work, so 88 fewer bits shrinks the job by a factor of 2⁸⁸. A trillion is a large number to a person and a small one to somebody renting high-performance machines to work through it.

Technical detail

Seed generation moved from ckcc.rng_bytes() to ngu.random.bytes(). Coinkite estimates about 40 bits of remaining search space on Mk3 and about 72 on Mk4/Mk5/Q, against a 128-bit target. Independent analysis by Block reaches the same order (under 2⁴⁰·⁷ and under 2⁷³·³) and finds narrower conditions where far less is left.2

Technical detail

Seed generation moved from ckcc.rng_bytes() to ngu.random.bytes(). Coinkite estimates about 40 bits of remaining search space on Mk3 and about 72 on Mk4/Mk5/Q, against a 128-bit target. Independent analysis by Block reaches the same order (under 2⁴⁰·⁷ and under 2⁷³·³) and finds narrower conditions where far less is left.2

What 24 words should be drawn from
115,792,089,237,316,195,423,570,985,008,687,907,853,269,984,665,640,564,039,457,584,007,913,129,639,936
What COLDCARD actually drew from
1,099,511,627,776
03

Because software cannot be random

Think about what makes a coin toss unpredictable. The force of the throw, gravity, a draught from an air conditioner, faint tremors in the ground. Dozens of influences you can name and dozens you cannot. Nobody can compute the trajectory, so nobody can call the result. Software works differently. It runs a fixed formula over a handful of starting values and produces a fixed answer. Here those values were the chip's serial number and how long the device had been powered on. An attacker who learns the recipe and the ingredients recomputes the output instead of guessing it.

Technical detail

With the hardware RNG disabled, rng_get() linked to MicroPython's Yasmarang PRNG, seeded from non-secret state (UID, SysTick, RTC) and it gathered no fresh entropy after that, so candidates enumerate offline. Coinkite does not consider seeds mixed with 50 or more fair, private rolls at risk from this issue alone: 50 × log₂6 ≈ 129 bits.3

Technical detail

With the hardware RNG disabled, rng_get() linked to MicroPython's Yasmarang PRNG, seeded from non-secret state (UID, SysTick, RTC) and it gathered no fresh entropy after that, so candidates enumerate offline. Coinkite does not consider seeds mixed with 50 or more fair, private rolls at risk from this issue alone: 50 × log₂6 ≈ 129 bits.3

04

And the check meant to stop it asked the wrong question

There was a guard in the build, written specifically to stop firmware shipping without the hardware generator. It asked whether a setting existed, not whether the setting was switched on. The setting existed, and it was off. The guard stayed quiet, the build reported no errors, and the firmware shipped.

Technical detail

#ifndef only tests definedness. The board config defined MICROPY_HW_ENABLE_RNG as 0, defined and disabled, so the #error never triggered and the linker resolved rng_get() to the software fallback.3

Technical detail

#ifndef only tests definedness. The board config defined MICROPY_HW_ENABLE_RNG as 0, defined and disabled, so the #error never triggered and the linker resolved rng_get() to the software fallback.3

The defect, quoted from the source.3

05

Nothing about it looked wrong for five years

A weak recovery phrase looks exactly like a strong one. Twenty-four ordinary words, the right checksum, a device that behaves normally. Nothing warns you on screen and nothing errors in the build. The source was public the whole time. Reading it still required somebody to open that particular file.

Technical detail

Output length, non-zero-ness and non-repetition all pass on a weak PRNG, so the usual smoke tests could not have caught it either.

Technical detail

Output length, non-zero-ness and non-repetition all pass on a weak PRNG, so the usual smoke tests could not have caught it either.

06

Then somebody did the arithmetic

They never touched a single device. They generated the likely phrases on their own machines, worked out which Bitcoin addresses each one would produce, and checked those addresses against the public blockchain. Every address holding a balance was emptied. A wallet that had sat unplugged in a drawer since 2022 was exactly as exposed as one in daily use.

Technical detail

Candidates derive offline through BIP-39/BIP-32; only the final balance lookup touches the network, so there is no signal on the victim's side beforehand.3

Technical detail

Candidates derive offline through BIP-39/BIP-32; only the final balance lookup touches the network, so there is no signal on the victim's side beforehand.3

This page is not a victory lap.

Coinkite disclosed the flaw, published a technical report and shipped a fix. Outside researchers could reconstruct what happened because COLDCARD is open source.

One caution on the estimates: they describe how much guessing an attacker faces under current assumptions, not a stopwatch. Nobody can tell you how long any particular wallet would take to crack.2

If you own a COLDCARD

Read this before anything else

What you need to do depends on which device you were using when the recovery phrase was first created, not which one you hold today.

Assume this is still happening. The phrases were made guessable in 2021 and the method is now public, so anyone can run the same search. There is no patch that closes it from the outside, and no reason for an attacker to stop. If you are affected, the safe assumption is that time is the only thing between you and them.

Mk2 and Mk3: move your coins now

The affected range is firmware 4.0.1 through 4.1.9. Version 4.2.0 fixes how new phrases are made, but no update can go back and add randomness to a phrase that already exists. Create a new wallet on a device you trust and move your funds across.1

Mk4 and Mk5: check the firmware version

If the phrase was created on firmware older than 5.6.0 (or 6.6.0X on Edge builds), update, create a brand-new wallet on the updated firmware, then move your funds. Updating on its own does not repair the old phrase.1

Q: same, the cutoff is 1.5.0Q

Update to 1.5.0Q or later, or 6.6.0QX on Edge builds, create a new wallet, write down and test the backup, send one small test transaction, then move the rest.1

Does updating COLDCARD firmware fix a recovery phrase I already have?

How do I find out which firmware created my COLDCARD recovery phrase?

How do I check whether my address was caught up in this?

Do dice rolls or a passphrase protect a COLDCARD recovery phrase?

Does Coinkite’s advisory cover every affected COLDCARD?

Coinkite's official technical noticeMove to a fresh wallet on a device you already trust, and send one small test transaction before migrating everything. Keep the public evidence (transaction IDs, addresses, timestamps) and never a secret. Anyone offering to recover your funds is a second theft in progress, and no such service exists. What hardware to buy next can wait until your coins are safe.
And if you own a OneKey

No OneKey device is affected

Not one model we have ever shipped. Our firmware carries no libngu, Coinkite, COLDCARD or CKCC dependency, so the code path that failed is not there to be reached, and you can check that yourself in our repositories. On our current hardware the key comes from the true random generator inside a certified secure element, never from software on the main processor. That substitution is what this failure was.

Not affected
OneKey Pro
OneKey Classic 1S
OneKey Classic 1S Pure
OneKey Touch
OneKey Classic
OneKey Mini

We did not take that on trust either. When the news broke, Anzen Lab traced our randomness end to end (where it comes from, what calls it, and the build settings that decide which version reaches your device) and published the exact files they checked.12

Read Anzen Lab's re-check
The question you're actually asking

Could this have happened to a OneKey?

This failure needed three separate things to be true at once. On a OneKey none of them is true, and you can check all three yourself.

Where ours comes from

So where does OneKey's randomness come from?

Made inside an EAL 6+ certified chip

Your keys are created and kept inside a dedicated, tamper-resistant chip rather than the general-purpose processor that runs everything else. EAL 6+ is the assurance grade used for payment and identity cards.

Randomness that watches itself

That chip generates randomness from real physical noise, and continuously tests its own output. If the randomness ever starts misbehaving, the chip notices instead of quietly carrying on.

We went and re-checked ours

After the COLDCARD news, Anzen Lab traced our own randomness the whole way through (where it comes from, what actually calls it, and the build settings that decide which version ends up on your device) and published the exact files they looked at.11

OneKey Pro's EAL 6+ certified secure element
EAL 6+ Badge
Each transaction, secured by EAL 6+ certified chips
Where the randomness is made
Secure element
THD89
Assurance level
EAL 6+ certified
Entropy source
Hardware TRNG, self-testing
Output certified against
BSI AIS 20 / 31
Re-audited after this incident
Anzen Lab, source published
How OneKey is built, and who checks it

Four checks on every OneKey, and none of them trusts the other three

Any one of these can miss something. The point is that all four would have to miss the same thing. COLDCARD had no such backstop: one unchecked build setting was enough.

01

Open source you can actually verify

Our firmware and apps are public on GitHub, and our builds are reproducible, which means you can rebuild the code yourself and confirm it produces exactly the software running on your device. That is the step that catches a "right code, wrong version" problem.

OneKey on GitHub
02
SlowMist

Outsiders check us, on the record

The security firm SlowMist audits us and publishes the reports. Separate assessments cover OneKey Pro, the Classic 1S and our SDK. Our security practices are certified to ISO/IEC 27001, and the Pro and Classic 1S line are certified against EN 18031 by an EU-appointed body. All of it published, none of it self-assessed.13

Read the SlowMist audit summary
03

A team paid to break our own products

Anzen Lab is our in-house security team of hardware, firmware and application security engineers, working with a rotating set of outside researchers. Their job is to break hardware wallets, ours included, before anything ships. When this story broke they re-examined OneKey’s own randomness end to end and published exactly which files they checked.11

Read the Anzen Lab analysis
04

We pay strangers to find our mistakes

Anyone can report a flaw to us privately, through our public program on BugRap or straight to [email protected], and get paid for it. Severity decides the payout, scored on CVSS. The whole point is to make telling us more attractive than selling it.15

OneKey on BugRap
entro.tools · Built by our founder

Test the wallet in your hand

entro.tools is a free, open-source tool that reads the actual random numbers coming out of a hardware wallet and runs the standard statistical health tests on them, in your browser, over USB, with nothing uploaded anywhere and no firmware update required.

It works on Trezor and KeepKey as well as on our own devices, so you can compare them side by side instead of trusting any single vendor's claim.
How it runs
In your browser, over WebUSB
Tests applied
FIPS 140-2, NIST SP 800-22 / 90B
Your data
Never leaves the page
Firmware update
Not required
Entropy Check

Runs FIPS 140-2, NIST SP 800-22 and SP 800-90B health tests locally over WebUSB (desktop Chrome or Edge). The device asks to export entropy, a batch of random numbers it just generated, never your recovery phrase.16

Maurer's universal statistical test needs at least 387,840 bits, and below that the report marks it skipped rather than quietly leaving it out.16

Which wallets can be checked

Whether an outsider can read a device's raw random numbers at all. This is one narrow dimension. See the note below it.

OneKey
Verifiable yourself
All models, stock firmware16
Trezor
Verifiable yourself
All models, shared wire protocol16
KeepKey
Verifiable yourself
Trezor wire-protocol family16
Ledger
Trust the vendor
Closed secure element; no host command exposes raw random numbers16
BitBox02
Trust the vendor
The protocol's random-number request was removed by the vendor16
Blockstream Jade
Trust the vendor
Host can only add entropy; there is no way to read the source back16
COLDCARD
Trust the vendor
Has USB, but its protocol contains no entropy command at all16
Keystone
Trust the vendor
Air-gapped by design; USB carries only device info and firmware updates16
"Can't be tested" and "insecure" are different claims. Closed secure elements follow their own certification path. A passing result proves only that no statistical defect shows up today. It cannot prove cryptographic unpredictability, and it says nothing about the randomness used the day your wallet was created.
Still wondering

Questions this raises for everyone else

Is OneKey affected by the COLDCARD entropy failure?

Which hardware wallets does the COLDCARD entropy failure affect?

Can I test my own wallet’s randomness?

How do I judge whether a hardware wallet can be trusted?

Security you can check, not security you're asked to believe.

Open source and reproducible, audited by outsiders, attacked by our own lab, and paid for when somebody finds a hole. These are the devices that argument is about.

References

Sources below, retrieved August 6, 2026. Coinkite's own advisory and technical report come first, then independent source-level analysis and on-chain accounting. Loss figures are still being revised upward: Galaxy Research confirmed 1,596 BTC on August 4 and put suspected losses nearer 2,055 BTC.