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.
| 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=1or an explicitly declared externalrng_get(), requires an explicit ESP32 attestation, usesgetrandom(2)on Linux andarc4random()on macOS and FreeBSD, refuses thread-enabled builds without a GIL, corrects the rejection mask inuniform(), 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()inshared/seed.pypreviously 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 theustruct.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
libngusubmodule 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 anNGU_STM32_EXTERNAL_RNG_GETmacro; 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
| Venue | Record 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
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.
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.
| 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
- V1 Verified · contested
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
Evidence → captured
- V2 Verified · contested
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
Evidence → captured
- V3 Verified · contested
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
Evidence → captured
- R4 Reported · contested
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
Evidence → captured
- R5 Reported · contested
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
Evidence → captured
- V6 Verified · contested
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
Evidence → captured
- V7 Verified · contested
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
Evidence → captured
- U8 Unverified · contested
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
Evidence → captured
- V9 Verified · contested
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
Evidence → captured
- R10 Reported · contested
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
Evidence → captured
- R11 Reported · contested
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
Evidence → captured
- V12 Verified · contested
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
Evidence → captured
- U13 Unverified · contested
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
Evidence → captured
- R14 Reported · contested
The existence, date and stated purpose of the Delving Bitcoin thread
Source Delving Bitcoin topic 2768, captured 6 Aug 2026
Evidence → captured
- R15 Reported · contested
Bitcoin Optech's statements about coordination, anonymous participation and AI-assisted reproduction
Source Bitcoin Optech Newsletter #416, published 31 Jul 2026, captured here
Evidence → captured
- R16 Reported · contested
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
Evidence → captured 1 Aug 2026
- V17 Verified · contested
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
Evidence → captured
- V18 Verified · contested
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
Evidence → captured
- R19 Reported · contested
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
Evidence → captured
- R20 Reported · contested
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
Evidence → captured
- V21 Verified · contested
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
Evidence → captured
- U22 Unverified · contested
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
Evidence → captured