Summary
dash-spv does not verify that a downloaded block's body actually matches the merkle root committed in its header before treating that block's transactions as authentic. Block acceptance on the receive path is currently based only on the 80-byte header hash matching a requested/expected hash — the body itself is never re-hashed and checked against header.merkle_root.
Impact
A peer able to serve (or intercept and substitute) a block body alongside its legitimate header — e.g. a malicious or MITM P2P peer — can present a fabricated body containing transactions that were never actually included in that block. Because header identity alone gates acceptance, the fabricated body is processed as authentic all the way through to wallet transaction handling. Depending on how a given consumer of this crate persists derived wallet state, this can translate into incorrect balance/spend tracking that is difficult to distinguish from legitimate activity, and does not self-correct.
This affects every configuration currently shipped by the crate — it is not narrowed by any existing validation toggle, and is not covered by ChainLock, InstantLock, or masternode-quorum verification, none of which authenticate a block's body against its merkle root.
Confirmed independently by three separate reviews, each explicitly tasked with trying to disprove it; all three reached the same conclusion with no narrowing.
Severity
- Critical — block-body/merkle validation is absent on the receive path, unconditionally.
- High — the crate's validation-mode configuration does not affect this behavior in any of its settings, which can give a false impression of protection.
- Medium — the traditional SPV partial-merkle inclusion-proof mechanism is not currently wired into message handling.
- Low (x2) — a couple of related permissive-fallback and unused-gate behaviors adjacent to the above.
Status
Not yet shipped to any tagged/released version — caught during active development, ahead of production exposure. Filing to track the fix; detailed reproduction and exact locations are being shared with maintainers directly rather than posted here, given this is a wallet-correctness/security-relevant gap. Happy to provide full technical detail privately to anyone actively working the fix.
Suggested direction
Validate a received block's body against header.merkle_root before it is queued/forwarded for further processing, at the point where blocks are first accepted off the wire — plus the equivalent check on any storage-reload path, for defense in depth. This is standard practice for Bitcoin-family SPV clients.
🤖 Co-authored by Claudius the Magnificent AI Agent
Summary
dash-spvdoes not verify that a downloaded block's body actually matches the merkle root committed in its header before treating that block's transactions as authentic. Block acceptance on the receive path is currently based only on the 80-byte header hash matching a requested/expected hash — the body itself is never re-hashed and checked againstheader.merkle_root.Impact
A peer able to serve (or intercept and substitute) a block body alongside its legitimate header — e.g. a malicious or MITM P2P peer — can present a fabricated body containing transactions that were never actually included in that block. Because header identity alone gates acceptance, the fabricated body is processed as authentic all the way through to wallet transaction handling. Depending on how a given consumer of this crate persists derived wallet state, this can translate into incorrect balance/spend tracking that is difficult to distinguish from legitimate activity, and does not self-correct.
This affects every configuration currently shipped by the crate — it is not narrowed by any existing validation toggle, and is not covered by ChainLock, InstantLock, or masternode-quorum verification, none of which authenticate a block's body against its merkle root.
Confirmed independently by three separate reviews, each explicitly tasked with trying to disprove it; all three reached the same conclusion with no narrowing.
Severity
Status
Not yet shipped to any tagged/released version — caught during active development, ahead of production exposure. Filing to track the fix; detailed reproduction and exact locations are being shared with maintainers directly rather than posted here, given this is a wallet-correctness/security-relevant gap. Happy to provide full technical detail privately to anyone actively working the fix.
Suggested direction
Validate a received block's body against
header.merkle_rootbefore it is queued/forwarded for further processing, at the point where blocks are first accepted off the wire — plus the equivalent check on any storage-reload path, for defense in depth. This is standard practice for Bitcoin-family SPV clients.🤖 Co-authored by Claudius the Magnificent AI Agent