Repository navigation
Muse audit public findings 10/17/2026 #1062
Description
Audit's done. Most important thing first: the 3 "Critical" consensus-split bugs from the early signal did not survive verification. I diffed each against actual Bitcoin Core source before writing anything up — Core pre-scans for OP_SUCCESS in tapscript exactly like rbitcoin does, Core has no pre-fExec gate for OP_RESERVED, and Core's disabled-opcode check sits pre-fExec just like rbitcoin's. All three were false positives, and I've documented exactly why so you don't report bunk.
The real findings that replaced them: rbitcoin wrongly pre-fails OP_VERIF/OP_VERNOTIF in dead branches (Core skips them — fail-closed chain stall, High), wrongly requires a witness commitment whenever witness data exists without one (High, fail-closed), and its signature-encoding check omits Core's sighash-byte range check (Medium, latent). Plus 13 remote-DoS items and 6 store-integrity items, all with file:line evidence.
Here's your paste-ready public issue (non-sensitive only — the sensitive ones are in the attached private notes for your direct contact):
Audit notes: hardening, hygiene, and process gaps (non-consensus)
Independent read-only audit of master at 4e2a813 (~300k lines / 16 crates).
Static review only — no builds, no live infrastructure. Method: per-area deep
dives (consensus/script, P2P, store, primitives/crypto, mempool, RPC/Electrum/
Esplora/SV2, supply chain), each finding carries file:line evidence.
A small number of consensus-critical and remotely-triggerable findings are
being reported privately per SECURITY.md and are deliberately absent here.
What follows is the non-sensitive remainder: process, hygiene, hardening, and
defense-in-depth. No fund-loss or RCE paths were found (there is no wallet
crate; fund-moving RPCs are explicitly refused).
Verified clean (with reasoning): primitives/crypto (SIMD sound, no hand-rolled
crypto — uses bitcoin_hashes); P2P framing, IBD header validation, compact
blocks, rate limiting; store io_uring completion safety; mempool fee floors and
eviction ordering. Strongest positives: differential fuzzing against live
bitcoind oracles, CodeQL security-extended on PRs, 93% coverage gate,
clippy -D warnings, all 156 registry deps checksummed.
Supply chain & CI process
S1 — deny.toml bans are permissive. [bans] multiple-versions = "warn",
wildcards = "allow", deny = []. The lockfile shows what warn tolerates:
secp256k1 0.28.2 + 0.29.1 (two secp256k1-sys C builds), bitcoin_hashes
0.13/0.14/0.16, hex-conservative ×4, getrandom 0.2 + 0.4. Duplicate C builds
widen the patched surface ("patch one, miss the other"). Suggest
multiple-versions = "deny" with explicit skips, wildcards = "deny".
S2 — Fuzzing is nightly-cron only, not a PR gate.
.github/workflows/fuzz.yml — nightly/weekly libFuzzer, not a required check;
same for miri.yml (primitives only) and core-functional.yml. A
consensus-changing PR can merge with zero fuzz signal. Suggest a short
(60–120s) per-target PR job, or at minimum replaying fuzz/corpus as a
regression gate.
S3 — No sanitizer coverage in CI; Miri covers only primitives. No
ASan/TSan/UBSan jobs; rbitcoin-store has the largest unsafe surface and never
runs under Miri/sanitizers. Suggest nightly ASan+UBSan for store/net suites.
S4 — mutants proc-macro in [dependencies], not dev-deps
(crates/rbitcoin-consensus/Cargo.toml:15-16,
crates/rbitcoin-query/Cargo.toml:17-18). Third-party proc-macro compiled into
production builds for zero runtime effect. Move to dev-dependencies.
S5 — BIP324 v2 transport depends on an unmaintained AEAD crate.
Cargo.lock: bip324 0.11.0 → chacha20-poly1305 0.1.2 (Dec 2019,
superseded by chacha20poly1305 0.10.x). P2P is v2-only per SECURITY.md, so
all peer-traffic AEAD rests on code that will never receive a security patch.
No known vulnerability — structural risk. Suggest upgrading bip324 to a
release on chacha20poly1305 0.10 (or vendoring) and tracking it in
deny.toml.
S6 — SECURITY.md Scope omits the script-skip milestone. "Consensus and
script: pure-Rust verification" is promised without mentioning that the default
build skips script/sig checks below block 840000 (anchored milestone). The skip
is documented in the README/OPERATOR.md, but not in the security policy.
Suggest a "Validation caveats" note in SECURITY.md.
S7 — min_work_be in MilestoneAnchor is stored but never enforced
(crates/rbitcoin-consensus/src/milestone.rs). Documented as a "chain work
floor (Core nMinimumChainWork shape)"; nothing reads the field. Either
enforce it or remove it — a dead security-looking field invites wrong
assumptions.
S8 — 356 unwrap/expect in non-test consensus code. Spot-checked sites
are guarded, but suggest an ast-grep rule flagging new ones (CI already runs
ast-grep). Consider #![forbid(unsafe_code)] on the zero-unsafe crates
(mempool, electrum, cli, rpc, test) to lock in the current state.
Hardening gaps (defense-in-depth, not directly exploitable)
H1 — No absolute fee cap (-maxtxfee equivalent).
crates/rbitcoin-mempool/src/accept.rs. A fat-fingered multi-BTC fee is
admitted, relayed, and would be mined. Sender-confined loss; still cheap to add.
H2 — No MAX_MONEY range check on the mempool admission path
(accept.rs:365 checks overflow but not range). Values trace to validated
UTXOs, so not practically exploitable — defense-in-depth only.
H3 — Silent-payments hand-rolled EC has no fuzz target.
crates/rbitcoin-consensus/src/silent_payments.rs implements BIP-352 tweak
math by hand (combine_keys + mul_tweak), reachable from the Electrum serve
path with attacker-influenced txouts. 21 fuzz targets exist but none cover it.
Suggest a differential target vs a reference implementation.
H4 — Esplora: no CORS ACAO, GET /broadcast without Origin/Host checks
(crates/rbitcoin-esplora/src/server.rs:819). Restrictive default, but simple
cross-origin requests (e.g. <img> GET) aren't stopped by CORS. Remove
GET /broadcast; validate Origin/Host on POST /tx.
H5 — --sv2-tp-authority-sec on the command line is visible in ps;
a -file variant exists — nudge it in the docs.
H6 — RPC cookie file that is group/world-readable warns instead of
refusing (crates/rbitcoin-rpc/src/auth.rs).
Minor notes
rbitcoin-primitives/src/merkle.rs:16-30: mutation predicate stricter than
Core (any equal adjacent pair vs tail-only) — not practically exploitable.rbitcoin-primitives/src/compact.rs:44-70:read_compact_sizeaccepts
non-canonical encodings; no wire consumer today — add a doc warning or a
strict variant.rbitcoin-primitives/src/scriptnum.rs:25-30:scriptnum_encode(i64::MIN)
panics in debug;scriptnum_decode_widthtrusts callermax_len ≤ 8—
add a debug_assert.rbitcoin-primitives/src/loc_simd.rs: aarch64 NEONtarget_featureon
callees not callers — sound (NEON mandatory on AArch64), propagate for
hygiene.rbitcoin-primitives/src/lib.rs:198-208:Network::parserejects
testnet4(functional gap).rbitcoin-store:readonly_map.rsTOCTOU betweenmetadata().len()and
mmap(external truncate → SIGBUS);store.secretXOR is
obfuscation-at-rest, not encryption (documented — fine).rbitcoin-net/src/seeds.rs:135-157: DNS seed results not filtered for
bogons;:307-320: flat 8192-entry AddrMan (no new/tried buckets),
mitigated by asmap-diverse selection.rbitcoin-net/src/chain.rs:174-186,372: unboundedInvalidatedset /
fork_tips— every entry costs the attacker a valid-PoW block
(hashpower-bounded); consider a cap+FIFO anyway.rbitcoin-consensus/src/script/interpreter.rs:108:
uses_segwit_serializationmisclassifies zero-input txs; unreachable in
consensus (check_tx_localrejects empty inputs first) — defense-in-depth.
Coverage limits (honest)
No builds or test runs (no cargo toolchain in this environment); all findings
are manual static analysis. Bitcoin Core behaviors cited were diffed against
current Core source (src/script/interpreter.cpp,
src/validation.cpp). Skimmed rather than deeply reviewed: tx_relay.rs,
bip324 internals, parts of ibd/, SH build pipeline, fee-estimation math,
rbitcoin-node wiring, test/bench/log crates.
The private findings (2 High consensus + 1 Medium consensus + 1 milestone footgun + 13 DoS + 6 store-integrity, plus the false-positive corrections) are in the attached notes for your direct contact — kept out of the issue per the repo's disclosure policy.
Activity
reardencode commentedon Oct 18, 2026
looking into these, thank you!
rearden-grok commentedon Oct 18, 2026
#1074 is the follow-up for the items that were not already in another PR.
The cookie file refuses a mode wider than
--rpc-cookie-perms(see #1060).cargo denyfails a new duplicate crate.mutantsis an optional feature so the proc-macro is off in a normal node build. Seed inject and addr gossip drop unroutable clearnet addresses;addpeeraddressand--connectdo not. Fork-tip hints are capped at 64. Invalidated hashes stay uncapped.P2P still has no absurd-fee cap, mempool fee math still checks
u64overflow rather thanMAX_MONEY, and BIP324 stays on thechacha20-poly13050.1 that upstreambip3240.11 links. Those are recorded in COMPAT.md, TESTING.md, and SECURITY.md. Fuzz stays a nightly job. A Sunday UBSan run coversasmapandblock_wireonly.