GHSA-65jj-fmw8-468q CVE-2026-52734
zebrad has unbounded memory leak in mempool download pipeline via timeout path cancel_handles retention
- Severity
- 5.3 / 10
- Medium · CVSS 3.1
- Exploit chance (EPSS)
- 0.51%
- Chance of exploitation in the next 30 days. Higher than 43.26% of scored vulnerabilities.
- Known exploited
- No
- Not in CISA's catalog
- Weakness
- CWE-401 Missing Release of Memory after Effective Lifetime
- Fix
4.5.0- Upgrade zebrad to this version or later
Description
Am I affected
You are affected if:
- You run
zebradup to and includingv4.4.1. - Your node accepts inbound P2P connections (
network.listen_addris set, which is the default). - Your node's mempool is active (node is synced near the chain tip).
All default configurations are affected.
Summary
The mempool download pipeline's cancel_handles map retains entries for transactions whose verification times out at the outer RATE_LIMIT_DELAY (73-second) boundary. The tokio::time::error::Elapsed error carries no payload, so the transaction ID is unrecoverable and the corresponding cancel_handles entry (including the full Gossip::Tx(UnminedTx), up to ~2 MB) is never removed. Entries accumulate monotonically with no upper bound or garbage collection, leading to eventual out-of-memory process termination.
Details
Downloads::poll_next() at zebrad/src/components/mempool/downloads.rs:215-228 handles three terminal states for a verification task:
Ok(Ok(...)): success. Callscancel_handles.remove(&tx.transaction.id). Correct.Ok(Err(...)): verification error. Callscancel_handles.remove(&hash). Correct.Err(elapsed): outer timeout. ReturnsErr(elapsed)without removing anything. Bug.
tokio::time::error::Elapsed has no payload, so the timed-out transaction's UnminedTxId is unrecoverable from the error. The consumer at zebrad/src/components/mempool.rs:663-672 explicitly acknowledges this gap with a TODO comment.
The only cleanup paths for cancel_handles are cancel(mined_ids) (removes entries matching mined transaction IDs; attacker transactions are never mined) and cancel_all() (clears everything on shutdown or chain reset). No periodic GC, no time-based eviction, and no count cap exists.
For direct tx pushes (Gossip::Tx), the retained entry holds the full deserialized transaction, which can be up to ~9 MB in memory for a transaction near the transparent-output extreme. Per-connection leak rate at worst case: ~685 KB/s (~2.4 GB/hour).
Patches
The fix preserves the UnminedTxId through the timeout error path: wrap the timeout future so the spawned task's outer error carries the txid (e.g., Err((txid, elapsed))). In Downloads::poll_next(), on the timeout arm, call cancel_handles.remove(&txid).
Workarounds
There is no configuration-level workaround. Restarting the node clears the accumulated entries. Operators running in memory-constrained environments (containers with cgroup limits) may see the process killed by the OOM killer before natural recovery.
Impact
Gradual, unbounded memory exhaustion of a Zebra node from unauthenticated P2P traffic. The leak is monotonic (entries are never freed under normal operation) but slow (~685 KB/s per connection worst case). An attacker must sustain traffic for hours to exhaust typical server memory. The node continues operating normally until memory pressure becomes critical, at which point the OS OOM killer terminates the process or the node degrades due to swap pressure. No consensus impact, no fund loss, no on-disk corruption.
Credit
Reported by @AnticsDecoded via a private GitHub Security Advisory submission. Working E2E reproduction on a live regtest node with staged parent/child transaction dependencies.
Affected versions
crates.io
| Package | Vulnerable | Fixed in |
|---|---|---|
| zebrad | < 4.5.0 |
4.5.0 |
How to fix
Move to the fixed version or later with your package manager, update the lockfile, and run your tests. If the package only arrives through another dependency, upgrade that dependency first. If none of its releases pulls a fixed version yet, force the version with your package manager's override.
zebrad crates.io → 4.5.0
- cargo
cargo update -p zebrad --precise 4.5.0
Severity breakdown
CVSS 3.1 5.3
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L
- Attack vector
- Network
- Attack complexity
- Low
- Privileges required
- None
- User interaction
- None
- Scope
- Unchanged
- Confidentiality
- None
- Integrity
- None
- Availability
- Low
Weakness
CWE-401: Missing Release of Memory after Effective Lifetime
The product does not sufficiently track and release allocated memory after it has been used, making the memory unavailable for reallocation and reuse.
How to prevent it
- Implementation: Choose a language or tool that provides automatic memory management, or makes manual memory management less error-prone. For example, glibc in Linux provides protection against free of invalid pointers. When using Xcode to target OS X or iOS, enable automatic reference counting (ARC) [REF-391]. To help correctly and consistently manage memory when programming in C++, consider using a smart pointer class such as std::auto_ptr (defined by ISO/IEC ISO/IEC 14882:2003), std::shared_ptr and std::unique_ptr (specified by an upcoming revision of the C++ standard, informally referred to as C++ 1x), or equivalent solutions such as Boost.
- Architecture and Design: Use an abstraction library to abstract away risky APIs. Not a complete solution.
- Architecture and Design, Build and Compilation: Consider using the Boehm-Demers-Weiser garbage collector (bdwgc), which can help avoid leaks.
References
Packages
Other links
- github.com/ZcashFoundation/zebra/security/advisories/GHSA-65jj-fmw8-468q
- github.com/ZcashFoundation/zebra/blob/d4cd662c716382f6397d2a730148025a1ca79fec/…
- github.com/ZcashFoundation/zebra/blob/d4cd662c716382f6397d2a730148025a1ca79fec/…
- github.com/ZcashFoundation/zebra/commit/1440b43ca7df59aca948090d45117557b217a6cd
- github.com/ZcashFoundation/zebra/releases/tag/v4.5.0
Timeline
- Published
- Last updated by the source
- Latest EPSS score
Related advisories
| Advisory | Severity | Why it's related |
|---|---|---|
| GHSA-ww9q-8r59-xv46 Zebra: Missing copy constraint in halo2_gadgets variable-base scalar multiplication allows under-constrained base, breaking Orchard Action circuit soundness | Critical | Also affects zebrad |
| GHSA-63wg-wjjj-7cp8 Zebra Address Book Aborted by IPv4-Mapped Mempool Misbehavior Update | High | Also affects zebrad |
| GHSA-2gf8-q9rr-jq3h zebrad has persistent on-disk corruption of Sapling/Orchard subtree roots after chain fork via pop_tip | Medium | Also affects zebrad |
| GHSA-hhm7-qrv5-h4r6 Zebra: Repeated Non-Finalized Shielded Transaction Aborts Zebra Before Duplicate-Nullifier Rejection | Medium | Also affects zebrad |
| GHSA-w834-cf6p-9m9w Zebra: Finalized address balance credit-first overflow on consensus-valid blocks | Medium | Also affects zebrad |
| GHSA-gvjc-3w7c-92jx Zebra has sync restart poisoning from single unauthenticated peer via above-lookahead block | Medium | Also affects zebrad |
| GHSA-gf9r-m956-97qx zebrad has consensus divergence via P2SH sigop undercount in pure-Rust disabled-opcode parser | Critical | Also affects zebrad |
| GHSA-4m69-67m6-prqp Zebra has block suppression via NU5 same-header body poisoning of sent-hash cache | High | Also affects zebrad |
MergeHarbor checks every repository's dependencies against this database, ranks what matters by exploitability and reachability, routes it to the owning team and opens the fix pull request.
Check your repos with MergeHarbor