The Paranoid Wallet

For five years, the most trusted wallet in Bitcoin generated keys an attacker could guess

by hodlonaut | Aug. 7th, 2026

On the night of July 30, 2026, an attacker spent about forty minutes moving other people's Bitcoin. The coins came out of thousands of addresses, in waves. By August 4, the research firm Galaxy put the confirmed haul at 1,596 bitcoin taken from roughly 7,300 addresses across three waves and fourteen smaller incidents, and estimated that including suspected cases would push the total toward 2,000 bitcoin, on the order of 130 million dollars. The confirmed figure alone was already past 100 million. Nobody was phished. No malware was involved. No device was touched. The attacker did not need any of that, because the wallets had told the world their secret years earlier, in the way they were born.

The wallets were Coldcards. For most of the last decade the Coldcard, made by the Canadian company Coinkite, was the hardware wallet that serious Bitcoiners recommended to each other. It was the cypherpunk choice, the one that came with a dice-roll feature and a security-first reputation and a founder who told you, loudly, that everyone else was doing it wrong. It was the paranoid option, and paranoia was the point.

What the sweep revealed is that for five years the paranoid option had been generating its seeds from a random number generator that was not random. The flaw was not exotic. It was a single character in a line of code, sitting in the open, in a public repository, waiting. This is the story of how it got there, who put it there, who tried to warn them, and why a community that built its entire identity around the phrase don't trust, verify spent five years trusting and not verifying.

 

Part I: The Seed

A Bitcoin wallet is a very large number. The private key that controls your coins is one specific value out of a space so enormous that guessing it is pure fantasy. A twelve-word recovery phrase encodes 128 bits of that space. To search it by brute force you would need more time than the universe has left.

That protection rests entirely on one assumption. The number has to be genuinely unpredictable. It has to come from real randomness, what cryptographers call entropy. A hardware wallet has exactly one job that matters more than any other: draw a truly random number from a physical source, and never let anything weaker stand in for it. Everything else is decoration.

The Coldcard has a hardware true random number generator on its chip, the physical source it is supposed to use. Coinkite has long marketed the device's careful approach to randomness, including an option to add your own entropy with dice rolls. On paper, the seed was safe.

On affected firmware, the request for randomness was still made, but it no longer reached the hardware. According to the engineering team at Block, which published the first detailed technical analysis, and the security firm Wizardsardine, which traced the same path independently, the call that was supposed to draw on the hardware generator silently resolved to software instead, so that the routine meant to mix physical noise with a backup was in fact mixing two software generators together. One of them, inside the libngu library, began from constants written into the source, identical on every Coldcard in the world, and contributed, as Wizardsardine put it, zero entropy.

The other seeded itself from the chip's unique identifier and the state of its internal clock, values that are neither secret nor genuinely random. What the seed rested on, in the end, was a small and guessable amount of state, and how small depended on which Coldcard you owned.

Coinkite's own estimate, published in its “Technical Deep Dive into the Entropy Issue” blog post, is that effective entropy dropped to roughly 40 bits on the Mk2 and Mk3, and about 72 bits on the newer Mk4, Mk5 and Q, against the 128 the wallet was supposed to deliver.

Forty bits is not a fantasy to search. An attacker who knew a wallet's public address could regenerate the small set of possible seeds, check each one against the blockchain, find the match, and take the coins, without ever seeing the device.

The dice rolls saved the people who used them. A seed built with fifty or more private dice rolls mixed in real entropy the software could not poison, and Coinkite says those seeds are not at risk from this flaw.

A strong, unique passphrase was also a safeguard against this exploit. Almost everyone else who generated a seed on the affected firmware was exposed, and most of them had no idea.

The company built a whole guide around that promise. Coldcard's own documentation includes a Paranoid Guide, a tutorial for the most security-conscious setup, which instructs that the device shall never, in its entire life, be connected to a computer of any kind, taking power from a wall adapter and exchanging data only by moving an SD card back and forth. Paranoid was not a word critics reached for. It was the company's own name for the most careful way to own the device.

The cruelest part is what the Coldcard was famous for. Its signature feature was that it never had to touch a computer. You could run it air-gapped, moving transactions on and off with an SD card, so that even if your PC was riddled with malware, nothing could reach across the gap to the keys. On the Stephan Livera Podcast in February 2021, NVK explained the logic at length: the point of air-gapping, he said, is that even if an attacker knows a vulnerability exists, he cannot get in remotely and retrieve what he is seeking. That was the whole security model, and against most threats it is sound. It did nothing here. The entropy flaw needed no reaching in and nothing to retrieve. The seed was already guessable from the public blockchain, so the attacker never had to touch the device, connected or not. The one feature that made the Coldcard feel safest was, against the failure that actually came, completely beside the point.

 

