COLDCARD RNG incident the public record, collected and explained
Informational only, and this site never asks for your seed words. details

Informational only. This is an open source collection of what others have published about the incident, together with an explanation of it. It is not financial, security or legal advice, and not a substitute for professional advice about your own situation. It is not affiliated with, endorsed by, or speaking for Coinkite. Material is attributed and quoted as published; where sources disagree their scenarios are kept separate with their assumptions rather than reconciled into one answer. Everything is meant to be checked against the linked evidence rather than taken on trust. Act on your own judgement about a particular situation. Editorial standards and corrections.

Do not disclose recovery material to a website, form, message or support account. This site never asks for it, and contributions containing recovery words or private keys are not accepted.

Plain language Updated 15 Aug 2026

What the developer community did

Four public incident-response proposals are tracked. Their state moved through 1 August 2026: one stayed open, two were closed by their own authors, and the firmware companion became a draft waiting on a new upstream proposal. Two are now merged upstream, on 5 and 6 August 2026; one of the closed proposals continues as a three-part stack, and a Coinkite collaborator has opened a firmware proposal that would require user-supplied entropy for every new seed. A separately published commit-history analysis is reported below.

Outside Coinkite's own repository, the community response began as proposals rather than shipped change. Three pull requests against the upstream libngu library and one companion COLDCARD firmware pull request were all still open and unreviewed or unmerged in the captures checked on 1 August 2026. Two have since been merged into the library's master: #61 on 5 August 2026 and #58 on 6 August 2026, the second of which changed the ineffective guard itself so that the configuration now fails the build. The library publishes no releases, so no proposal is present in a numbered release as of 15 August 2026. A third, closed by its author on 1 August, was split the same day into three smaller proposals; two were still open on 7 August, and the third was closed by its author as overtaken by #61. Bitcoin Optech carried the advisory to its technical readership, and an independent developer published a commit-history reconstruction, reported below. Nothing here changes what an owner should do; it records what the developer community proposed.

The upstream guard in the 1 August capture

The COLDCARD hotfix replaces the linked rng_get() implementation for the affected boards. It does not change libngu's original #ifndef MICROPY_HW_ENABLE_RNG guard. An integrator could encounter the same condition if it defined that macro as (0) and linked a software rng_get() fallback.

That is no longer the state of the library. ngu/random.c on master changed on 6 August 2026 when libngu #58 was merged: the guard now reads #if MICROPY_HW_ENABLE_RNG == 0 rather than #ifndef, so a board that defines the macro as zero fails the build with #error "get a HW TRNG plz" instead of passing silently. The same commit routes the Linux target through getrandom() in place of random() and rejects a negative byte count in random_bytes(). The captures do not show what any downstream integrator has done with that change. V1

Three pull requests were opened against switck/libngu, two on 31 July 2026 and one on 1 August 2026.

Upstream libngu pull requests opened after disclosure V2
PR Proposal State across the captures held
#58btchip · patch Enforce a hardware TRNG. Make an unsupported board configuration fail at build time rather than use the software path. Merged Still open in the last capture of 1 August, 08:11 UTC, with no maintainer reply in any capture; merged by the maintainer as commit e9d5e80 on 6 August 2026, with no review recorded on the page.
#59jgmontoya · patch Fail-closed entropy backends and HMAC_DRBG. The branch includes tests against official NIST CAVP vectors, deterministic health-rule tests and negative compile gates. Closed by its author Open at 03:25 UTC, closed by 16:08. The maintainer replied "diff too big"; the author offered a three-PR split and then closed this one. The split was opened the same day as libngu #62, #63 and #64, all three held here.
#60ballance · patch Absorb a full-width seed. Accept a bytes-like reseed value, mix every byte into all Yasmarang state words, and retain integer input for compatibility. Closed by its author Open at 06:21 UTC, closed by 16:08. No review or maintainer reply appears in any capture; the work moved to a new proposal, libngu #61.
#61scgbckbone · patch Replace the generator outright. Substitutes a SHA-256 Hash-DRBG for Yasmarang and requires a reseed seed of at least 32 bytes, so the old four-byte integer call is rejected rather than quietly accepted. Merged Opened after the other three and open with no maintainer reply in the 3 August captures; merged by the maintainer on 5 August 2026. The 7 August capture adds a referenced-by block naming the #62, #63 and #64 stack.

