# Zebra's Transparent SIGHASH_SINGLE Handling Diverges from zcashd for Corresponding Outputs

Zebra computes a ZIP-244 SIGHASH_SINGLE digest for inputs lacking a corresponding output instead of failing, letting malformed V5 transactions pass Zebra but be rejected by zcashd.

- Payout: Research
- Severity: critical
- Program: Zebra
- Found by: sangsoo-osec, defuse
- Disclosed: 2026-05-07
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-cwfq-rfcr-8hmp
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-cwfq-rfcr-8hmp
- Tags: area:web3 domain:web3 impact:integrity kind:research platform:ghsa sev:critical tech:rust technique:parser-differential technique:source-review vuln:crypto vuln:signature-replay

**Target:** Zcash node transparent script verifier (ZIP-244 sighash)
**Root cause:** Zebra's Rust ZIP-244 sighash uses transparent_outputs_hash([]) when input index >= vout.len() instead of erroring, while zcashd's SignatureHash throws and CheckSig returns false.
**Steps:**
1. Build an otherwise-valid V5 transaction with >=2 transparent inputs and only 1 transparent output.
2. Sign input 0 normally.
3. Sign input 1 with canonical `SIGHASH_SINGLE` or `SIGHASH_SINGLE|ANYONECANPAY` using Zebra's digest where the missing output contributes `transparent_outputs_hash([])`.
4. Submit the transaction to Zebra and to zcashd.
5. Observe Zebra accepts into mempool, selects into `getblocktemplate`, and can mine/accept a block; zcashd rejects it.
**How found:** Cross-implementation differential review of transparent sighash handling: compared zcashd's SignatureHash ZIP-244 branch (throws on nIn >= vout.size()) against Zebra's Rust sighash engine, spotting the empty-outputs-hash fallback instead of an error.
**Exploitation:** Attacker crafts a V5 transparent tx with more inputs than outputs, signs the missing-output digest Zebra computes, submits to Zebra mempool; Zebra templates it and an external miner includes it, producing a block zcashd rejects.
**Escalation:** Consensus split escalates to chain divergence if miners build on Zebra-templated blocks containing the malformed tx.
**Insight:** When auditing consensus clients, diff the exact error/exception paths of the reference implementation against the reimplementation's sighash library — a fallback value (like hashing an empty list) where the reference throws is a consensus split, and mempool+getblocktemplate reuse of the same verifier makes it reachable.