Part II: One Commit

The flaw entered the codebase on a single day, March 1, 2021, in a single commit. It is public. Anyone can read it. Its message is First pass w/ libNgU, its identifier begins b18723d, and it changed 120 files, adding 2,766 lines and removing 2,722. It was authored by the GitHub account doc-hex.

That one commit did several things at once, and the combination is the center of this story. It deleted the file named COPYING, which held the text of the GPL version 3 license. It removed a submodule pointing at a Trezor-derived cryptography library, the mature, years-hardened code Coldcard had been built on. It added a new submodule pointing at a library called libngu, owned by an account named switck.

And in the same sweep it reworked the files that generate the wallet's seed, including the board configuration header and a new random-number file.

So in one commit, on one day, Coldcard tore out the battle-tested crypto library it had inherited, shed the license that came with it, and wired seed generation to a new library written by someone else. The someone else, it turns out, was not someone else at all.

The migration was not indiscriminate, and that is the strangest thing about it. Of the seven places in the firmware that drew on the hardware random source, five were left exactly as they were, still reading the hardware generator, where they remain today. Two were moved onto the new path. Those two were the wallet seed and the shared random module that feeds it: the two most security-critical sources of randomness in the device.

Alekos Filini, the developer who first documented the migration from the public git history, is careful about what it means, and when I asked him directly, he was careful again. The same developer, he notes, wrote the correct guard in the firmware's own code and the broken one in libngu, which Filini calls a mistake. I asked whether his analysis showed the seed path had been moved deliberately. He would not go that far. The finding, he told me, would be better phrased as the fact that two of the paths were treated differently from the rest.

Whether that difference was deliberate, he said, he could not say, because he could not be sure it was not done by accident. He offered the two readings himself, without choosing between them. The developer, he said, may have been jumping around in the code without thinking too much. Or the move was on purpose and well meant: he may have thought his new library was better and wanted to use it, genuinely believing it would improve the device's entropy rather than destroy it.

That is as far as the person who found the fact will go. What the code will not explain on its own is why the single most important call in the device was among the two that moved, while file erasure and backups were left on the hardware they still use. That the seed path was treated differently is a fact. What it means is not one the record settles, and the one person who has read the history most closely declines to settle it. I asked Coinkite in a Right of Reply email why the seed path and the module feeding it were moved while the other five consumers were left on the hardware. The company did not answer the question before the deadline.

One more timestamp belongs to this Part, and it is public. On March 9, 2021, the day the 4.0.0 beta was announced, a user read the release notes, noticed the line about the BIP39 code being replaced, and asked about it directly, posting a zoomed screenshot of the exact words: “all crypto and bip39 related code replaced.”

DocHex answered at 11:23 that night, in the open, where the exchange still sits. Yup, Replaced with functionally equivalent code. All the same features plus some BIP39 improvements since we were in there.

The user asked whether the company's guide to verifying dice rolls still held. Yes. 100%, DocHex answered. On the dice guide he was right; dice rolls were the one seed path the regression never touched. On the equivalence he was wrong. The replacement was not functionally equivalent, because for the most important feature the device had, it no longer reliably reached the hardware. What the exchange preserves is the certainty, offered publicly by DocHex, eight days after the commit and eight days before the release, to a user who had pointed at exactly the right place.

 

Part III: switck

Two names have run through this story so far. One is doc-hex, the account that authored the commit and answered for it in public. The other is switck, the account that owns libngu, the library the commit reached for. In October 2020, switck had announced that library on X with the words “i made a useful thing”, linking to the repository.

A few days earlier he had written to DocHex that he was “making yet another bitcoin library that could be useful on @COLDCARDwallet someday”.

DocHex and switck are the same person, and that person is Peter D. Gray, co-founder and Chief Technology Officer of Coinkite. This is not speculation. The developer Dylan LeClair identified it by matching GPG cryptographic signatures on dozens of commits made under both the switck and doc-hex names and Gray's own.

The Bitcoin developer James O'Beirne verified the match.

Foundation's Zach Herbert independently noted a phone number ending in the same two digits tied to both accounts, and a Clarity.fm profile listing Gray as a co-founder and CTO.