For #59, the proposed split is: the DRBG and CAVP-vector tests, the entropy health rule, and a smaller final random.c rework. All three were opened on 1 August as libngu #62, #63 and #64, and each is held here with its patch, captured on 7 August 2026.

  • #62, the HMAC_DRBG core, is closed. Its single commit added an HMAC_DRBG built directly on the SHA-256 backend libngu already uses, rather than mbedtls' HMAC layer, which the author says allocates; the author states it was checked by a host-compiled harness against official NIST CAVP vectors through both backends. The author closed it on 7 August with the comment "No longer relevant given #61" — the proposal the maintainer had merged two days earlier.
  • #63, the entropy health rule, is closed. It rejected a source word that was zero or that matched either of the two most recently accepted words, so that a stuck source and an exact two-word cycle were caught, and a rejected word did not advance the history. The author stated a steady-state false-rejection probability of 2-31 per word and said the rule detected no cycle longer than two words. On 7 August 2026 the author of the merged #61 reviewed it, argued that no guidance he could find recommended rejecting a single A, B, A sequence and that a healthy 32-bit generator would produce one about once in four billion words, and asked whether a documented two-word cycle failure mode justified the check. The author agreed, said he would rebase #64 without the rule, and closed #63 the same day.
  • #64, the platform-boundary rework, is merged with four commits. It centralises backend selection so unknown targets fail to build, permits STM32 builds only with MICROPY_HW_ENABLE_RNG=1 or an explicitly declared external rng_get(), requires an explicit ESP32 attestation, uses getrandom(2) on Linux and arc4random() on macOS and FreeBSD, refuses thread-enabled builds without a GIL, corrects the rejection mask in uniform(), and adds negative compile gates that assert each misconfiguration fails. It was merged on 10 August 2026 after scgbckbone approved it on 9 August.

What the stack proposes has narrowed since #59 closed. #59 offered to replace Yasmarang with the author's own HMAC_DRBG; #64 states that the generator "remains Cifra Hash_DRBG" as merged in #61, and hardens the entropy boundary around that generator rather than substituting for it. #62 and #63 were closed on 7 August; #64 was force-pushed and retitled twice on 7 August and merged on 10 August. Each of the three carries a disclosure from its author that it was developed with substantial LLM assistance, then adversarially reviewed, and that maintainer review is still required. V3 R4

#63 drew a substantive review from the author of the merged #61. On 7 August 2026 scgbckbone, writing as a repository contributor, questioned the rule: nothing in NIST SP 800-90B or STM32 guidance that he could find recommends rejecting a single A, B, A sequence, a healthy 32-bit generator will produce one about once in four billion words, and without a documented two-word cycle failure mode the check "seems arbitrary" and only adds an eventual false failure. The author agreed later the same day, said he would rebase #64 without the health rule and closed #63. #64 later received scgbckbone's approval on 9 August and was merged on 10 August. R5

COLDCARD firmware PR #691 began as the companion to libngu #60. It proposes passing the complete SHA256d digest from mk4.rng_seeding() into the widened reseed API rather than unpacking only its first four bytes. Through the day its state moved: open at 06:21 UTC, still open at 16:08, and a draft by the 17:41 capture, marked so at 16:13. A maintainer asked that the libngu changes be opened as a separate pull request against the libngu repository. The rewritten description now depends on libngu #61 rather than #60, a proposal that replaces the generator with a SHA-256 Hash-DRBG and requires a seed of at least 32 bytes, so the old four-byte call is rejected outright. In the capture held on 12 August 2026 a reviewer notes that the same change is already covered by PR #713 commit d16d47b and asks the author to close this draft; a collaborator asks the author to double-check and close it. V6 Its patch is held separately.

