# Zebra's Block Validator Undercounts Coinbase and P2SH Sigops

Zebra undercounted coinbase and aggregate P2SH sigops against the 20000 block limit, accepting blocks zcashd rejects and risking a consensus split.

- Payout: Research
- Severity: critical
- Program: Zebra
- Found by: sangsoo-osec, defuse
- Disclosed: 2026-05-07
- CVE: CVE-2026-44498
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-jv4h-j224-23cc
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-jv4h-j224-23cc
- Tags: area:oss domain:oss impact:dos impact:integrity kind:research platform:ghsa sev:critical tech:rust technique:source-review vuln:accounting-error vuln:business-logic

**Target:** Block validator sigop accounting (MAX_BLOCK_SIGOPS consensus check)
**Root cause:** Zebra skipped the coinbase input's scriptSig in legacy sigop counting and never accumulated P2SH redeem-script sigops during block validation, only on the mempool path. zcashd counts both against the per-block 20000 limit.
**Steps:**
1. Compare zcashd GetLegacySigOpCount (includes coinbase scriptSig) with Zebra's Sigops impl, which skips the coinbase input.
2. Hide up to ~98 sigops in the coinbase scriptSig (100-byte cap less height prefix) uncharged.
3. Compare zcashd GetP2SHSigOpCount (accurate=true, summed block-wide in ConnectBlock) with Zebra, which only computes P2SH sigops on mempool acceptance.
4. Build a block with aggregate redeem-script sigops >20000, e.g. 1334 P2SH spends × 15 sigops = 20010.
5. Submit block: Zebra accepts, zcashd rejects with `bad-blk-sigops`, splitting the chain.
**How found:** Code-reading comparison of Zebra's sigop accounting against zcashd's GetLegacySigOpCount and GetP2SHSigOpCount/ConnectBlock, spotting the coinbase skip and the mempool-only P2SH path.
**Exploitation:** A miner includes enough P2SH-spending transactions (or hides sigops in the coinbase scriptSig) so aggregate sigops exceed 20000; Zebra nodes follow the offending chain while zcashd nodes reject it, causing a network split.
**Escalation:** Consensus divergence between Zebra and zcashd nodes enables chain split by a single miner.
**Insight:** When reimplementing consensus, diff every counting/limit function against the reference client line-by-line; sigop-style limits are often aggregated block-wide in the reference but computed per-tx or only on mempool paths in rewrites.

