OpenSourceCheck

OSC-2026-0001 · github.com/Coldcard/firmware

critical findings-validated claude-fable-5 2026-08-04 signed: nostr

Repository
github.com/Coldcard/firmware
Commit
bcc2c382a324690a2fcf972c0bac3b79bf923f7b
Scope path
stm32/COLDCARD/
Model
claude-fable-5
Harness
claude-code
Prompts
prompts/entropy-rng-audit-v1.md
Independent runs
1
Transcript sha256
7e7330c5a5a78ddc12401eb9eb8b7b1d5f3fca97b4f90491ee12fc9166c0a41b
Auditor
TheIcarusWings (theicaruswings)
Signature
nostr-schnorr · npub19tzp8lf3klmqj3dz9mz0qnuvjp7uyy9993gmljmyaxs8phztj7wsnujvq5

Scope. Retrospective, source-grounded audit of the publicly-disclosed Coldcard seed-entropy vulnerability at the last vulnerable commit (bcc2c382, parent of the fix ca724637). In scope: entropy/RNG code paths feeding BIP-39 seed generation on STM32 builds; TRNG-vs-software-PRNG selection; build-time RNG symbol linkage. NOT in scope: PIN/secure-element logic, PSBT handling, USB stack. The ngu.random->C rng_get binding lives in an unfetched submodule and is inferred from the fix's symbol-level assertions plus the Python call sites (confidence: high).

Findings

critical OSC-2026-0001-F1 validated

BIP-39 seed generation draws from a software PRNG instead of the STM32 hardware TRNG. The board file stm32/COLDCARD/rng.c exports the hardware reader only as static rng_get_or_fault() and never defines a global rng_get(); the linker therefore resolves rng_get() to MicroPython's upstream ports/stm32/rng.c, whose implementation falls back to the Yasmarang software PRNG (pyb_rng_yasmarang). Seed material generated via ngu.random (shared/seed.py:605 `seed = ngu.random.bytes(32)`) is thereby drawn from a weak PRNG, cutting effective Mk2/Mk3 seed entropy from 128 bits to ~40 bits (brute-forceable). Confirmed by the fix commit ca724637, which adds a board-level rng_get() wrapping the TRNG, poisons pyb_rng_yasmarang, and adds an arm-none-eabi-nm build-time symbol check asserting the correct rng_get is linked.

stm32/COLDCARD/rng.c (missing global rng_get); consumer shared/seed.py:605 · CWE-338

Validated by theicaruswings — Validated against source: read the fix diff ca72463709f4e3f8964952039d5caf955f566a87 and the pre-fix tree bcc2c382a324690a2fcf972c0bac3b79bf923f7b. Consistent with Coinkite's advisory (2026-07-31) and Block Engineering's independent analysis. See transcripts/OSC-2026-0001.md for full reproduction steps.