A larger firmware proposal followed from inside the repository. On 5 August 2026 scgbckbone, writing as a repository collaborator, opened COLDCARD firmware PR #707, "Improve seed gen & require external entropy for each new wallet", from the branch improve_seed_gen-public. It is a proposal, not shipped firmware: it was open, labelled an enhancement by doc-hex, and carried no review in the first capture held, taken at 15:45 UTC on 7 August 2026. By the next capture, at 19:22 UTC the same day, it was closed in favour of a successor by the same author; that is set out below. Its seven commits are held as a separate patch capture, and what they change is readable there:

  • Seed generation mixes the two secure elements with the TRNG. generate_seed() in shared/seed.py previously hashed 32 TRNG bytes alone; the patch appends 32 bytes read from SE1 and 8 from SE2 before the SHA256d.
  • The four-byte reseed truncation is removed. mk4.rng_seeding() drops the ustruct.unpack('I', n[0:4]) line and passes the whole 256-bit digest, which is the change firmware PR #691 proposed from outside the repository.
  • Every new master seed would require user-supplied entropy. The changelog entry states that key mashing, physical dice rolls or physical coin flips must be chosen, that TRNG, SE1 and SE2 randomness is mixed in as well, and that the user-supplied results are checked for obviously bad distribution. A later commit extends the requirement to CCC keys and temporary seeds.
  • The dice-only path would gain a warning screen stating that the rolls are the only source of randomness, that no hardware randomness is mixed in, and that the hash shown while rolling is secret. A UX test asserts the screen appears. This describes a proposed code change; what the shipped firmware does today is set out under the dice conditions.
  • The libngu submodule is bumped so the SHA-256 Hash-DRBG merged as libngu #61 replaces Yasmarang. A seventh commit then excludes schnorr and musig from the build to save flash and adds an NGU_STM32_EXTERNAL_RNG_GET macro; the author states on 7 August that this commit requires a further upstream proposal, libngu #68, and another submodule bump after it merges. That proposal was merged upstream the same day.

The proposal is unmerged in the capture held, and each of its changelog entries is added to releases/Next-ChangeLog.md, the file the repository uses for changes not yet published in a normal release. Nothing held here states that it will be adopted. It is recorded as what was proposed, and where it stood on 8 August 2026. V7 U8

It did not stand for long. Between the two captures held of that page, both taken on 7 August 2026, #707 moved from open to closed, and the same author opened firmware PR #713, "Improve seed generation - mash timing with microsecond-resolution", stating that it replaces #707. It was opened with seven commits and was still open in the capture held at 23:42 UTC on 14 August 2026, by which point it had been force-pushed to commit 11d8130 with a five-commit series that revises the mash-entropy implementation, adds a testing fixture and disables MicroPython threads for the unix port. The conversation also gained cross-references to PR #691 and #700 and an author self-review comment. What it changes about its predecessor is the mash path rather than the entropy requirement: timing is hashed at microsecond resolution at the raw key edge, 128 presses are required, and one bit of entropy is credited per press, which the proposal attributes to Peter Todd's push-button generator model. A proposal replaced by its own author within two days is worth stating plainly rather than leaving the record pointing at the version that was withdrawn. V9

A process observation on the firmware repository

The review path of the firmware repository itself drew comment. On 2 August 2026, mutatrum observed that most changes in coldcard/firmware land directly on master or are merged without review comments, and asked what the open repository provides in that state. R10 That is an attributed observation about the visible history, not a measurement this archive has repeated: no independent count of direct-to-master commits or reviewless merges has been made here.

Independent commit-history analysis

On 1 August 2026, bitcoin++ Insider Edition published a guest analysis by Core Lightning developer Dustin Dettmer, announced the same day on X. It reads the firmware commit history around the disabled hardware-RNG guard and the call chain that left seed generation on the software generator, and argues that the board override was aimed at a symbol the seed path never uses, while silencing the build condition that would have exposed the mistake. Dettmer attributes the defect's introduction to a 2021 commit and describes the developer's intent; both are reported here as published, not independently checked. R11

