Skip to content

protocol

Zcash Zebra 4.5.0 patches P2SH sigop bug that risked chain split

Zcash Foundation ships Zebra 4.5.0 plus a 4.5.1 hotfix, closing 15 advisories including a critical P2SH disabled-opcode sigop undercount that could split the chain.

by 5 min read

The Zcash Foundation released Zebra 4.5.0 on May 29, 2026, closing 15 GitHub security advisories disclosed the same day, then shipped a 4.5.1 hotfix hours later because the patch for the most severe bug — a critical P2SH signature-operation undercount that could split the Zcash chain — was itself incomplete. Node operators on zebrad ≤ 4.4.1 are urged to upgrade directly to 4.5.1. The release notes and advisories are public on the ZcashFoundation/zebra repository.

What shipped

The 4.5.0 release notes (v4.5.0 on GitHub) recommend node operators "update to 4.5.0 as soon as possible." Fifteen advisories were published the same day. The single critical one was GHSA-gf9r-m956-97qx — "Consensus divergence via P2SH sigop undercount in pure-Rust disabled-opcode parser." Within hours, 4.5.1 followed (v4.5.1 on GitHub), with a one-line summary: "The last P2SH input sigop count fix was incorrect. Properly fixed it to match zcashd."

A second critical, GHSA-h9hm-m2xj-4rq9 — "Permanent Block Discovery Halt via Gossip Queue Saturation" — was disclosed earlier on May 5 and is also folded into the 4.5.x branch.

Mechanism — sigop counting that didn't match zcashd

The critical advisory targets zebra-script/src/lib.rs:399. Zebra's P2SH validation walks redeem scripts with a pure-Rust parser; that parser's try_fold halts the first time it hits a disabled opcode (e.g. OP_CODESEPARATOR), returning an incomplete signature-operation count. The reference C++ implementation, zcashd, calls GetSigOpCount, which keeps counting through disabled opcodes during static analysis and only rejects them at execution time.

Result: a redeem script that contains a disabled opcode followed by signature-checking ops can produce a block whose total sigops exceeds MAX_BLOCK_SIGOPS = 20,000 on the zcashd accounting but stays under the limit on Zebra. Zebra accepts the block. zcashd rejects it with bad-blk-sigops. Two cohorts of nodes now disagree on the tip, and per the advisory, "every subsequent block extending the Zebra-side tip inherits the divergence."

The attack requires no mining capability and no special permissions — only transaction fees to land the crafted P2SH input. Affected: zebra-script ≤ 6.0.1 and zebrad ≤ 4.4.1. Patched in zebra-script 7.0.0 and zebrad 4.5.0 — with the caveat that the first attempt did not fully match zcashd semantics and was reissued in 4.5.1.

The other 13 advisories

The rest of the May 29 batch leans toward denial-of-service and peer-handling defects rather than consensus splits. The high-severity ones:

  • GHSA-4m69-67m6-prqp — rejected block hashes retained in SentHashes, letting an attacker short-circuit honest re-deliveries as duplicates.
  • GHSA-w834-cf6p-9m9w — finalized address-balance credit-first overflow that could halt the node permanently on restart.
  • GHSA-63wg-wjjj-7cp8 — IPv4-mapped peer addresses that aborted Zebra's address-book updates.

Moderates cover mempool memory leaks (GHSA-65jj-fmw8-468q, ~2 MB per queued transaction), sync restart poisoning by a single unauthenticated peer, repeated shielded-transaction panics, persistent on-disk corruption of Sapling/Orchard subtree roots after forks, and uncapped pre-handshake buffer reservations.

No CVE IDs were assigned at disclosure time. Reporters credited in the advisories include @samsulselfut (the P2SH sigop bug) and @sangsoo-osec (the 4.5.1 hotfix coordination).

Impact

  • Zebra-only validators on ≤ 4.4.1 are exposed to a chain-split path that needs no mining hashrate to trigger. The mitigation is the upgrade — there is no contract-level workaround.
  • Mining pools and exchanges running Zebra should treat the 4.5.0/4.5.1 sequence as a single hotfix and skip 4.5.0 entirely. Going to 4.5.0 leaves the second iteration of the same zcashd-mismatch open.
  • Light clients are unaffected directly. The exposure is to node operators running consensus-critical infrastructure.
  • No active exploitation is acknowledged in the advisories. The disclosures are coordinated patches, not incident reports.

Action checklist for node operators

  1. Upgrade zebrad to 4.5.1 directly. Skip 4.5.0.
  2. If you operate zebra-script as a library, bump to 7.0.0 (the version that matches zcashd's GetSigOpCount semantics for disabled opcodes).
  3. Cross-check your node against a zcashd peer once on the new version: a tip-hash divergence after upgrade would surface a leftover effect of the bug. None has been reported, but the check costs nothing.
  4. Review your peer-scoring telemetry over the last 48 hours for anomalies tied to the IPv4-mapped or repeated-shielded-transaction paths now patched.
  5. Watch the ZcashFoundation/zebra advisories feed for any 4.5.2 follow-up. The pattern of a hotfix one day after a major batch is itself a signal that the audit cycle is still surfacing edge cases.

Context — implementation diversity is a real cost

Zcash runs two independent consensus implementations on purpose: zcashd (the legacy C++ node) and Zebra (the newer Rust node). The trade-off is well understood: implementation diversity reduces single-bug risk, but multiplies the surface area for consensus mismatches when the two parsers disagree about edge cases — which is exactly what GHSA-gf9r-m956-97qx is.

This is not Zcash's first consensus-relevant Zebra patch, and it is unlikely to be the last as zcashd is wound down and Zebra carries more of the network. The Foundation's vulnerability-disclosure initiative cited >80 reports under review, per its May statements — the May 29 batch is a chunk of that backlog landing at once.

For Zcash operators, the takeaway is operational: upgrade now, verify tip parity with a zcashd peer if one is reachable, and treat any future Zebra release that quotes zcashd-parity in the diff as a consensus-critical change, not a routine bump.

Related stories