Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
🦀
🦀 crates.io
Not in CISA KEV
LOW severity

GHSA-443g-gwgp-49x4 zebrad

LOWFix: ZcashFoundation/zebra#10570

GHSA-443g-gwgp-49x4 is a low-severity (CVSS 3.7) remote code execution vulnerability in zebrad. A fix is available for zebrad — see the affected versions and patch details below.

zebrad vulnerable to getblocks/getheaders locator CPU amplification via uncapped vector length

Published
Jul 2, 2026
Updated
Jul 2, 2026
Affected
2 pkgs
Patched
2 / 2
Exploits
None indexed
Exploitation data as of Jul 2, 2026 · OSV.dev, FIRST.org (EPSS)

Real-World Exposure

2 pkgs affected
🦀zebrad🦀zebra-chain

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects crates.io packages — download data is not available via public APIs for these ecosystems.

Description

Am I affected

You are affected if:

  1. You run zebrad up to and including v4.4.1.
  2. 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.

Affected Packages

2 total 2 fixed
EcosystemPackageVulnerable rangeFix
🦀crates.iozebradall versions4.5.0cargo update -p zebrad --precise 4.5.0
🦀crates.iozebra-chainall versions8.0.0cargo update -p zebra-chain --precise 8.0.0

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for zebrad, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update zebrad to 4.5.0 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-443g-gwgp-49x4 is resolved across your whole dependency graph.

  3. Workarounds

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

  4. How O3 protects you

    O3 Security's impact-aware SCA analyses which vulnerable code paths your application actually calls, so a match like GHSA-443g-gwgp-49x4 can be triaged on real exposure rather than presence alone.

Tailored to GHSA-443g-gwgp-49x4. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.

Frequently Asked Questions

### Am I affected You are affected if: 1. You run `zebrad` up to and including `v4.4.1`. 2. 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
O3 Security · Impact-Aware SCA

Is GHSA-443g-gwgp-49x4 in your dependencies?

O3 Security finds GHSA-443g-gwgp-49x4 across crates.io dependencies, including transitive ones, and its impact-aware SCA ranks findings by whether your code actually calls the vulnerable path.

GHSA-443g-gwgp-49x4: zebrad (Low 3.7) | O3 Security