Am I affected
You are affected if:
- You run
zebrad up to and including v4.4.1.
- Your node accepts inbound P2P connections.
Summary
The read_getblocks and read_getheaders codec paths accepted block locator vectors up to approximately 65,535 entries (the generic TrustedPreallocate ceiling derived from MAX_PROTOCOL_MESSAGE_LEN), rather than the protocol-specification limit of 101 entries (matching zcashd's MAX_LOCATOR_SZ). Each entry in the locator vector triggers a per-hash chain lookup (HashMap::contains_key + RocksDB::contains_hash) in find_chain_intersection on a tokio blocking-pool thread.
A single maximally-sized getblocks message occupies one blocking-pool thread for approximately 10–65ms. Under sustained load from multiple peers, this can degrade state-read performance for block validation, RPC, and mempool lookups.
Details
The read_headers codec path already implements the correct pattern: it reads the CompactSize count, validates against MAX_HEADERS_PER_MESSAGE = 160 before deserialization, and rejects oversized messages. The read_getblocks and read_getheaders paths were missing this pre-deserialization count check and instead relied on the generic block::Hash::max_allocation() bound, which allows (MAX_PROTOCOL_MESSAGE_LEN - 1) / 32 = 65,535 hashes.
A legitimate block locator is logarithmic in chain length (approximately 30 hashes for the current ~3M-block Zcash chain). Zebra's own send-side cap is MAX_FIND_BLOCK_HASHES_RESULTS = 500.
The practical impact requires significant attacker bandwidth (approximately 2 MiB per request) and multiple Sybil peers to meaningfully degrade the blocking pool, which limits real-world exploitability.
Patches
Patched in Zebra 4.4.2. The fix caps block::Hash::max_allocation() at MAX_BLOCK_LOCATOR_LENGTH = 101, matching zcashd's MAX_LOCATOR_SZ. This causes the deserializer to reject oversized locators before any allocation or iteration occurs.
Workarounds
No specific workaround is needed. Existing backpressure mechanisms (load shedding, sequential per-peer message processing, connection limits) constrain the practical impact.
Impact
Under sustained load from multiple Sybil peers, oversized locator vectors can occupy blocking-pool threads and degrade state-read performance. The effect is bounded by connection limits and requires significant attacker bandwidth.
Credit
Vulnerability identified by @dingledropper, who submitted the fix in PR #10570. Downstream CPU/blocking-pool impact analysis contributed by @ouicate.
References
Am I affected
You are affected if:
zebradup to and includingv4.4.1.Summary
The
read_getblocksandread_getheaderscodec paths accepted block locator vectors up to approximately 65,535 entries (the genericTrustedPreallocateceiling derived fromMAX_PROTOCOL_MESSAGE_LEN), rather than the protocol-specification limit of 101 entries (matching zcashd'sMAX_LOCATOR_SZ). Each entry in the locator vector triggers a per-hash chain lookup (HashMap::contains_key+RocksDB::contains_hash) infind_chain_intersectionon a tokio blocking-pool thread.A single maximally-sized
getblocksmessage occupies one blocking-pool thread for approximately 10–65ms. Under sustained load from multiple peers, this can degrade state-read performance for block validation, RPC, and mempool lookups.Details
The
read_headerscodec path already implements the correct pattern: it reads the CompactSize count, validates againstMAX_HEADERS_PER_MESSAGE = 160before deserialization, and rejects oversized messages. Theread_getblocksandread_getheaderspaths were missing this pre-deserialization count check and instead relied on the genericblock::Hash::max_allocation()bound, which allows(MAX_PROTOCOL_MESSAGE_LEN - 1) / 32 = 65,535hashes.A legitimate block locator is logarithmic in chain length (approximately 30 hashes for the current ~3M-block Zcash chain). Zebra's own send-side cap is
MAX_FIND_BLOCK_HASHES_RESULTS = 500.The practical impact requires significant attacker bandwidth (approximately 2 MiB per request) and multiple Sybil peers to meaningfully degrade the blocking pool, which limits real-world exploitability.
Patches
Patched in Zebra 4.4.2. The fix caps
block::Hash::max_allocation()atMAX_BLOCK_LOCATOR_LENGTH = 101, matching zcashd'sMAX_LOCATOR_SZ. This causes the deserializer to reject oversized locators before any allocation or iteration occurs.Workarounds
No specific workaround is needed. Existing backpressure mechanisms (load shedding, sequential per-peer message processing, connection limits) constrain the practical impact.
Impact
Under sustained load from multiple Sybil peers, oversized locator vectors can occupy blocking-pool threads and degrade state-read performance. The effect is bounded by connection limits and requires significant attacker bandwidth.
Credit
Vulnerability identified by
@dingledropper, who submitted the fix in PR #10570. Downstream CPU/blocking-pool impact analysis contributed by@ouicate.References