OpenSourceCheck

OSC-2026-0012 · github.com/diybitcoinhardware/embit

info clean-run claude-fable-5 2026-08-04 signed: nostr

Repository
github.com/diybitcoinhardware/embit
Commit
fff7ffa43f6ce088c5ba22cb3877a122bf01dc96
Scope path
src/embit/psbt.py
Model
claude-fable-5
Harness
claude-code
Prompts
prompts/tx-authorization-audit-v1.md
Independent runs
1
Transcript sha256
31012b8bee42811662926b43afa565c398659e261e3269db6875c11ebb6d0afb
Auditor
TheIcarusWings (theicaruswings)
Signature
nostr-schnorr · npub19tzp8lf3klmqj3dz9mz0qnuvjp7uyy9993gmljmyaxs8phztj7wsnujvq5

Scope. Transaction-authorization loss-of-funds class at HEAD fff7ffa4 - second lens on the target audited for signing nonces in OSC-2026-0004. In scope: whether the library performs change-output verification, what fee-attack protection it offers and whether that is opt-in, and PSBT parser robustness on hostile input. NOT in scope: display logic (none), firmware update integrity (none), and the downstream applications that consume this library.

Findings

info OSC-2026-0012-F1 unreviewed

No defect found in scope; the central check is not applicable BY DESIGN, and that is the point of the record. Searching all of src/embit/ for is_mine, is_change, change_index or change_derivation returns no matches: embit is a general-purpose PSBT library, not a wallet, and correctly leaves 'is this output mine' to the application. It is recorded because that responsibility is easy to assume someone else has taken - embit is the PSBT layer beneath SeedSigner, Specter-DIY and other DIY signers, and any integrator assuming embit validates change for them has a fund-loss bug in their own code. embit DOES provide InputScope.verify() (psbt.py:226), whose docstring names the Trezor miner-fee attack directly, but it is OPT-IN: PSBT.utxo(i) (:691) does not call it and prefers witness_utxo gated only on caller-set state, and PSBT.fee() (:702) sums values without forcing verification - so a consumer that never calls verify() gets no fee-attack protection, which OSC-2026-0009 records is the case for SeedSigner. Parser robustness is sound: read_string bounds-checks length-prefixed reads (:33-38), duplicate keys are rejected globally and per-scope, and the PSBT magic is validated before parsing; psbtview.py documents a time-of-check/time-of-use hazard with untrusted SD media in its module docstring.

src/embit/psbt.py:226 (verify, opt-in), :691 (utxo), :702 (fee), :33 (read_string bounds check) · CWE-655