Defensive-audit findings (adversarially verified + fleet stability-tested):
#4 (CRITICAL) hush_voutupdate trusted an attacker-decoded OP_RETURN length
(opretlen, up to 65535 via OP_PUSHDATA2) with no check against the real script
length, driving up to ~64KB out-of-bounds reads through hush_stateupdate ->
hush_eventadd_opreturn -> hush_kvupdate (persisted to disk, leaked via kvsearch
RPC, reliable crash on block connect). Reject any opret claiming more bytes than
remain in the script, at the single taint source.
#5 (HIGH) notary-ratification loop did memcpy(pubkeys[numvalid++],..) into a
fixed uint8_t[64][33] with no bound; >64 crafted vouts smashed the stack. Clamp
numvalid < 64.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
hush_validate_chain() enters its body when hush_getblockindex(srchash) returns
NULL (via || short-circuit) -- srchash comes from an attacker-controlled
notarization OP_RETURN -- then a debug fprintf dereferenced the NULL pindex.
A block carrying one crafted OP_RETURN tx crashed every synced node on connect,
and crash-looped on restart. Guard the deref: pindex ? GetHeight() : -1.
Introduced by Leto commit 4988ce6f2 ("much debug such wow", 2022).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>