Post-mortem, 12 October 2026
How the earlier ZeroTrace vault was emptied by a forged proof that a flawed Barretenberg verifier accepted, what we have done, and the refund of every note.
Summary
On 12 October 2026 at 11:18:09 UTC, transaction
0xccccd5a8117a27beae11b2ff8361bcc0c496f14a65d0481dedd6965044fb1a42 (block 86632174) emptied the ZeroTrace vault
(0xf3935bec6247170B28e1755c85957A72f243D84D) on Robinhood Chain. An address that had never used the vault,
0xf7a504450ec997c264338b4bff0eb4199d964a24, submitted a zero-knowledge proof claiming to spend two notes worth the
vault's entire share supply. The vault released 90,422,336 ZERO, which were sold for 4.670 ETH.
The proof should never have been accepted. It proves a statement that cannot be true, and the vault accepted it because the proof system's verifier, generated by Aztec's Barretenberg, had a soundness flaw: it could be made to accept proofs of false statements.
Aztec found and fixed that flaw on 14 May 2026. They published no security advisory for it, did not mention it in their release notes, and left their official installer pointing to a build without the fix. That installer still installs the vulnerable build today. The same flaw was used on 24 September to take 1.9 million USDC from Payy.
Our contracts, our circuit and the vault's accounting worked as designed. Entries to the vault are closed, and a new vault with a corrected verifier was deployed on 12 October 2026 at 22:36 UTC. Every note that was unspent in the emptied vault is refunded in full, into a note of the new vault.
What happened
A ZeroTrace vault holds ZERO and a Merkle tree of private notes. Spending a note requires a zero-knowledge proof that the note exists, belongs to the spender and has not been spent, and that the value going in equals the value going out. The vault checks that proof with a verifier contract generated by Barretenberg, Aztec's proving system for the Noir language.
The transaction called the vault's router to sell, with a proof that two notes were being spent and that together they covered all 20,520,873,138,048,082,021,922,500,621,968 shares in existence. That is impossible: part of the share supply is a locked seed note that nobody can spend, so no set of real notes can add up to it. The verifier accepted the proof anyway. The vault paid out its entire backing, the router sold it, and the ETH went to the sender.
Root cause: a soundness flaw in Aztec's Barretenberg
UltraHonk, the proof system Barretenberg uses, has a zero-knowledge mode in which part of the proof is checked through a sub-protocol called the small-subgroup inner-product argument. That argument is only sound if the verifier checks, as a separate condition, that a running sum starts at zero. Barretenberg's verifier did not. It checked a single combined equation, which, in Aztec's own description of the fix, left the prover one degree of freedom: enough to make a false proof verify.
Aztec corrected this on 14 May 2026 in commit 58bf73a of AztecProtocol/aztec-packages, titled "fix!: small
subgroup ipa bug". The corrected verifier checks the missing condition as a fifth opening claim. The verifier deployed
for ZeroTrace has the uncorrected form, with four.
How the vulnerable build reached us
Noir and Barretenberg are released separately, and their versions must match. Aztec's official installer, bbup,
chooses the Barretenberg build from a compatibility table published in Aztec's repository, keyed by the installed Noir
version.
- The installer selects the vulnerable build. For Noir
1.0.0-beta.22, the most recent Noir release with an entry in Aztec's table when we built our verifier,bbupinstalls Barretenberg5.0.0-nightly.20260522. That build was made eight days after Aztec's fix, from a branch that did not contain it. - Aztec added that entry after fixing the flaw. The mapping was added to the table on 1 June 2026, two weeks after the fix, and has never been updated. On 13 October 2026, the installer still installs the vulnerable build for Noir beta.22. No later Noir release has an entry at all.
- No advisory. Aztec has published no security advisory for this flaw. On 8 October 2026 they published two advisories for a different verifier bug, and none for this one, two weeks after it had been used against Payy.
- No mention in the release notes. The fix first shipped in Barretenberg v5.0.0 on 13 July 2026. Its release notes have a section on security hardening listing six themes; this flaw is not among them. The only public trace is a commit message.
- No warning in the installer.
bbuphas a mechanism to warn about Barretenberg versions with known soundness issues. It covers only versions before 0.82.
A project following Aztec's documented installation path with Noir beta.22 received a verifier that accepts forged proofs, with no advisory, release note or warning to tell it otherwise. That is what happened to us.
What is established
| Finding | How it was checked |
|---|---|
| The proof is valid for the deployed verifier. | It verifies against the verifier compiled from our circuit, whose verification key hash (0x13f6de89dae0e1428e798c62078eab1df1241f41254ee203e9e51e10b52f8202) is the deployed one, and against Barretenberg's own native verifier. |
| The proof is bound to the transaction. | Changing the exit amount by one makes it fail. |
| The statement it proves is impossible. | It exits the entire share supply, including a locked seed note that nobody can spend. |
| Our circuit is correct. | Its compiled constraints enforce membership, ownership, unique nullifiers, value ranges and conservation of value, each covered by tests. |
| The vault's accounting is correct. | Every increase in the share supply, from the first deposit to the drain, matches a deposit. |
| The proof used a real state of the vault. | The note tree rebuilt from the vault's events gives the root the proof used. |
| The build we used lacks Aztec's fix, and later releases have it. | In Aztec's repository, tag v5.0.0-nightly.20260522 does not contain commit 58bf73a and its verifier template has no boundary check; tag v5.0.0 contains both. |
| The deployed verifier has the uncorrected form. | Its source, compared with the corrected template. |
What is inferred
That the attacker used this particular flaw is inferred, not reproduced. Every other component checks out, the proof is valid for a statement that cannot be true, and this flaw produces exactly that result. It had been used the same way against Payy eighteen days earlier.
What it was not
- Not a stolen key, and not our team, front end, RPC or relayer: the attacker needed none of them.
- Not a replayed or altered transaction: the proof is bound to its inputs and to the vault.
- Not a flaw in our circuit, our contracts or the vault's accounting.
Timeline (UTC)
| Date | Event |
|---|---|
| 14 May 2026 | Aztec fixes the flaw in Barretenberg (commit 58bf73a). No advisory. |
| 22 May 2026 | Barretenberg 5.0.0-nightly.20260522 is built without the fix. |
| 1 June 2026 | Aztec's installer table maps Noir beta.22 to that build. |
| 13 July 2026 | Barretenberg v5.0.0 ships the fix; the release notes do not mention it. |
| 24 September 2026 | Payy loses 1.9 million USDC to a forged proof through the same flaw. |
| 25 September 2026 | We build the ZeroTrace verifier with Noir beta.22 and the Barretenberg build Aztec's installer selects. |
| 2 October 2026 | ZeroTrace launches on Robinhood Chain. |
| 8 October 2026 | Aztec publishes advisories for a different verifier bug; none for this one. |
| 12 October 2026, 11:18 | The vault is drained. Entries are closed. |
| 12 October 2026 | Root cause identified. |
| 12 October 2026, 22:36 | A new vault with a corrected verifier is deployed. |
| 13 October 2026, 22:36 | ZERO's creator fees move to the new vault's harvester. |
Impact
- 90,422,336 ZERO, the full backing of every note in the vault, were released and sold for 4.670 ETH, sent to
0xf7a504450ec997c264338b4bff0eb4199d964a24. - Every note held in the vault at block 86632174 lost its value. The vault had received 63 deposits from 28 addresses. Every one of those notes is refunded in full: see Refund of the earlier vault.
What we have done
The new vault is deployed (0xEE92d20c1b0AAA686DDc8809A1B6A67aB092eb33); the wallet will reopen on it.
- A verifier with Aztec's fix. It is generated with Barretenberg 5.2.1, the latest stable release, and the Noir version Aztec builds it with. It contains the missing check.
- No reliance on Aztec's installer. Both tools are pinned to exact versions, downloaded from their official releases and checked against their published checksums. Barretenberg is a stable release, never a development build; Noir has no stable release yet, so we use the version Aztec builds Barretenberg 5.2.1 with.
- Checks on the generated verifier. The build stops, and the tests fail, if the verifier lacks the check Aztec added. Before deployment, the new verifier must also accept a real proof.
- A vault that can be stopped and repaired. The new vault can be paused, stopping every spend of a note, and its verifier can be replaced without moving any note, should Barretenberg ever need another fix. Pausing and upgrading are separate roles, and each is a public on-chain transaction.
- A refund of every note, in full. Every note that was unspent in the emptied vault at block 86632173, the last block before it was emptied, is refunded what it was worth then, to the wei: 90,409,186.61 ZERO in all, funded by ZeroTrace. A refund contract checks each claim with the corrected verifier against the vault's note tree as it was at that block, pays each note once into a private note of the new vault, and pays the gas. The app refunds a wallet's notes automatically when privacy is turned on. There is no deadline. See Refund of the earlier vault.
- Tests. Contract, circuit and SDK tests, and end-to-end tests with real proofs on a fork of Robinhood Chain.
Appendix
| Transaction | 0xccccd5a8117a27beae11b2ff8361bcc0c496f14a65d0481dedd6965044fb1a42 (block 86632174) |
| Attacker | 0xf7a504450ec997c264338b4bff0eb4199d964a24 |
| Vault | 0xf3935bec6247170B28e1755c85957A72f243D84D |
| Router | 0x9EB58318791e61decBCf8A4d169a0FaD8b6fb987 |
| Verifier | 0x3DAd6EB076169F409A7901dff7BD26be3E883B09 |
| Shares exited | 20520873138048082021922500621968, the entire supply |
| Released and sold | 90,422,336 ZERO for 4.670 ETH |
| Aztec's fix | AztecProtocol/aztec-packages commit 58bf73a289f7da78c8920c9c73604a8e5d105025 (14 May 2026), first released in Barretenberg v5.0.0 (13 July 2026) |
Sources:
- Aztec, commit
58bf73a, "fix!: small subgroup ipa bug" - Aztec, Barretenberg v5.0.0 release notes
- Aztec, security advisories
- Aztec, bbup compatibility table
- Certora, "The Payy Exploit: A $1.92M Forged ZK Proof Attack"