Jun 17, 2026

Aztec 2.0 Rollup Incident

On 17 June 2026, at 18:34 UTC, an attacker drained approximately $2.2M of assets from the original Aztec 2.0 rollup contract on Ethereum, across three transactions. Aztec 2.0 was Aztec's original privacy-preserving zk-rollup on Ethereum, launched in 2021 and deprecated in 2022.

The exploit targeted an unsound verification key behind the contract's escape-hatch verifier. Specifically, the deployed escape-hatch circuit accepted a withdrawal that was not backed by any real deposit.

On 18 June 2026, at ~08:16 UTC, a second, seemingly unrelated actor reproduced the same technique to sweep the leftover 0.76 ETH (rollupId 4490). The contract is now empty.

This incident follows a 15 June 2026 incident draining a different deprecated rollup, Aztec Connect.

Important to note

Incident timeline (UTC)

When (UTC) Event
17 Jun 18:21 Attacker funds a fresh wallet (0x6952…E97F) with 0.13 ETH for gas.
17 Jun 18:34 Withdrawal #1: the escape hatch is used to drain 1,158 ETH (0xab30…2b5).
17 Jun 18:49 Withdrawal #2: 150,000 DAI drained (0x5c19…05c3).
17 Jun 18:50 Withdrawal #3: 0.47 renBTC, the entire balance, drained (0x9e1d…03ca).
18 Jun ~08:16 A separate copycat actor sweeps the residual 0.76 ETH via the operator path (0x389b…cb0c). The contract is now empty.

The attacker's main attack, from gas funding to the final asset drain, took roughly 37 minutes.

What is Aztec 2.0?

Aztec 2.0 was Aztec's original privacy-preserving zk-rollup on Ethereum, launched in 2021 and deprecated in 2022. Aztec 2.0 let users shield assets and transact privately, batching many user transactions into a single Ethereum settlement with correctness guaranteed by a zero-knowledge validity proof. It was an early, pioneering design, later superseded by the Aztec Connect system in 2022.

In April 2024, after a year of supported exits and reminders urging users to withdraw their funds, we formally and permanently relinquished control of the contract onchain. This allowed users to continue to exit with no input from Aztec Labs by running their own infrastructure.

Technical details of the exploit

Background

To withdraw funds from Aztec 2.0, a user must submit a cryptographic proof that they own the funds, that the funds were genuinely deposited, and that those funds have not already been spent. Two parts of the system work together:

The contract also included an escape hatch, a public function allowing users to withdraw their own funds directly in the event the operator ceased to function. The security of this escape hatch was guaranteed by a proof system: each escape-hatch proof is checked against a set of constraints a valid proof must satisfy.

Details of exploit

From our analysis, the root cause is a soundness bug in the escape hatch circuit that allowed the attacker to withdraw funds that were never deposited or owned by them.

The exact mechanism is not provable from onchain data alone. However, our leading hypothesis involves a flawed decoupling of two values that should have been forced to match. Ownership of funds is proven against the contract's ledger, which is summarised by a cryptographic fingerprint (a Merkle root). The escape-hatch code uses this fingerprint twice, and never checks that the two uses agree.

Value What it is used for What the attacker set it to
Membership root The ledger the proof checks fund ownership against A fake ledger the attacker invented, in which they hold the target funds
Settlement root The ledger the contract validates against the live chain The genuine, live onchain root

Because the contract never required these two values to be equal, an attacker could prove ownership against a fabricated ledger while presenting the genuine ledger on L1. Both checks passed independently, and the contract had no means of detecting the discrepancy.

We confirmed the failure directly onchain. The attacker's proof explicitly states deposit = 0, withdraw = 1,158 ETH, and the notes it cites as the source of those funds are fabricated, which cannot occur in a legitimate proof. The verifier accepted it and the contract paid out. Notably, the verifier was neither broken nor empty: re-running it confirms that tampering with the proof in other ways causes it to reject. The fact that this forged proof nonetheless passed is the contradiction that identifies the flaw as residing in the verification key.

Assuming that was the mechanism, the attack proceeded as follows:

  1. Funded a fresh wallet with 0.13 ETH for gas.
  2. Read the contract's live state from the public chain and copied its genuine Merkle roots into the proof, ensuring the contract's own bookkeeping checks passed.
  3. Constructed a forged proof for "withdraw 1,158 ETH to me", backed by fabricated notes verified against a self-generated ledger.
  4. Submitted it through the public escape hatch. The verifier accepted it and the contract released 1,158 ETH.
  5. Repeated the process for the remaining two assets, one per transaction.

The second attack applied the same principle to extract the residual 0.76 ETH approximately 14 hours later. It used the normal operator path rather than the escape hatch, which was possible because a default Anvil/Hardhat developer test account had been registered as an authorised operator as part of the 2024 decommissioning.

Extracted assets: first attack

Asset Amount Approx. value
ETH 1,158.0 ~$2.04M
DAI 150,000.0 ~$150,000
renBTC 0.46963295 ~$7,000 (upper bound)
Total ~$2.2M at time of exploit (renBTC is a deprecated, depegged asset; its real value is likely far lower)

Extracted assets: second attack

Asset Amount Approx. value
ETH 0.759804206229645062 ~$1,300

Core impacts

Appendix