Skip to content

dash-spv accepts block bodies without verifying merkle root against header #852

Description

@Claudius-Maginificent

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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions