Worked example · 2026-06
Zcash Orchard counterfeiting vulnerability — under-constrained halo2 scalar-mul gadget (AI-discovered responsible disclosure) — 2026-05-29 / 2026-06-02
Summary
Zcash is a privacy coin whose Orchard shielded pool (activated in the NU5 upgrade, 2022-05-31) uses the halo2 (Halo 2 / PLONKish) proving system. Supply integrity inside Orchard depends on the soundness of the Orchard Action circuit: a valid proof must exist only for transactions that conserve value and spend each note exactly once.
On 2026-05-29, Taylor Hornby ran his zcash-full-stack-auditor agent framework — an automated soundness/zero-knowledge audit suite — over the halo2 implementation, including the Orchard circuit, using the just-released Opus 4.8 model at max effort. An audit agent flagged a critical under-constraint in the variable-base scalar-multiplication gadget that could be used to double-spend Orchard notes. Hornby (with Claude) built a proof-of-concept against the real Orchard circuit, then an RPC test that doubled an Orchard note's value repeatedly until a local regtest balance exceeded 10M ZEC — confirming a practically exploitable, unbounded inflation attack (bounded only by Zcash's pool turnstiles). The PoC ran only in local regtest; nothing was broadcast to testnet or mainnet.
He disclosed the same night (2026-05-29, 11:53pm MDT) over Signal to Daira Emma Hopwood and Kris Nuttycombe, delivered a second PoC at 2:06am, and after escalating by phone got ZODL engaged on 2026-05-30. ZODL prepared an emergency soft fork to disable Orchard; the first soft fork failed (a missed p2p DoS-banning rule prematurely banned non-upgraded nodes), and a retry 60 blocks later activated on 2026-06-01 (~9:30pm MDT). Orchard was re-enabled with corrected circuit code at block 3,364,600 (the NU6.2 upgrade, 2026-06-02 ~10pm MDT / 2026-06-03 UTC).
The total window of exposure was 4 years, 1 day, 10 hours (NU5 activation → fix). The window from Opus 4.8's public release to discovery was 4 days, ~10 hours. Because Orchard transactions are shielded, whether the bug was exploited during the four-year window cannot be determined cryptographically; the Zcash Foundation states there is no evidence of exploitation and that user privacy was not affected. The public disclosure (2026-06-05) coincided with a sharp ZEC sell-off and high-profile capitulation.
Vulnerability detail (precise root cause)
The Orchard Action statement enforces diversified-address integrity:
(1)
pk_d_old = [ivk] · g_d_old
i.e. the incoming viewing key ivk the prover supplies must be the correct one for the note's address (pk_d, g_d). This is what binds the prover to the note's real ivk — and therefore its real nullifier key nk — so that the nullifier the Action reveals is the spent note's true nullifier, preventing double-spends.
The check [ivk]·g_d is computed by halo2's variable-base scalar-multiplication gadget (halo2_gadgets/src/ecc/chip/mul/incomplete.rs, lines 309–310). For performance, the gadget uses an incomplete point-addition inner loop. The root cause: the base point is handed to the incomplete-addition stage with assign_advice() — which assigns a private witness value without introducing any constraint that the value equals the actual base. A separate constraint (q_mul_2) forces the loop's base values equal to each other, but nothing binds them to the real base g_d.
Consequently a malicious prover has complete freedom to choose the base used in the loop. Given any target (pk_d, g_d, ivk), the prover can solve for the unconstrained base that makes [ivk]·g_d evaluate to pk_d, circumventing check (1) entirely. (Per the writeup, Opus 4.8 derived the required algebra on its own.) With (1) defeated, the attacker can spend a note using a wrong nk, and since nk feeds the nullifier computation, each wrong nk yields a distinct nullifier for the same note — letting them spend it repeatedly, doubling its value each time.
The fix is one-line-shaped: change the first-iteration assign_advice() to copy_advice(), producing a constraint that binds the first base value to the correct base; the existing q_mul_2 then propagates that equality across the loop.
AI-assisted discovery (why this case is a landmark)
- Found by an automated audit agent within ~4 days of the model's release. Hornby's
zcash-full-stack-auditorframework, running Opus 4.8 at max effort, surfaced the under-constraint during a routine soundness sweep that included Orchard in scope. - The prior model missed it. Earlier runs of the same framework with Opus 4.7 (xhigh) did not find the bug; 4.7 found it only when narrowly directed ("audit the variable-base scalar-mul gadget for missing constraints that could lead to an inflation/double-spend bug"). On a generic prompt, even Opus 4.8 found it in only ~1 of 4 runs — a small, explicitly non-scientific sample, but a sharp illustration that discovery was probabilistic and prompt-sensitive.
- The model doubted itself. Opus 4.8 was "extremely skeptical that it had found a real bug," assuming audited upstream code must be correct (or that it was looking at a planted backdoor), and needed prodding to take the finding seriously — a notable failure-mode for AI-assisted audit.
- Humans had not found it. "Orchard had pretty in-depth audits prior to activation, suggesting the bug was difficult for humans to discover," and it survived four years of public scrutiny.
- A possible differentiator: the successful run fed the halo2 book into the initialization stage (vs only the protocol spec / ZIPs in prior audits).
Detection / exploitation forensics (the load-bearing asymmetry)
- The attack leaves no observable on-chain signature: exploitation only sets private circuit inputs, and nullifiers from double-spends are indistinguishable from legitimate nullifiers.
- The only statistical handle is Orchard transaction arity (actions per transaction) — an attacker might duplicate-then-consolidate notes. Hornby had Claude analyse arity since the Opus 4.8 release; results were inconclusive (an arity-4 anomaly in the window matched a similar month-boundary anomaly a month prior). And because the bug doubles note value, very few actions are needed to accrue a large balance, so even this handle is weak.
- Eli Ben-Sasson's heuristic (StarkWare; a relevant zk authority) on how to read the uncertainty: if the bug was exploited, the market will likely learn within days, because an attacker rushes the turnstile to surface and cash out shielded value; each day that passes without such a move makes prior exploitation less likely. It is a behavioural bound, not a cryptographic proof — which is precisely the point of the case.
Timeline (MDT unless noted)
| When | Event | OAK ref |
|---|---|---|
| 2022-05-31 11:50am | Vulnerable NU5 upgrade activates; Orchard goes live with the under-constrained scalar-mul gadget | (latent T9.014 surface — 4y) |
| 2026-05-28 ~12:00pm | Opus 4.8 publicly released | (capability shift) |
| 2026-05-29 ~6:00pm | Hornby's zcash-full-stack-auditor (Opus 4.8, max effort) audit agent flags a critical Orchard double-spend under-constraint |
T9.014 discovered |
| 2026-05-29 11:53pm | Reported with PoC over Signal to Daira Emma Hopwood & Kris Nuttycombe | (responsible disclosure) |
| 2026-05-30 2:06am | Second PoC against the real Orchard circuit (multi-nullifier double-spend); recommends emergency disable | |
| 2026-05-30 ~6:30am | Issue acknowledged by ZODL; RPC PoC inflates regtest balance past 10M ZEC | |
| 2026-06-01 ~9:30pm | Soft fork disabling Orchard activates (first attempt failed on a p2p DoS-ban rule; retry 60 blocks later succeeds) | (containment) |
| 2026-06-02 ~10:00pm | Orchard re-enabled at block 3,364,600 with corrected circuit (NU6.2); 2026-06-03 UTC | (fix via network upgrade) |
| 2026-06-05 | Public advisory; ZEC sells off (~31% in 24h; ≈$600 → ≈$312 peak-to-trough); Arthur Hayes exits his ZEC position | (disclosure / market) |
Total exposure: 4 years, 1 day, 10 hours. Opus-4.8-release-to-discovery: 4 days, ~10 hours.
What defenders observed / should take away
- Audit the missing constraints, adversarially. The defect was an
assign_advice()that should have been acopy_advice()— a witness assigned with no binding constraint. The report's own long-term recommendation is to enumerate everyassign_advice()(and similar) and ask a SAT solver or AI: "can this value be changed to anything other than the honest prover's assignment without violating any constraint?" Under-constraint bugs are invisible to functional testing (valid inputs still produce valid proofs); they surface only under adversarial witness construction. - Pre-build a fast "disable the pool" lever. The two-phase soft-fork-to-disable, then hard-fork-to-fix is the model T9.014 response, but the soft fork was a multi-day coordination effort (and the first attempt failed on an unrelated p2p rule). The report recommends a multisig to turn off shielded pools, which "would have reduced the exposure window by days." Protocols with consensus-critical circuits should hold a pre-planned kill-switch.
- Treat new-AI-model release as a security event. "Balance-integrity-violation audits should be performed immediately upon the public release of any new AI model." A latent bug that humans missed for years became discoverable within days of a model release — which means it became discoverable to adversaries on the same clock. (Mitigating note from the report: the full PoC took ~6 hours to build even after the bug was known, so it is unlikely the miners who privately received the soft-fork patch — which did not include bug details — could have weaponised it before activation.)
- Shrink the turnstile-bounded blast radius over time. Because realised theft is capped by pool turnstiles, the report recommends spinning up a fresh Orchard-equivalent pool and auto-migrating funds so the turnstile-enforced upper bound on potentially-stolen value decreases over time.
What this example tells contributors writing future Technique pages
- T9.014 needs a documented zk-circuit-soundness sub-shape. It is mechanically distinct from the integer-overflow (Bitcoin 2010) and duplicate-input (CVE-2018-17144) sub-shapes: the inflation surface is an under-constrained proving circuit, and the audit discipline is constraint-coverage / adversarial-witness review, not integer-bounds checking. Record which sub-shape a new T9.014 case belongs to.
- Circuit soundness is a consensus bug, not a "smart-contract bug." When a validity/shielded system's supply invariant is enforced by a circuit, a missing constraint is a network-wide unbounded-mint vulnerability fixed by hard fork, not contract upgrade. Map under T9.014 (cross-ref T9.004 for the "missing-validation" reading).
- Record forensic asymmetry for privacy systems. Note explicitly that exploitation may be cryptographically unprovable and that "no evidence of exploitation" is a weaker assurance than on a transparent chain. Capture behavioural heuristics (Ben-Sasson's turnstile-rush argument) as the only available read on exploitation.
- Record AI provenance and the model-release clock. This is the first OAK anchor where the discovery capability itself is dated to a model release. Contributors should record the tool/model, whether prior models found it, and that adversaries operate on the same release clock — neutrally, as a fact about how discovery now works (consistent with OAK's Moonwell cbETH AI-co-authored-commit note).
Public references
[shieldedlabsorchard2026]— Shielded Labs / Zcash community forum advisory, "The Orchard Counterfeiting Vulnerability — and next steps," by Zooko Wilcox, Jason McGee, and Taylor Hornby, 2026-06: https://forum.zcashcommunity.com/t/the-orchard-counterfeiting-vulnerability-and-next-steps/56015[hornbyorchard2026]— Taylor Hornby, "Orchard Security Bug" — primary technical writeup: under-constrainedhalo2variable-base scalar-mul gadget (assign_advicevscopy_advice), diversified-address-integrity bypasspk_d=[ivk]·g_d, multi-nullifier double-spend; discovered viazcash-full-stack-auditor+ Opus 4.8; timeline, regtest 10M-ZEC PoC, and long-term mitigations.[eccounterfeiting2019]— Electric Coin Company, "Zcash Counterfeiting Vulnerability Successfully Remediated" (CVE-2019-7167) — the 2018 BCTV14 zk-SNARK counterfeiting flaw (Ariel Gabizon), quietly fixed in Sapling (2018-10-28), disclosed 2019-02-05: https://electriccoin.co/blog/zcash-counterfeiting-vulnerability-successfully-remediated/[theblockzcash2026]— The Block, "Security researcher finds Zcash vulnerability allowing 'unlimited' counterfeit minting; ZEC drops 31%": https://www.theblock.co/post/403698/zcash-vulnerability-zec-drops[coindeskzcash2026]— CoinDesk, "Zcash plummets 30% as Shielded Labs reveals a major bug that went undetected for four years": https://www.coindesk.com/markets/2026/06/05/zcash-plummets-30-as-developer-reveals-a-major-bug-that-went-undetected-for-four-years[blockheadzcash2026]— Blockhead, "Zcash Founder Discloses Critical Orchard Forgery Flaw Fixed by Emergency Hard Fork": https://www.blockhead.co/2026/06/05/zcash-founder-discloses-critical-orchard-forgery-flaw-fixed-by-emergency-hard-fork/[panewszcash2026]— PANews, "Zcash founder reveals details of a serious forgery vulnerability in Orchard": https://www.panewslab.com/en/articles/019e9547-ae66-702f-b590-865375fb228f[cryptobriefingzcash2026]— Crypto Briefing, "Zcash fixes critical Orchard bug after emergency network upgrade, restores shielded transactions": https://cryptobriefing.com/zcash-orchard-bug-emergency-upgrade/
Discussion
Zcash Orchard joins OAK's protocol-client consensus-bug lineage (examples/2010-08-bitcoin-value-overflow-bug.md and the CVE-2018-17144 pipeline anchor) as its first zero-knowledge sub-shape, its first privacy-coin case, and its first AI-discovered anchor. Where Bitcoin's 2010 bug is the canonical transparent-ledger arithmetic inflation — exploited on mainnet, identified, reorged — Orchard is the canonical shielded-circuit soundness inflation — demonstrated in a regtest PoC, disclosed responsibly, patched by hard fork, but with the defining twist that exploitation can never be proven or disproven. Same structural failure (reference-client validation lets value be created from nothing; fixed by network upgrade), opposite forensic posture (provable vs unprovable).
The sharpest context is that Zcash has been here before. In 2018, cryptographer Ariel Gabizon found a subtle flaw in the BCTV14 zk-SNARK construction underpinning the original (Sprout) shielded pool that also allowed undetectable infinite counterfeiting — a bug "so subtle it evaded years of analysis by expert cryptographers." It was quietly fixed in the Sapling upgrade (2018-10-28) and disclosed only in February 2019 (CVE-2019-7167), again with no evidence of exploitation and no privacy impact. Orchard 2026 is the second occurrence of the same class at the same project: a years-latent soundness flaw in Zcash's shielded-pool proof system enabling infinite counterfeit, fixed-then-disclosed, exploitation unprovable. The recurrence is the lesson — the soundness of a shielded pool's circuit is a perennial, consensus-critical attack surface, and the 2026 instance adds that the discovery side has been transformed: what took an in-house cryptographer's insight in 2018 was surfaced by an automated audit agent within days of a new model's release in 2026. As the report puts it, the unsettling question is not this bug but how many comparable under-constraints still sit in other protocols' circuits — now that the tooling to find them ships to attackers and defenders simultaneously.