A security failure is often described as if one part broke. The lock failed. The random number generator failed. The wallet failed.
That shorthand is convenient, but it hides the useful part. In the July 2026 COLDCARD entropy incident, the hardware random number generator was present. Coinkite says the intended design was to use that hardware TRNG for seed generation. Block's independent analysis reached the same basic shape: the strong component existed, but the wallet-generation path did not reach it.
That is a different kind of failure. It is not a warning that cryptography is fragile in some vague way. It is a warning that architecture diagrams, source comments, and reviewed components do not protect production systems unless the executed path is checked.
The Part Everyone Trusted Was Still There
The intended COLDCARD design was straightforward: when a wallet seed is created, draw randomness from the device hardware RNG and use that entropy as the basis for the BIP39 seed words. That is the part users reasonably thought they were buying. A hardware wallet is supposed to keep secret material offline, and seed generation is supposed to start with enough unpredictability that guessing is out of the question.
According to Coinkite's [technical deep dive](https://blog.coinkite.com/entropy-technical-backgrounder/), the relevant change arrived during a 2021 migration to libNgU and Bitcoin Core's libsecp256k1. Older seed generation had used ckcc.rng_bytes(). The changed path used ngu.random.bytes(). That looked like a normal internal refactor around cryptographic plumbing. The dangerous part was not the cryptographic library. It was where the random call resolved.
The board configuration defined MICROPY_HW_ENABLE_RNG as zero because COLDCARD had its own hardware RNG wrapper. But a libNgU guard checked whether the macro was defined, not whether it was enabled. The build passed. The symbol resolution then reached MicroPython's rng_get() fallback instead of the board-specific hardware RNG implementation.
Coinkite describes this as a build and link integration error, not an intentional weak fallback. That distinction matters. The lesson is not that someone deliberately chose weak randomness. The lesson is that the production call graph quietly disagreed with the intended design.
The strong part can be in the repo. It can be in the binary. It can be reviewed. If the startup path, link path, or runtime path lands somewhere else, the control is not in force.
A Random-Looking Output Is Not The Same As Entropy
The fallback generator was MicroPython's Yasmarang PRNG. A PRNG can produce bytes that look noisy to a casual observer. That does not make the bytes unpredictable.
Block's [analysis](https://engineering.block.xyz/blog/predictable-rng-fallback-and-32-bit-reseed-in-coldcard-firmware) says the MicroPython fallback was initialized from values such as the low part of the MCU UID and timer registers. Those values can vary, but they are not cryptographic entropy. A device UID is device metadata. Timers are timing state. They may create work for an attacker, but they are not equivalent to fresh randomness sampled from a hardware generator.
This is where a lot of incident summaries become too simple. It is not accurate to say every affected wallet had exactly a 2^32 keyspace. Coinkite currently estimates about 40 bits of effective search space for affected Mk2/Mk3 conditions and about 72 bits for Mk4, Mk5, and Q under its assumptions. Block, looking at the implementation path, describes Mk2/Mk3 v4 as deterministic when UID, timer state, and call history are fixed. It also describes a broad upper bound below 2^40.7 when hidden timer state is counted.
For later devices, Block identified a different limit: secure-element material was hashed, but only four bytes were fed into reseed(). For a fixed fallback state and call history, that leaves at most 2^32 securely distinguished output streams. Block also gives a loose combined ceiling below 2^73.3 when timer fields are counted, while warning that this is not the same thing as 73-bit cryptographic security. Practical recovery depends on fallback state, timers, device UID knowledge, RNG call history, derivation paths, and public validation data.
That precision is important. Security reviews get worse when teams compress every finding into one dramatic number. The real finding is more operational: the entropy budget depended on accidental state and narrow reseeding, not on the hardware RNG path people thought was feeding seed generation.
Hashing Could Not Put Randomness Back
The affected wallet-generation path still hashed output. That can make a value look uniform. It cannot create entropy that was not present in the input family.
If a process can produce only a small set of possible 32-byte values, hashing those values produces a small set of possible hashes. The outputs may be evenly distributed across the hash space, but there are still only as many candidates as there were inputs. BIP39 checksums have the same limitation. They can catch certain transcription errors. They do not make a weak seed strong.
This is a common failure mode outside wallets too. A system adds a checksum, a signature, a hash, a wrapper format, or an approval screen after a weak input and then treats the later artifact as proof that the earlier step was sound. It is not proof. It is packaging.
In software operations, the same mistake shows up with startup files, repo notes, deploy checks, and approval commands. A repo can have a correct deploy checklist while the actual deploy script skips it. A handoff note can say the service depends on one queue while the startup file points at another. A project rule can require an approval command, but the worker path can run without reading the rule. The written control matters only when the running path reaches it.
The Blockchain Made The Mistake Observable
Bitcoin added another property to the incident: public validation data.
Once someone can derive candidate keys, public addresses and transaction history become an oracle. A candidate seed can be tested by deriving addresses and comparing them to funded addresses on-chain. No wallet service has to be breached for that check. No victim has to type a seed phrase into a phishing site. The public ledger lets an attacker ask, candidate by candidate, whether a guessed key controls real money.
The visible sweep around the address [bc1qnk4zh9qcnap2mycp56qjrgza3cc8ylrh8fecp0](https://mempool.space/address/bc1qnk4zh9qcnap2mycp56qjrgza3cc8ylrh8fecp0) shows the operational shape. Mempool reported 502 transactions for that address, with total received of 594.47723261 BTC and a remaining confirmed balance of 32.45056320 BTC. The core sweep described by public incident researchers involved 500 transactions, 1,324 source UTXOs, and a narrow confirmation window on July 30, 2026 UTC. Many of the listed fee rates cluster around 30.14 to 30.21 sat/vB, which is consistent with coordinated construction rather than unrelated manual sends.
A later consolidation moved most of the collected funds onward. The public incident record at [coldcardentropy.org](https://coldcardentropy.org/) describes 341 inputs totaling 562.02666941 BTC producing a 562.01962301 BTC output to bc1qq85v2c926eg6pgxhwp6q7lf6cnsz80qs3fcu9r, while 159 initial outputs remained at the original collection address in that snapshot. A later dust event also appears in the address history at a much lower fee rate.
Those are blockchain observations. They do not prove real-world identity, common ownership, victim status, or that the entropy flaw caused every transfer. CoinDesk's [July 31 report](https://www.coindesk.com/tech/2026/07/31/major-bitcoin-wallet-flaw-drains-594-btc-in-25-minute-sweep) gives broader incident context around the initial 594 BTC sweep. The technical cause still has to be separated from the public movement of funds.
The careful statement is this: vulnerable key material, public validation data, and funded addresses are a dangerous combination. Once the candidate space is small enough, the chain can tell an attacker which guesses are worth spending.
The Operational Lesson
The obvious response to a wallet incident is to ask whether users should update firmware or migrate funds. For affected users, Coinkite's [security advisory](https://blog.coinkite.com/coldcard-mk3-seed-generation-warning/) is the source to follow. It says fixed firmware is available for affected models and release tracks, and it also says updating firmware does not repair an existing affected seed. A seed created with insufficient entropy has to be replaced unless the independent dice-entropy exception applies.
The broader engineering lesson is not wallet-specific.
Security work often reviews components. Does the hardware RNG exist? Does the implementation fail on hardware RNG errors? Is the library cryptographically respected? Is the seed hashed? Is the checklist written? Those are necessary questions, but they are incomplete. The next question is whether the exact production path reaches the control under the same build flags, startup files, dependency versions, and deployment commands that users actually run.
That question is easy to skip because it is boring. It lives in symbol resolution, preprocessor guards, repo notes, generated files, one-line wrappers, and handoff details. It lives in the gap between the architecture people intended and the code path the system executed.
Good operations narrow that gap. They keep project rules close to the work. They make startup files explicit. They record decisions when ownership changes. They check deploy artifacts, not just source files. They leave handoff notes that let someone resume the work cleanly instead of repeating setup and trusting stale notes.
The COLDCARD incident is severe because the affected artifact was a Bitcoin seed. But the pattern is familiar. A control was present. People believed it was in the path. The production path went somewhere else.
That is the part worth carrying into the next review.