2026-10-10
This monthZcash Orchard Soundness Bug: How an Unbound Base Point Slipped Past Audits
Produced by the ZK Security research pipeline. Published only after the automated quality gate. The gate is described in the editorial policy.
The soundness vulnerability in Zcash's Orchard shielded pool, found and patched in the first days of June 2026, is one of the most instructive zero-knowledge security incidents of the year. It sat in…
Zcash Orchard Soundness Bug: How an Unbound Base Point Slipped Past Audits
The soundness vulnerability in Zcash's Orchard shielded pool, found and patched in the first days of June 2026, is one of the most instructive zero-knowledge security incidents of the year. It sat in widely reused circuit code, survived previous audits, and could only be fixed by changing consensus. This review covers what the bug was, how the Zcash ecosystem contained it, and what circuit developers using halo2 or similar proving systems should take from it.
The bug
The flaw lived in the halo2_gadgets crate, in the incomplete double-and-add loop of the elliptic-curve scalar multiplication chip (ecc::chip::mul). According to the Zcash community forum post-mortem, the circuit kept the per-iteration base point constant across loop rows using a selector, but "never tied it to the real base." The base coordinates were written with assign_advice, and "the constancy chain reached neither the doubling-row nor the complete-addition base anchors."
The consequence was that a prover could substitute a free constant point B' for the real base. The gadget would then compute [a] base + [b] B' rather than [scalar] base, and the proof would still verify. Cointelegraph Magazine summarized the root cause as using assign_advice() where the stricter copy_advice(), which adds an equality constraint to an existing cell, was required. It reported that the flaw may date to Orchard's activation in 2022.
This is a textbook under-constrained circuit. Each row of the computation looked correct in isolation. What was missing was the equality constraint linking the values used inside the loop to the value the rest of the circuit believed it was multiplying. In a proving system, a value that is assigned but never constrained is chosen by the prover, not by the protocol.
Impact
The Zcash Foundation said exploitation could have let the Orchard pool accept invalid state transitions, potentially enabling double-spending within Orchard. It could not inflate the total ZEC supply, which Zcash's turnstile mechanism protects. Cointelegraph reported that a working exploit created counterfeit ZEC inside a local regtest environment. On mainnet, the Foundation said "the vulnerability was caught before any known exploitation occurred," and the forum post-mortem said no unauthorized value creation had been detected.
The affected components were halo2_gadgets before v0.5.0, orchard before v0.14.0, zcash_primitives before v0.28.0, zcashd v5.0.0 through v6.12.3, and zebrad below v4.5.1. Any other project that reused the vulnerable halo2_gadgets scalar-multiplication chip should check its version.
Discovery and remediation
Independent researcher Taylor Hornby found the bug on May 29, 2026 while auditing on behalf of Shielded Labs, and disclosed it privately to Zcash Open Development Lab (ZODL) engineers that night. Cointelegraph reported that he used AI-assisted analysis tooling, and the forum post-mortem noted that such tools are "dramatically reducing the cost of vulnerability discovery."
The fix could not ship as an ordinary software patch. Correcting the circuit changes the pinned verifying key, and that requires a consensus change. The team therefore used two stages:
- Emergency soft fork (Zebra 4.5.3). After mainnet block 3,363,426, nodes rejected any transaction or block containing Orchard actions, disabling the pool. The forum post explains that "a direct patch would have revealed too much information about the nature of the issue." A first activation attempt ran into coordination problems, and a second patch activated around 02:00 UTC on June 2. Orchard was offline for roughly 24 hours.
- NU6.2 hard fork (Zebra 5.0.0). At block 3,364,600, activated at 00:05 EDT on June 3, Orchard returned with the corrected circuit and a new verifying key. The upgrade also added a consensus rule rejecting Orchard bundles with non-canonical proof sizes.
Private coordination with miners and exchanges began on the evening of May 31, before any public detail was released. The incident illustrates a disclosure problem specific to shielded systems: because Orchard transactions hide amounts, the team could not rule out prior exploitation cryptographically. It could only check aggregate pool balances for signs of value creation.
Lessons for circuit developers
- Treat every advice assignment as prover-controlled. If a value must equal another cell, enforce it with an equality or copy constraint. An assignment alone is not a constraint.
- Audit gadgets, not just applications. The bug sat in a shared library gadget that application-level reviews tend to assume is correct.
- Test soundness negatively. Functional tests show that honest proofs verify. Soundness testing has to show that dishonest witnesses fail, for example by mutating advice values and confirming the verifier rejects them.
- Plan remediation before you need it. In systems with a pinned verifying key, a circuit bug means a consensus change. Pre-agreed paths for disabling a pool and coordinating miners and exchanges shortened Zcash's response to days.
Sources
Related guides: under-constrained circuits, auditing circom, choosing a proving system, trusted setup risk, the checklist.