The identity is over-determined. Before publication I asked Coinkite directly whether it disputed that the switck and doc-hex accounts are Gray's. I also the questions via X DM to Novak(@NVK) and Gray(@switck). Novak’s DM was read, but remained unanswered. A Coinkite support specialist confirmed forwarding the email questions to the company. No answer came. Coinkite has not disputed the identity, and given the chance to, did not.

There is a detail here that is easy to miss and hard to unsee once you have seen it. On October 21, 2020, an issue titled "PR's accepted?" was opened on the switck repository. The account doc-hex, Gray's Coinkite identity, opened it, labeled by the repository as a contributor, writing as if from the outside: “Welcome to Open Source. I see this is MIT licensed and we'd like to use some (or really all of it) in certain projects, like @Coldcard. Would you accept code from us when we give it as PR?”

The account switck, Gray's other identity, labeled the owner, replied not an issue, closed the issue as completed, and then, a moment later, added JK. just depends on PR.

The exchange runs from the opening question to the closing quip in about eight minutes. Gray was asking himself for permission, and granting it, in public, to establish that libngu had come to Coldcard as an outside contribution.

It had not. It was the CTO's own code, dressed as a third party's. I asked Coinkite what the purpose of that exchange had been, and whether it was meant to present libngu as a third party's library. The company did not answer.

The fiction did not stay on GitHub. When the rewrite shipped that March, the official release notes for firmware 4.0.0 credited the migration with the words “huge thanks to @switck for the new library!”

The company was thanking its own chief technology officer, under his pseudonym, as if he were an outside contributor, in its own documentation, where the credit remains today.

What that staged exchange proves is narrow. It proves Gray manufactured an arms-length origin for a library that was his own. It does not prove he knew the library was broken, nor his motives for creating the distance.

 

Part IV: The License

To understand why the CTO of a hardware wallet company might want to stage a fake permission slip for his own library, you have to go back to the summer of 2020, and to a competitor.

On July 28, 2020, Foundation Devices announced Passport, a new hardware wallet. Foundation stated openly that Passport built on Coldcard's firmware, which at the time was published under the GPL version 3 license. The GPL is a copyleft license. It grants anyone the freedom to study, modify, and build on the code, on the condition that they release their own version under the same terms. Coldcard had itself used that freedom in 2018, building on Trezor's GPL code. Now a competitor was using it on Coldcard.

Two days later, on July 30, 2020, NVK, Coinkite's chief executive, posted his reaction. The post read: “I really regret choosing GPLv3 for Coldcard. Now we've a Clone (if ships) w/ ZERO contributions in code/financially. Clone is what you call when someone takes the hard stuff & just changes the UI. Our fault for choosing GPL. We will be changing a lot of that w/ future updates”.

That post has since been deleted from NVK's account. Its wording is preserved here from a capture made before deletion, and the deletion itself is confirmed: X's own interface now shows the message This Post was deleted by the Post author where the post used to be quoted.

What NVK promised in that post, the company then did, and the sequence is documented in Coinkite's own repository. On November 18, 2020, Coldcard added a new license, MIT plus the Commons Clause, a combination that permits reading the code but forbids others from selling products substantially based on it. The Commons Clause is explicit that software under it is not open source. Firmware release 3.2.1, in January 2021, announced the change in its own notes: the license had moved from GPL to MIT plus Commons Clause.

Coldcard was becoming, in the plain meaning of the terms, source available under a commercial restriction rather than free software.

The last piece of GPL code to remove was the Trezor-derived cryptography. That is what the March 2021 commit did. And the library brought in to replace it, switck's libngu, had itself been relicensed for the occasion. On February 5, 2021, three and a half weeks before it was wired into Coldcard, libngu's license was changed from a standard MIT license to a custom one titled Licensed for Bitcoin Only, with a new clause forbidding its use in any system handling a cryptocurrency other than Bitcoin.

The personal side project had been fitted with a bespoke, competitor-hostile license immediately before it became the foundation of Coldcard’s seed generation.

NVK made the motive plain in public. On August 6, 2020, a week after his deleted post about GPLv3, he tweeted that he was possibly making a brand new license to deal with Open Source predatory behaviour, and that he was thinking of calling it Fuck The Leeches License, FTLL.

The license Coldcard actually shipped was less profane and more effective. But the sentiment that reuse of the open code was predation to be shut down, is the thing that drove the overhaul. And the overhaul is the thing that carried the bug.

