On 30 July 2026, someone started emptying Coldcard wallets. The first wave took 1,196 of them in forty-one minutes. Reported losses now run between $88 million and $130 million.
Nobody was hacked. No device was stolen, no recovery phrase photographed, no server breached. The keys were simply guessed.
They could be guessed because of a programming mistake that shipped in March 2021 and sat there for five years. Instead of the dedicated randomness chip inside the device, affected Coldcards quietly used a much weaker source. That made the wallets they built roughly 72 quadrillion times easier to guess, and nobody noticed until someone started guessing.
One group was untouched. Anyone who had rolled at least fifty dice by hand was fine, because their own throws had supplied enough real randomness. The people who did the paranoid thing were the only ones who were safe.
Why nobody noticed for five years
Your wallet is one number. Every address you own and every key that spends your coins is calculated from it. The twelve or twenty-four words you wrote down are not separate from that number. They are that number, in a form a human can copy without typos. Those words are called your seed.
The number is 256 bits long, and a bit is one coin flip. So picture flipping a coin 256 times and writing down the result. That is your wallet, and your security rests on one question: can anyone else guess the flips?
To produce them, a device gathers something unpredictable: a noise chip, a camera, or dice you roll yourself. Then it puts whatever it gathered through a blender, called a hash function, which turns any input into a clean 256-bit result. The blender is where the trap lives.
It makes anything look random. Put in the word "banana" and out comes a 256-bit number with no visible pattern at all. It would pass every statistical randomness test ever written. It is also guessable in one try by anyone who thinks of the word "banana".
The rule worth remembering
Randomness tests measure what the result looks like. They cannot measure whether someone can predict it. Every affected Coldcard seed looked flawless.
This is not a fringe opinion. NIST, the American body whose standards most of the security industry works to, said so in its own guide to randomness testing in 2010: these tests cannot tell you a generator is safe. It is now rewriting that guide to discourage exactly that. One stricter standard does work, but only on the raw noise before the blender, which is the one thing a finished wallet never shows you.
So testing your own seed is a dead end. One question is left: can you reproduce the number yourself, from something you controlled and can check? I read the code of six wallets to find out who lets you.
What I found
Six things, taken from the firmware rather than the documentation, at a fixed version. None of it is an emergency, and every finding is rated at the bottom.
1. SeedSigner squeezes the randomness out of its own photo
SeedSigner can build a seed from a camera image: fifty quick preview frames plus one final full-resolution photo, mixed together. The fifty previews go in exactly as the sensor produced them. The final photo does not. It is saved as a JPEG first and then reopened, and JPEG works by discarding fine detail your eye will not miss. Fine detail is exactly where camera noise lives, and that noise is the whole reason for pointing a camera at anything. The code calls that photo "our headline entropy". It is the one ingredient wrung out before use.
Your seeds are fine. The fifty untouched frames go in first and carry the real randomness, and randomness already mixed in cannot be taken back out. The flaw is that the device is proud of the wrong ingredient.
2. The SeedSigner you can install today does not check its own camera
The next version insists on fifty genuinely different frames and refuses blank ones. Those checks were added on 8 August. The current release, 0.8.7, came out on 9 June. So on the version people actually run, a covered lens or a frozen camera still produces a seed, and nothing warns you.
Of everything here, this is the one I would most want fixed.
3. Jade mixes in five zeros and calls them sensor readings
Blockstream Jade stirs sensor readings into its randomness: battery voltage, USB current, temperature and three others. On current Jade v2 hardware, five of those six sensors are written like this:
uint16_t power_get_iusb(void) { return 0; }
uint16_t power_get_temp(void) { return 0; }
You do not need to read C. Both functions hand back the number zero, every single time, and zero is not randomness.
Blockstream's marketing describes mixing in button taps, dice rolls and ambient temperature. There is no button-tap code, no dice code at all, and temperature is that hard-coded zero. Jade is not broken, because its real randomness comes from elsewhere. But the layers of defence are thinner than they look.
4. Trezor checks only the wallets it throws away
Trezor built something genuinely clever. Before your computer sends its own randomness, the device must seal its answer in an envelope, so it cannot peek at yours and adjust. Your computer opens the envelope afterwards and checks the wallet was really built from what was inside. Then it repeats, a secret number of times between two and eight.
On the last round, the envelope is never opened. Every round that gets checked is a wallet that is then discarded, and the wallet you walk away with is the one nobody verified. That is deliberate, and the reasoning holds: a dishonest device cannot know which round is last, so it has to gamble and will probably get caught.
It makes cheating a losing bet. What it does not do is prove your seed is honest, which is how it usually gets described.
5. Krux grades your dice, and the grade can be fooled
Krux is the only device that scores your throws and warns you if they look wrong. The warnings can be clicked past, and they miss an obvious trick. Throw ten dice honestly, then copy that block five times to fill your fifty. You have supplied about 26 bits, roughly a short password. Krux reports 126 and says nothing.
Its own manual admits the score is not a guarantee. The risk sits in the gap between that manual and a green progress bar in front of you. Krux is also the only device that shows you its working, which is the best habit here.
6. OneKey never picked up the protection it inherited
OneKey's firmware is built from Trezor's. In January 2025 Trezor added the envelope scheme described above, so a device cannot cheat by reacting to your computer's randomness. OneKey forked in May 2022 and never took the update.
The evidence is one message definition, in the same file in both projects:
Trezor: message EntropyRequest {
optional bytes entropy_commitment = 1;
optional bytes prev_entropy = 2;
}
OneKey: message EntropyRequest {
}
Empty. Searching OneKey's entire codebase for that commitment field returns nothing at all.
This holds for every current OneKey device, in code dated June 2026. A wallet sold as the open-source alternative is missing the protection its upstream built for exactly this problem.
The part I got wrong, which is good news
I expected dice backups to be locked to whichever brand made them, so your written-down throws would be worthless on any other device. That is false.
Give any of them the same dice and you get the same words back
SeedSigner, Krux and Coldcard's dice mode do the identical thing with your throws. They hash the digits as plain text, with nothing added. I checked that rather than taking anyone's word for it, by reproducing the six test vectors those projects publish. All six came out right.
You can do the same, with a command that has shipped with Linux for decades:
printf '65515223131652132161133154444123616466443112153441' | sha256sum
Those fifty digits are fifty dice throws, and what comes back is the seed your wallet would build from them. Use printf rather than echo, because a stray line break changes the answer completely.
Then I checked Keystone, and it disagrees.
Keystone rewrites every 6 as a 0 before hashing. The other three hash the digits exactly as you tapped them. So the same fifty throws build two different wallets:
hashed as typed -> hole luggage safe present express tragic...
6 rewritten as 0 -> tip toward alcohol rule pave weird...
The same fifty dice throws, and nothing in either set of words tells you which convention produced it.
The widely used Ian Coleman browser tool sits in Keystone's camp, rewriting the 6 in its own source. So there are two conventions rather than one standard, and your device does not tell you which one it follows. Written-down throws only work on a wallet in the same camp.
That aside, this remains the most useful fact here. A dice-made seed can be checked on a laptop you already own, against nobody's word but arithmetic. On Coldcard, note it is the dice-only mode that works this way, not the newer default that mixes in device randomness.
What it adds up to
Several of these companies have built clever protections against a dishonest device faking your transactions. Almost none of it protects the seed, the one number everything else depends on.
The Coldcard failure is what that gap costs, once, in public, for north of $88 million. The cause was one line of code that checked whether a setting existed, instead of what it was set to.
You cannot test your way out of this. You can only decline to be the one who has to trust. Fifty dice and one command is the only method here that gets you there.
How serious is any of this?
Not very, and I would rather rate it than ask you to take my word for it.
| Finding | Severity |
|---|---|
| SeedSigner 0.8.7 does not check its camera | Low, the highest here. A covered lens is a plausible accident. Fixed in the next version. |
| OneKey is missing Trezor's entropy check | Low. No sign of anything wrong, but you are trusting OneKey with none of the checking its upstream provides. |
| Krux dice grading can be fooled | Low. You would have to fake your own throws. |
| SeedSigner's JPEG photo | Informational. Cannot weaken a seed, since randomness already mixed in cannot be removed. |
| Jade's five zeros | Informational. Zeros neither add nor subtract. |
| Trezor checks only discarded wallets | Informational. Deliberate, and sound. Just widely described wrongly. |
Nothing above Low is why I published straight away. Researchers normally sit on a finding for ninety days, to keep attackers away while a fix is built. Here there is no attack to withhold, no fix anyone is waiting on, and every line I quote already sits in a public repository. Holding it back would protect reputations, not people. I am notifying each project, and any reply will be added here.
I read BitBox02, Bitkey and Ledger too. BitBox02 and Bitkey had nothing worth reporting, which is worth saying out loud. Bitkey in particular fails safe: if its randomness source errors, the device halts rather than carrying on. Ledger could not be assessed at all, because the code that generates the seed has never been published.
One thing to declare: Bitsaga recommends SeedSigner, writes about it, and built a browser simulator for it. My sharpest finding is against SeedSigner, and I led with it, because a review that spares your own favourite is not a review.