One further code-level assertion was made on 7 August 2026, in an exchange the disclosure history records: replying to a Coinkite correction about where the weak generator came from, James O'Beirne linked a specific libngu blob and said the Yasmarang copy in that library was weaker still because it used hardcoded constants. The characterisations on both sides are contested and are set out there; the source lines he pointed at can be checked here. The held capture of ngu/random.c from before the 6 August merge does define a second Yasmarang inside libngu, with fixed initial state (0x0a8ce26f, 69, 233), XORed into every output alongside CHIP_TRNG_32(), and a reseed() that assigns only the 32-bit yasmarang_pad. That is a second generator, distinct from MicroPython's; how it broke sets out how the two combine. Whether one is weaker than the other is a comparative judgement this archive does not make. V12

Where public discussion was found

Public technical-discussion record checked on 1 August 2026, rechecked 13 August 2026 U13
VenueRecord as of 5 August 2026
Bitcoin Optech Newsletter #416 led with the incident and placed "Move funds secured by COLDCARD-generated keys" in its Action items section.
bitcoin-dev and MicroPython upstream No thread or issue was found in either in a search on 1 August, nor in the 5 August recheck. MicroPython provides the software fallback; the ineffective guard was in libngu.
Delving Bitcoin Nothing in a search on 1 August. On 4 August, seed-cat opened Towards New Self-Custody Best Practices, a draft of custody practices written in direct response to the incident: 2-of-2 multisig, multi-vendor signing and user-generated verifiable entropy. The prescriptions are the author's own. R14

Two details from Optech

Coordination and anonymous researchers

Optech describes Block's analysis as "performed with anonymous researchers and disclosed in coordination with Coinkite". This is Optech's report of coordination and anonymous participation. It does not identify who originally found the defect or explain why the initial affected-model lists differed.

AI-assisted reproduction

Optech reports that several developers reproduced the attack with frontier-model assistance and advised treating the vulnerability as actively exploitable. That is reproduction after disclosure, not the unknown original discovery method: the AI page carries the quotation and works the distinction through. R15

Downstream public reactions

The disclosure also prompted decisions and reviews in other public repositories. These records show what those projects did or proposed. They do not establish that another product shared COLDCARD's defect.

Selected high-signal repository reactions checked on 1 August 2026, rechecked 5, 12 and 13 August 2026; a fourth was registered on 7 August 2026 R16 V17 V18
Record Response Public state
Bitcoin.org #4905 Removed the COLDCARD and COLDCARD Q wallet listings under the site's criterion concerning evidence that users were harmed by a listed wallet issue. Merged 1 Aug at 02:13 UTC. A separate issue opened on 2 August, "Actual live website is stuck behind master", references this pull request; it showed open in the 4 August capture and closed in the 6 August one. The merge is into the repository, and the archive holds no capture of the deployed site.
SatSigner #468 Reports an incident-prompted entropy audit. The author says the default OS-backed path was sound and proposes fixes for separate optional dice and coin paths. Merged Open with no review in the 1 August captures; merged by Psycarlo on 3 August 2026.
SeedSigner #962 Proposed camera-entropy health checks, then withdrew them after the author concluded the thresholds did not measure sensor entropy and the synthetic tests were not valid evidence. Closed unmerged No SeedSigner product change resulted from this proposal.
Sparrow #2047 Adds a warning row and a link to Coinkite's advisory wherever a COLDCARD is selected as a device, placed in the shared pane header so it covers import, airgapped keystore, USB and export flows at once. The author states that Sparrow does not generate the COLDCARD seed, so this is not a Sparrow flaw, and that detection is on the exact wallet model so that devices subclassing the COLDCARD importers do not trigger it. The description says the branch was drafted with an LLM coding tool and that the author could not run a local build, and asks a maintainer to verify. Open Opened 6 August 2026 by nrobi144 and approved by skwp the same day; open and unmerged in the capture held at 04:42 UTC on 12 August 2026. A second commit corrected the firmware and model details to match the advisory, a reviewer asked whether existing wallets would also be warned, and the discussion gained a follow-up comment clarifying which COLDCARD selection surfaces show the warning and another comment proposing a load-time acknowledgment or MOTD feature.

Licensing and forkability

The incident renewed a question about what the published source permits. On 2 August 2026, notgrubles asked whether Coinkite's licence would legally prevent forking the firmware to provide longer-term support if the company went out of business. R19 The question sits against an attributed history: a community account posted the same day links the firmware's Trezor-derived origins and a later relicensing under the Commons Clause to the outside-review question. R20 Neither post is a legal analysis, and this archive has not itself construed the licence terms; the question is recorded as open.

Follow-up items as checked on 15 August 2026, except where a later date is given

  • Coinkite promised a technical postmortem. The captured statement does not give a publication date or detailed scope. The company's blog index as of 15 August 2026 lists no postmortem; its newest incident post is "Update on Customer Data Retention", and the most recent incident write-up remains the 4 August "Adding to the Public Record on Our Ongoing Investigation". V21
  • No captured source announces an independent audit of the fixed firmware. This is an archive limitation, not proof that no private review exists. It still holds against material registered to 15 August 2026: the incident-funded review effort captured on the AI page scans Bitcoin repositories at large and is not presented as an audit of the fixed COLDCARD firmware.
  • No incident-specific CVE record was identified. NVD remained unreachable or inconclusive from this collector on 9 August 2026; no incident-specific CVE for COLDCARD/Coinkite has been captured, and the only NVD result seen earlier was the CVE-2019-14356 OLED side-channel record. A differently worded or unpublished request could be missed.
  • The two reproduction scripts described by Gregory Sanders (instagibbs) remain unavailable here. A dated search of his public GitHub repositories, code results and gist index found no matching publication, so the archive still cannot inspect the test conditions or method. Nothing registered up to 15 August 2026 supplies them. U22