This is where the evidence is strong and where it stops. What is proven, from immutable git history, is that the removal of the GPL and Trezor lineage and the introduction of the flawed seed path happened in the same commit, as part of the same licensing-driven overhaul. What is not proven is that the licensing motive caused the bug. Herbert, who assembled much of this timeline and has every reason to press the point, does not press it. His own words are: “We don't know by how much the licensing pressure affected the scope or timeline of the rewrite. All we can determine is that the entropy bug was introduced inside the same 120-file commit that removed the old GPL code dependencies”.

The rewrite had real technical goals too. Coinkite cited a move to Bitcoin Core's libsecp256k1, faster cryptographic routines, and reproducible builds.

A rushed rewrite driven partly by a desire to shed a license, carrying real engineering ambitions, that happens to introduce a catastrophic flaw nobody catches: that is a description of negligence under pressure, not of sabotage. It is worth saying plainly, because the temptation runs the other way, that nothing in the licensing story on its own shows anyone intended to weaken the wallet. The question the code raises, the one from the last section about which files were moved, is separate, and it stays open.

 

Part V: One Character

The bug itself is almost disappointingly small. libngu contained a guard, a piece of code whose entire purpose was to stop exactly this from happening. It reads, in effect, if the hardware random number generator is not available, refuse to build and raise the error “get a HW TRNG plz”.

The intent could not look clearer. The author wanted the firmware to fail loudly rather than ship without real randomness.

The guard was written wrong by one character. It used a check that asks whether a setting is defined, rather than whether it is switched on. Coldcard's board configuration defined that setting, but defined it as zero, meaning off. Because the setting existed at all, the guard saw it and stayed silent. The build passed. The error never fired. And seed generation, reaching for a hardware random number, resolved instead to the software imitation. As Wizardsardine summarized it, one character stood between that safeguard and its purpose.

The correct hardware routine was still present in the firmware the whole time. It was used for other things, like generating passwords for backup files. Reviewers who looked at the code saw it there and concluded the wallet was fine. What no one verified, according to the analysis of the proof-of-concept that circulated after disclosure, was which routine the seed path actually reached at the moment a wallet was created. The safe code existed. Nobody checked that it ran. I asked Coinkite whether anyone at the company had ever verified at runtime, rather than by reading the source, which generator the seed path reached when a wallet was created. The company did not answer.

Gray's own explanation for the bug, published in Coinkite's “Technical Deep Dive into the Entropy Issue”, describes exactly the kind of mistaken assumption that produces this: he set the configuration flag to zero thinking the wallet did not need either version of the built-in generator, not understanding that the setting would summon the software one instead.

What the guard cannot tell you is why the seed path was routed toward it in the first place while the other hardware consumers were left alone. That question and this one do not have to have the same answer.

The mistake was a small one. The man who made it was not a small talent. Long before Bitcoin, before Coinkite, Peter Gray had spent a career at exactly the layer where this bug lives. His work was embedded firmware on bare-metal microcontrollers, the same class of small, resource-starved chips that runs inside a hardware wallet: the 8-bit and 16-bit Motorola parts, the 32-bit ARM. He wrote device drivers and ported operating systems and network stacks onto hardware that had none. He built USB stacks by hand, in kilobytes of memory. He worked in C and in assembly, across architectures, for decades, in the close and unforgiving space where software has to meet silicon exactly or not at all. This was not a domain he was visiting. It was the domain he knew best.

That is what makes the guard so hard to look away from. A check that fails because it asks whether a setting is named, rather than whether it is switched on, is precisely the kind of error that a careful reading by exactly that expertise is built to catch. It is the sort of thing Gray, of all people, was equipped to see. And for five years, in the most security-critical library in a device whose entire promise was security, no one saw it, least of all the person in the company best able to.

 

Part VI: The Warning

The flaw did not go five years without anyone seeing it. In May 2025, more than a year before the sweep, James O'Beirne set out to audit exactly this part of Coldcard's firmware. He wanted to know, conclusively, where the wallet's randomness came from. He traced it to libngu. He flagged that the hardcoded Yasmarang constants were unnecessarily lax and a bad choice, and advised the team that libngu was unnecessary and could be removed in favor of a standard cryptographic library. He had also picked apart the device's randomness mechanisms for himself, and what troubled him most, he told me, was that he could not be sure the MicroPython software fallback was not in use. He believes he expressed that concern to the team, though he does not recall his exact words.

O'Beirne is not a hostile outsider. He is a respected Bitcoin developer, and by his own account he had been a friend of NVK's. He raised the concern directly, by name. A Signal group named, aptly, LNGU Clean up, dated May 23, 2025, with NVK and Gray in it, records that the conversation happened.

