Summary
Description
Am I affected
You are affected if:
- You run any version of
zebradup to and includingv4.4.1. - Your node accepts inbound P2P connections (
network.listen_addris set, which is the default). - Your node processes blocks past the checkpoint height (non-finalized state is active).
All default configurations are affected.
Zebra records a block hash in non_finalized_block_write_sent_hashes when the block is sent to the write task, before contextual validation completes. If validation fails, the hash is not removed. A remote unauthenticated peer can deliver a poisoned block body that shares a header hash with a later valid canonical block. The poisoned body is rejected, but the hash remains cached. When the valid canonical block arrives, Zebra treats it as a duplicate and rejects it. The node cannot advance past that height until restart or a reorg event.
Details
ZIP-244 defines txid_v5 without binding transparent input scriptSig, which lives in auth_digest and is committed to by hashBlockCommitments in the block header. Because merkle_root is computed over txids (not auth digests), and the block hash is computed over the header, an attacker can construct two blocks with identical header hashes but different transaction bodies by mutating the coinbase scriptSig.
The attack flow over P2P:
- Attacker observes a new block header (from any peer).
- Attacker constructs a poisoned body by flipping a byte of the coinbase scriptSig extra-data section. The block hash is unchanged.
- Attacker advertises the block hash via
invto the target node. - Target requests the block via
getdata; attacker serves the poisoned body. - Zebra adds the hash to
non_finalized_block_write_sent_hashesbefore validation. - The write task rejects the body at
block_commitment_is_valid_for_chain_history(auth_data_root mismatch). - The hash is not removed from
non_finalized_block_write_sent_hashes. - When the valid canonical block arrives (from honest peers or RPC),
queue_and_commit_to_non_finalized_statesees the hash in the cache and returnsKnownBlock::WriteChannelduplicate. - The node is stuck at height N-1.
A secondary variant exists where chain pruning (via MAX_NON_FINALIZED_CHAIN_FORKS) removes a chain from chain_set but leaves its block hashes in non_finalized_block_write_sent_hashes, producing the same lockout for children of the pruned fork.
Workarounds
There is no complete configuration-level workaround. Reducing the node's inbound peer count (network.peerset_initial_target_size) narrows the attack surface but does not eliminate it. Restarting the node clears the in-memory cache and allows the valid block to be re-fetched.
Credit
Reported independently by @ipwning (primary, with ZIP-244 malleability analysis and zcashd cross-reference) and @x15-eth (first reporter, with E2E reproduction and control experiment).
Impact
A remote unauthenticated P2P peer can permanently stall a targeted Zebra node at a specific block height. The node diverges from the network tip; downstream consumers (lightwalletd, wallets, explorers, mining infrastructure) relying on the node see a stalled chain. The attack requires winning a propagation race: delivering the poisoned block body before honest peers deliver the canonical block. A well-positioned attacker (low-latency connection to the target, observation of new blocks from other peers) can reliably win this race. In sustained form, the attacker repeats for each new block, keeping the target permanently behind.
Recovery requires restarting the node (which clears the in-memory sent-hash cache) or waiting for a reorg at the affected height (rare on the canonical chain).
Affected versions
Security releases
Kodem intelligence
Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.
Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.
Remediation advice
Patched in Zebra 4.4.2. The fix removes stale entries from non_finalized_block_write_sent_hashes on every failed non-finalized write path.
Frequently Asked Questions
- What is CVE-2026-52736? CVE-2026-52736 is a high-severity security vulnerability in zebra-state (rust), affecting versions <= 6.0.0. It is fixed in 7.0.0, 4.5.0.
- Which packages are affected by CVE-2026-52736?
zebra-state(rust) (versions <= 6.0.0)zebrad(rust) (versions <= 4.4.1)
- Is there a fix for CVE-2026-52736? Yes. CVE-2026-52736 is fixed in 7.0.0, 4.5.0. Upgrade to this version or later.
- Is CVE-2026-52736 exploitable, and should I be worried? Whether CVE-2026-52736 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
- What actually determines whether CVE-2026-52736 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
- How do I fix CVE-2026-52736?
- Upgrade
zebra-stateto 7.0.0 or later - Upgrade
zebradto 4.5.0 or later
- Upgrade