Evidence on this page 22 items
  1. V1
    Verified

    The text of libngu ngu/random.c on master before and after 6 August 2026: the guard change from #ifndef to #if MICROPY_HW_ENABLE_RNG == 0, the Linux getrandom() helper, and the negative-count check in random_bytes()

    Source Captured raw ngu/random.c at switck/libngu master, 1 Aug and 6 Aug 2026, and the diff between them

  2. V2
    Verified

    The public contents of libngu pull requests #58, #59, #60 and #61, and the state each was in at every capture held: 03:25 to 17:41 UTC on 1 August 2026 for the first three, 3 to 5 August 2026 for #61, and rechecks on 6 and 7 August 2026 for #58, #59 and #61

    Source Captured switck/libngu pull-request pages and separate patch captures, 1 Aug to 7 Aug 2026

  3. V3
    Verified

    The titles, open or closed states, commit counts, stated scope and stated verification steps of libngu #62, #63 and #64, the closing comments on #62 and #63, the 7 August force-pushes and retitles, the 9 August approval and the 10 August merge of #64, as displayed in the captures held

    Source Captured switck/libngu pull-request pages #62, #63 and #64 and their separate patch captures, 7 Aug to 12 Aug 2026

  4. R4
    Reported

    The authors' own statements about CAVP verification, false-rejection rates, compile-gate coverage and LLM assistance; none of these test runs has been repeated by this archive

    Source jgmontoya's pull-request descriptions on libngu #62, #63 and #64, captured 7 Aug and 12 Aug 2026

  5. R5
    Reported

    scgbckbone's review comment on libngu #63, the author's reply agreeing to drop the rule and close #63, and scgbckbone's later approval of #64

    Source scgbckbone review comment on libngu #63 and scgbckbone's approval of libngu #64, captured 7 Aug and 12 Aug 2026

  6. V6
    Verified

    The public contents of COLDCARD firmware pull request #691, its stated dependency, the state it was in at every capture held from 06:21 to 17:41 UTC on 1 August 2026, and the 11 August 2026 review noting that PR #713 commit d16d47b covers the same change

    Source Captured Coldcard/firmware pull-request page and separate patch capture, 1 Aug and 12 Aug 2026

  7. V7
    Verified

    The title, author, branch, enhancement label, absence of review, commit list and the code and changelog changes quoted above, as held in the pull-request and patch captures of 7 August 2026

    Source Captured Coldcard/firmware pull-request page #707 and its separate patch capture, 7 Aug 2026

  8. U8
    Unverified

    Whether any part of this proposal is adopted, and what a released firmware would do at seed generation

    Source No captured source states that #707 or its successor will be merged or shipped as of a 15 August 2026 recheck; firmware PR #713 remains open in the newest held capture (14 Aug 2026, 23:42 UTC) and no new release tag was published

  9. V9
    Verified

    That firmware PR #707 was open at 15:45 UTC and closed at 19:22 UTC on 7 August 2026, that PR #713 opened by the same author with seven commits states that it replaces #707, and that the newest held capture of PR #713 at 23:42 UTC on 14 August 2026 shows it force-pushed to commit 11d8130 as a five-commit series with the revised mash-entropy implementation, testing fixture, disabled MicroPython threads for the unix port, cross-references to PR #691 and #700 and an author self-review comment

    Source Captured Coldcard/firmware pull-request pages #707 and #713 on 7 Aug 2026, and Coldcard/firmware pull-request page #713 on 14 Aug 2026

  10. R10
    Reported

    mutatrum's observation that most coldcard/firmware changes land on master directly or merge without review comments

    Source mutatrum, 2 Aug 2026, preserved as an X capture

  11. R11
    Reported

    The existence, subject and central argument of Dettmer's commit-history walkthrough, including his attribution of the defect's introduction to a 2021 commit and his account of the developer's intent

    Source Dettmer's published analysis and its announcement, both captured 1 Aug 2026

  12. V12
    Verified

    The presence of a second Yasmarang generator inside libngu with the initial state values quoted, its XOR into every output, and the 32-bit assignment in reseed(), as of the pre-merge capture

    Source Captured raw ngu/random.c at switck/libngu master, 1 Aug 2026, lines 47 to 56 and the reseed function

  13. U13
    Unverified

    Whether upstream libngu maintainers were consulted privately before integration

    Source Absence of a public thread is based on a dated search and is weaker evidence than a captured publication

  14. R14
    Reported

    The existence, date and stated purpose of the Delving Bitcoin thread

    Source Delving Bitcoin topic 2768, captured 6 Aug 2026

  15. R15
    Reported

    Bitcoin Optech's statements about coordination, anonymous participation and AI-assisted reproduction

    Source Bitcoin Optech Newsletter #416, published 31 Jul 2026, captured here

  16. R16
    Reported

    The stated rationale and technical findings in the selected Bitcoin.org, SatSigner and SeedSigner repository responses

    Source Captured primary pull-request pages; inclusion does not endorse the projects' technical conclusions

  17. V17
    Verified

    The open, merged or closed-unmerged states and timestamps displayed for the three pull requests

    Source Captured GitHub pull-request metadata checked 1 Aug 2026, rechecked against newer captures 5 Aug 2026

  18. V18
    Verified

    The stated purpose, detection method, review state, author-declared LLM assistance and follow-up comments about warning surfaces and a load-time acknowledgment/MOTD proposal of Sparrow pull request #2047, as displayed in the capture held at 04:42 UTC on 12 August 2026

    Source Captured sparrowwallet/sparrow pull-request page, 12 Aug 2026

  19. R19
    Reported

    notgrubles' question about whether the firmware licence would prevent a long-term-support fork if the company folded

    Source notgrubles, 2 Aug 2026, preserved as an X capture

  20. R20
    Reported

    The community account linking the firmware's Trezor-derived origins and Commons Clause relicensing to the outside-review question

    Source gegelsmr4, 2 Aug 2026, preserved as an X capture

  21. V21
    Verified

    What the Coinkite blog index displayed as of 15 August 2026: the titles and dates of the listed posts, and the absence of a post presented as the promised technical postmortem

    Source Held captures and unchanged index polls of blog.coinkite.com through 15 Aug 2026

  22. U22
    Unverified

    The absence of a located formal Coinkite review, incident-specific CVE, audit announcement and public instagibbs reproduction scripts

    Source Bounded searches of the official Coinkite blog, current firmware repository, NVD (unreachable from this collector) and public instagibbs GitHub surfaces, checked 15 Aug 2026