When I asked O'Beirne what answer he got, he told me it came from Gray or another Coinkite engineer, and that its substance has stayed with him: if that were broken, they would have known about it years ago, because the device would have been generating so many bad keys. The reasoning assumed a broken generator would announce itself. The particular cruelty of an entropy failure is that it does not. A weak seed looks exactly like a strong one, to its owner and to its maker, until the day someone else derives it. O'Beirne did not push further. He took the dismissal, he told me, as assurance that the code was in fact configured the right way, just confusingly. That was, he says now, “a huge mistake”; he had deferred too much, he told me, to the company's assurance that nothing was off. Fourteen months later, the wallets began to drain. I put O'Beirne's account of that exchange to Coinkite and asked whether the company disputed it. It did not answer.

Coinkite’s response to O’Beirne was not an off-hand brush-off. It was a principle. Four years earlier, on Stephan Livera's podcast, NVK had laid out his philosophy of who gets to decide how serious a vulnerability is. The person who chooses the severity of a bug, he said, is the target vendor, who is the ultimate source of truth on it, even if they minimize it.

Read one way, that is simply true: the maker knows the code best. Read against O’Beirne’s story from May 2025, it is the whole problem in a sentence. When the vendor is also the sole arbiter of whether a warning is worth acting on, a wrong dismissal has no security net. O'Beirne raised the exact defect. The vendor, the ultimate source of truth, minimized it.

O'Beirne is worth listening to precisely because of where he stops. He has looked harder at this than almost anyone, he was rebuffed personally, and he has said the pseudonym and the dismissal leave him with, in his words, “a high potential that something isn't right”. He does not say it was deliberate. When the person with the most reason and the most standing to make the larger accusation declines to make it, that is very likely the honest boundary of what the evidence supports.

There is a coda to the warning, and Coinkite published it itself. In August 2026, after the theft, the company released a chronology of every security review in the device's history. It records that between May 1 and June 26 of 2026, one year after O'Beirne pointed at libngu by name, an AI-assisted review of the firmware produced eighty-five candidate findings, every one of them triaged and the review closed.

The exploit began thirty-four days later. The review had not caught the entropy bug. Coinkite says it has since tested the code against several frontier AI models, and that none of them caught it either. By the company's own accounting, the bug lived at a boundary between submodules, outside the code that its reviews were aimed at. O’Beirne had aimed at the right code, by name, a year before.

 

Part VII: The Thing Nobody Verified

There is a bleak joke buried in the timeline. On October 10, 2021, seven months after the flaw shipped, the official Coldcard account was asked to define a piece of security jargon, a retirement attack. It answered: “It's when the project makers could have a "bug" in the entropy generation for later retrieval”.

A retirement attack is a real, named idea in hardware wallet security: a maker deliberately weakens the randomness so they can drain everyone later. Coldcard was describing, as a known threat, the precise shape of the failure its own firmware was already carrying by accident. It is important not to over-read this. Describing a textbook attack is not confessing to one, and every serious wallet maker warns about the category. But the irony is exact, and it points at the real indictment, which is not about one man's intent at all.

There is a second version of the same irony, and it is sharper because NVK volunteered it himself. On Citadel Dispatch in 2022, riffing on how a sophisticated state actor might quietly kill an open-source project, he described the playbook admiringly: “You make a bunch of very bad decisions, he said. You make the software awful, there is no documentation, and then you just add all the bugs that you can exploit later”.

He was describing sabotage. By the time he said it, his own firmware had already made a bad, undocumented decision in a rewrite more than a year earlier, and the bug that rewrite carried would be exploited about four years after he named the pattern. Nothing about that proves intent, and the resemblance could just be the cruel symmetry of the thing. But the exact shape of the catastrophe had been mentioned twice, before it arrived.

The oldest version of the irony predates the flaw itself. In December 2020, ten weeks before the commit introducing the bug, NVK debated seed generation on X with Michael Flaxman, a security engineer who advocates verifiable dice rolls on the grounds that, as he put it in that thread, the alternative of trusting the RNG is horrible. NVK was relaxed about the machine:My money is on people screwing themselves out of their BTC before any vendor tries a retirement attack”, he wrote. “Alternatively people could just use dice ;)”. And then: “I think we both agree that people shouldn't trust the vendor RNG, we just have different preferences on the solution. I just think people will screw up entropy”.

Every clause of that bet inverted. It was the vendor's generator, not the users, that screwed up entropy, and dice, rolled in earnest numbers, were what saved those who used them. He was right about the principle. Nobody should have trusted the vendor RNG, Coinkite’s least of all. Like the other ironies, this one proves nothing but proximity, and talking frankly about vendor risk is what responsible vendors do. What the exchange documents is: ten weeks before the rewrite shipped, the stakes of the seed path were very clear to the company about to rewrite it.

 

