Zebra has block suppression via NU5 same-header body poisoning of sent-hash cache
You are affected if:
zebrad up to and including v4.4.1.network.listen_addr is set, which is the default).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.
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:
inv to the target node.getdata; attacker serves the poisoned body.non_finalized_block_write_sent_hashes before validation.block_commitment_is_valid_for_chain_history (auth_data_root mismatch).non_finalized_block_write_sent_hashes.queue_and_commit_to_non_finalized_state sees the hash in the cache and returns KnownBlock::WriteChannel duplicate.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.
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.
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.
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).
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).
왜 이 VPI인가 (설명가능 · 실험적)
VPI 산정 기준
| 영향도(심각도 등급 추정치) | 80.00 |
| 악용 신호(추가 악용신호 없음) | ×1.00 |
| VPI | 80.00 |
VPI 공식 vpi-v1 기준