Retroactive Grant Application - zcashd Medium Severity V4 Sapling Parsing Mismatch (GHSA-3jg6-49c6-q99v)

Hello Zcash community,

Thank you again to the coinholders who approved my Q3 proposal and everyone who reviewed, discussed, and supported that work.

I have submitted a Q4 retroactive grant application on GitHub (#75), requesting $37,500 USD for GHSA-3jg6-49c6-q99v, a completed Medium severity disclosure concerning a V4 Sapling transaction parsing mismatch between zcashd and Zebra. GitHub displays this severity as Moderate.

Shared background with my High severity proposal

My earlier forum post on the High severity finding sets out the shared background: the Q3 approvals for critical vulnerability research, recent published security findings, and the opportunity to discuss how researchers’ contributions to Zcash’s security should be rewarded.

This application brings the same discussion to a separate Medium finding, with its own technical record, practical trigger conditions, and proposed amount. The Q3 references and recent release data are available in that forum thread.

The vulnerability and my contribution

For a V4 Sapling transaction with no Sapling spends or outputs, the serialized valueBalanceSapling must be zero. The malformed case has:

Serialized field Value
nSpendsSapling 0
nOutputsSapling 0
valueBalanceSapling A non-zero in-range value, such as 1

In the affected zcashd code, the V4 read path used the presence of Sapling actions to decide whether to assemble a bundle. When both action vectors were empty, it discarded the non-zero balance and exposed an empty-bundle balance of zero. The later validation check therefore examined an already-normalized object.

Zebra’s V4 parser instead rejected the same raw encoding with BadTransactionBalance.

The official advisory, published on May 8, 2026, credits sangsoo-osec as the reporter and documents the analysis and reproduction steps.

I used LLM-assisted differential code review to map the equivalent parsing and validation paths in zcashd and Zebra. I then traced the handling of the malformed balance, validated the mismatch, and examined how normalization affected later validation, transaction IDs, reserialization, and the relay and mining paths.

Practical impact and remediation

The advisory describes how the parser disagreement can reach block validation:

  1. A miner or custom raw block producer embeds the malformed transaction bytes directly into a block.
  2. The block’s Merkle root uses the normalized transaction ID that zcashd derives after parsing.
  3. zcashd can accept the raw block after normalization, while Zebra rejects those same bytes during deserialization.

The ordinary zcashd transaction relay, mempool, and mining path normalizes the encoding before block production. Submitting the malformed transaction to a stock node’s mempool alone therefore does not preserve the divergent trigger. Subsequent zcashd block relay can also reserialize the block in canonical form. These constraints are documented in the advisory’s impact analysis and are relevant to assessing this finding’s practical value.

The zcashd v6.12.2 security release, published May 6, 2026, describes the fix: malformed empty-Sapling encodings with a non-zero balance are now rejected during deserialization, matching Zebra’s behavior. The advisory lists versions below v6.12.2 as affected and v6.12.2 as patched.

The question for coinholders

As discussed in my earlier forum thread, I see this round as a useful opportunity to consider what criteria should guide rewards for researchers’ contributions to Zcash’s security. This Medium finding gives that discussion another concrete case.

I would welcome coinholders’ views on how to balance these considerations, whether through severity-based reference amounts, case-by-case assessments, or a combination of the two. This application puts one Medium finding and a specific requested amount before coinholders to help make that discussion concrete.

3 Likes