Part VIII: How Scrutiny Was Punished

That reputation did real work, and it was defended fiercely. When Foundation Devices built a wallet on Coldcard's open code in 2020, exactly as the GPL license invited anyone to do, NVK did not treat it as ordinary competition. In the official Coldcard Telegram group he called it affinity scamming, said all they did was change the UI, declared the project source closed, and warned, in a pun on tears, that it would end in tiers when users get pwnd by ppl that can do the security themselves. A pure clone, he wrote elsewhere in the same channel, a festival of imported libs. These are his words, in his own community, about a competitor exercising the freedom his license granted.

There is a sharper irony in the same pattern, visible because both ends are on the record. In 2018, when it was Coldcard building on someone else's GPL code and Trezor's co-founder criticized Coldcard for renaming the borrowed files, NVK defended himself by invoking the exact principle he would later abandon: “We researched the licensing issues carefully and respect the GPL”, he wrote then.

Two years later, on the other side of the same act, respect for the GPL had become predation by leeches to be shut down with a custom license. The rule did not change. Only which side of the fork he stood on did.

The point of assembling this is not that NVK was rude, though he was. It is that the combativeness had a function. It made criticizing Coldcard expensive, and the clearest examples are the ones where the target was not a competitor but the machinery of verification itself.

In June 2023, WalletScrutiny, a project whose entire purpose is to check whether a wallet's public code actually matches the binary that ships, reported that it could not reproduce certain Coldcard builds.

NVK's response was to post that WalletScrutiny was “either incompetent or malicious, and, minutes later, “is it time to just sue them? Maybe other projects slandered by their incompetence in review should join”.

The company's GitHub issue tracker was disabled, so the technical dispute played out as insults on social media instead. Then a well-regarded Bitcoin Core developer, Carl Dong, with no stake in either side, spent a day on it, saying he hated to see both sides in a feud. He reproduced the problem, traced it to a build script that failed to set a timestamp variable when a file was pre-downloaded, confirmed the builds were now fixed, and concluded, in his words, that “no one was trying to be malicious, it was an honest misunderstanding”. The auditor had been right. The defect was real, benign, and already patched. The “incompetent or malicious” charge had been refuted by an independent expert within twenty-four hours.

It is only fair to note that NVK's conduct in that episode was not all of one piece. In the same window he also offered a bounty, a million sats each to the first people who could reproducibly build the firmware on video, which is a pro-verification gesture, and Coldcard did ship the fix. His response was contradictory, generosity in one breath and lawsuit threats in the next, rather than uniformly hostile. But the hostility was aimed squarely at a reproducible-builds project for doing reproducible builds.

It had happened before. In late 2020, researchers from Shift and from Nunchuk responsibly disclosed a genuine flaw in how Coldcard verified multisignature setups, a bug that could let a compromised computer trick the device into accepting a wallet the user was not actually part of. Coinkite fixed it promptly, in version 3.2.1, and credited the researcher by name.

Speaking about it a year and a half later, on Citadel Dispatch episode 8, NVK owned it without reservation: “it was 100% our fault”. And in the same breath, he characterized the people who had reported it: “it was like PR terrorism”. Elsewhere he called the disclosing researchers “salty cunts” and explained his refusal to pay them a bounty with “I don't deal with terrorists”.

He had a real argument underneath the invective, that a competitor can weaponize disclosure by shipping a security feature and then branding its absence in a rival a bug, and a fair grievance that some coverage overstated the flaw as a remote attack. But the target of the terrorist language was a group of researchers who had quietly reported a real vulnerability, that his own company had fixed, and that he himself called one hundred percent his fault.

The pattern did not go unremarked by the people who had most reason to defend the company. Ben Perrin aka BTC Sessions, a prominent hardware-wallet educator who had been a paid Coldcard sponsor and recommended the device to his audience for years, wrote after the theft that O'Beirne had been ignored, and that others who raised concerns had been dismissed as fear-mongering, or blocked. NVK, he wrote, had met the wider field with an attitude of superiority, and had at times been combative toward competing projects.

Coming from someone who had promoted the product, and against his own past word, it was not the testimony of a rival.

Whether this climate discouraged the scrutiny that might have caught the entropy bug earlier cannot be proven, and it should not be asserted. What can be said is that the scrutiny did not happen, that the one researcher who did look closely was waved off, and that the flaw was ultimately found not by a careful audit but, on the evidence of the days after disclosure, by people pointing modern code-analysis tools at a public repository and finding in minutes what five years of deference had missed.

 

Part IX: Sleep at Night

The Coldcard was sold, and recommended, and trusted, as the wallet for people who verify everything. Its culture was built on the phrase don't trust, verify. In practice, verification in that world came to mean running your own node to check the blockchain. Almost no one can audit a signing device's random number generator, and almost no one did. The one thing a hardware wallet exists to do, produce an unguessable number, was the one thing that sat unverified, on faith, behind a founder's reputation, for five years.

As late as August 7, more than a week into the draining, the company's public profile on X still described the Coldcard as the best Bitcoin hardware wallet, ultra secure, the words sitting directly below a security advisory about the theft.

The questions came, over the years, and they were the right questions. In July 2021, four months into the vulnerable window, in a public thread, a user named Alex Waltz asked NVK whether the company had ever tested the true random generator, and what it used. NVK answered that they did not use the chip's dedicated generator because it was too slow, that they used the main processor's instead, and that “we have tested it's entropy quality”.

Asked how, he pointed to the firmware, and Waltz read it and named the tool: dieharder.

Dieharder measures whether a stream of numbers looks uniform, which the software fallback's output does. It cannot measure whether the generator you believe is running is the one the wallet actually reaches. The one test that would have caught this was not in the rubric, and the answer to how they tested was a test that could not have caught it.

The company had sold that trust directly. Coldcard's marketing made paranoia a service it performed on the customer's behalf: “we make paranoid security designs”, it posted, “so that you can sleep at night”.

It was specific about why a customer could. Nothing is infallible, it wrote in another post, everything has attack surface, and then it listed the reasons people slept anyway: extreme paranoid attention to detail, well readable and verifiable source code, reproducible builds, and the old engineering discipline of keeping it simple.

Each of those was true right up to the point where it mattered. The attention to detail missed a one-character error in the most important line it had. The source was readable and public and went unread. The builds were reproducible, and faithfully reproduced the flaw. And the simplicity was gone, traded away in a 120-file rewrite that swapped battle-tested code for a library written in-house, for reasons that seemingly had more to do with a license than with security.

There is one more figure in the record of those weeks, and he complicates the picture in the other direction. Dee, a Coinkite support specialist who posts on X as HodlDee, spent the days after July 30 in public, answering affected users one at a time. On August 1 he was urging Coldcard users to move potentially affected funds immediately, telling them his direct messages were backed up but that he was answering everyone as fast as he could. By August 2 he described working through hundreds of support emails and messages, helping people rotate keys and migrate funds, and noted that he had no control over the company's social accounts. To a man who wrote that he had lost a third of his savings, he replied that he was sorry, that he felt for him, and that he should send a message if he needed help with anything. For many of the people trying to find out whether their coins were gone, he became the human face of the company.

Others noticed. “My heart goes out to @HodlDee”, a commenter named PakoVM wrote on August 5, describing what the job looked like from outside: hundreds of worried and angry people directing their questions at one support employee, every second spent helping one of them a second not spent helping someone else. If there was anyone who did not deserve the storm that came down on the company, he concluded, it was him. Whatever else the record shows about how Coinkite met scrutiny, it should show this too.

Coinkite sold verification as its creed and its product, and the one thing that most needed verifying was the one thing no customer could check and no reviewer thought to. The safeguards it advertised were real, and every one of them was pointed at the wrong place. Reproducible builds proved the binary matched the source, and the source was broken. Public code invited inspection, but the flaw sat in it, in the open, for five years.

 

Part X: The Correction

When the thefts began, Coinkite's first public explanation was that they were not the company's fault. In the initial hours, Kevin Loaec of Wizardsardine, who would later publish the definitive teardown, noted publicly that the pattern looked like it could be an entropy weakness, the randomness not fully broken but too weak, and that many of the drained coins were old. NVK quote-tweeted him to push back. There was no need to panic, he wrote: someone had loaded a bad seed into a Coldcard or leaked their own, and the incident touched some five hundred keys.

Both halves would prove wrong. The seeds were not user error but the company's own, and the losses were not five hundred keys but thousands of addresses and more than a hundred million dollars. NVK later deleted the post.

What replaced it was not silence. From the first days, Coinkite communicated, and often. It published an urgent advisory on July 31 and updated it as findings came in. It emailed the customers it could still reach.

On August 4 it published a longer statement, titled “Adding to the Public Record on Our Ongoing Investigation”, that opened by acknowledging the obvious: “We understand there is real anger at this moment. Users have suffered real losses, and for those impacted, no public statement is enough”. The contrition reads as genuine. The company did not hide, and it did not pretend the losses were small.

But across a week of statements, the questions that go to how the failure happened, and why it lasted, went unanswered, and the technical defense narrowed, in the end, to a correction about a single word.

The correction went out on August 7, in a quote post of a widely watched explainer by Jack Mallers, who had described the failure as a fallback to weak entropy. Not so, Coinkite said. There was no weak-entropy fallback. The generator that produced the guessable seeds was not Coinkite's design but MicroPython's, a general-purpose routine inherited from the platform the firmware runs on. Coinkite's intent had been the opposite of a software fallback: seed generation was meant to rely exclusively on the hardware. Setting the flag to zero was supposed to disable the software path. The weak generator became active not by design but through a link-time error.

Every clause of that is true, and none of it is exculpatory.

It is true that no one at Coinkite wrote a line of code that said, if the hardware fails, use something weak. What they wrote was a guard meant to make that impossible, and the guard did not fire, and the software path they believed they had disabled was the one the wallet used for five years.

Whether you call that an intentional fallback or an inherited default activated by a link-time error is a question about vocabulary. It is not a question about whose firmware it was, who disabled the flag, who wrote the guard that failed, or who shipped it untested. The answer to all of those is the same, and the correction does not change it.

The correction is also, on its own terms, incomplete. The hardening pattern the code used was to take a number from the hardware and mix it, by exclusive-or, with an internal pseudo-random generator, so that even a weak generator could not spoil a good hardware draw. When the hardware input silently became a second software generator, the operation was mixing two software generators together. One of them was MicroPython's, the one Coinkite pointed to. The other was Coinkite's own, inside libngu, and it began from constants written into the source, contributing no entropy at all. Of the two generators in the failure, the weaker one was the one Coinkite had written. James O'Beirne, who had warned them about this code the year before, read the correction and called it what it was: “hairsplitting and misdirection.You absolutely did fall back to weak entropy”, he wrote, and the one they had written was weaker than the one they blamed.

Alongside the correction, in the same days, the company reached for a second explanation, one that pointed away from itself and toward the moment. The bug had lived in public for five years, it said, and no one had found it. It had taken the newest AI models to find it.

The first half of that is true, and it is the heart of the indictment. The second half the company's own history does not support. The flaw was pointed at, in May of 2025, by a person, with no frontier model, who traced it to the library by name and was told the company would already know if something were wrong. It was found again after disclosure by people pointing ordinary code-analysis tools at a public repository. What took five years was not the finding. It was the looking.

The keys and coins are gone either way. A wallet built on the promise that you would never have to trust anyone, turned out to rest, at its foundation, on trusting one company, one man, and code that no one read closely enough. The lesson Coldcard leaves is us with the one it always claimed to teach, butnever quite meant literally enough.

Do not trust. Verify. All the way down.

 

Right of Reply

This investigation makes findings about a named company and named individuals. Before publication, each was given the opportunity to respond.

On August 5, 2026, I sent Coinkite eight written questions covering every adverse point in this piece: the reason the seed-generation path was moved to libngu while other consumers were left on the hardware; whether anyone at the company had ever verified at runtime which generator the seed path actually reached; the purpose of the October 2020 exchange on the switck repository; whether the company disputed that the switck and doc-hex accounts are operated by Peter Gray; whether it disputed James O'Beirne's account of his May 2025 warning; and the licensing decisions surrounding the 2021 rewrite.

The questions were sent through four channels: by direct message to Rodolfo Novak (NVK), Coinkite's chief executive; by direct message to the switck account, which this reporting identifies as Gray's; and by email to the company. The doc-hex, Coldcard, and Coinkite accounts do not accept direct messages. The direct message to Novak's account was opened. A Coinkite support specialist confirmed, on August 5, that he had forwarded the emailed questions to the company's team.

I set a deadline of August 7, 2026, at 6:00 PM ET, and stated that any response received after that time would be published as an update. Coinkite did not answer any of the eight questions by that deadline.

The company was not silent in this period. It communicated extensively in public about the incident, and those statements, including its August 7 correction and its account of the failure's cause, are engaged with directly in this piece. But the specific questions put to it went unanswered.

A company facing an incident of this scale may have been constrained by counsel from addressing questions directly, and the absence of a reply should be read with that possibility in mind. It is not treated here as an admission of anything.

Any response from Coinkite, Novak, or Gray received after publication will be added to this piece.