A Forgotten Escape Hatch Cost Aztec's Retired Bridge Another $2.2 Million
On June 14th, an attacker had already pulled $2.28 million out of a shuttered Aztec Connect contract — a product Aztec Labs wound down in 2023 and stripped of admin control in 2024 — by exploiting a gap between what the zero-knowledge proof layer verified and what the L1 settlement logic actually enforced. Because the contract was immutable, there was no patch to ship and no recovery to attempt.
Three days later, on June 17th, the same retired bridge infrastructure gave up a further $2.198 million to a different attacker. The contract wasn't the same one, the flaw wasn't the same flaw, and the entry point wasn't the same entry point — but both incidents rested on an identical broken assumption: that a ZK proof linking two independent witnesses was actually forcing them to agree.

Here's how the second drain unfolded. The attacker seeded a new wallet with 0.134 ETH sourced from HitBTC, then invoked escapeHatch() on a deprecated Aztec 2.0 rollup contract that hadn't seen active use since 2022. Across three transactions spanning roughly thirty-seven minutes, they extracted 1,158 ETH, 150,000 DAI, and 0.4696 renBTC.
The escape hatch existed for exactly one purpose: a last-resort function letting users force their own withdrawal if the sequencer ever stopped operating, gated by a ZK proof of ownership.
The root cause was a mismatch between the transaction set the rollup proof actually verified and where the L1 settlement boundary drew the line. Specifically, the numRealTxs value wasn't properly tied to the transaction set the proof constrained, leaving the proving system and the L1 settlement code reading two different transaction lists.
Aztec Labs had no admin keys to intervene with — the contract's immutability was total. The circuit responsible for the bug had been stripped out of the codebase years before, yet the verifier still deployed on-chain retained the old escape-hatch verification key, meaning proofs generated against the retired circuit logic still passed.
Credit for the reporting and detection work below goes to Aztec Labs, PeckShield, BlockSec Phalcon, thisvishalsingh, CertiK, MistTrack, L2Beat, Specter, TrustSec, and Defi Edward.
01How the alert unfolded
Researcher thisvishalsingh spotted the activity on the evening of June 17th, roughly three hours after the drain had already finalized on-chain. The initial read was cautious: a call to escapeHatch() on the Private Rollup Bridge contract had sent 1,158 ETH to the caller with no reverts and nothing structurally unusual — the proof simply cleared. The on-chain footprint was minimal: just 0.00009 ETH in gas, a single RollupProcessed event logged for rollup ID 4487, and a balance that had gone from funded to zero. The question left open at that point was whether the underlying proof reflected genuine ownership or had slipped through a hole in the verification logic — an answer that wouldn't arrive until the next morning.
CertiK confirmed the theft later that night, naming the attacker's address and putting the loss at approximately $2.15 million. A follow-up thread from the firm added a key mechanical detail: within the escape hatch's rate limit of 240 calls per 4,800 blocks, the attacker had crafted proofData where the header fields rollupSize and numTxs read zero, while the actual withdrawal parameters were embedded further into the payload. Verification logic read the zeroed header values, while execution — hardcoded at line 512 to process at least one transaction — picked up the real withdrawal figures instead. The two code paths were parsing different sections of the identical calldata and arriving at different answers.
Shortly after midnight, PeckShield laid out the complete asset breakdown: 1,158 ETH, 150,000 DAI, and 0.4696 renBTC, worth roughly $2.165 million combined at the time, moved to a wallet originally funded with 0.134 ETH from HitBTC. BlockSec Phalcon followed up with all three attack transaction hashes and flagged the link to the June 14th exploit: two distinct deployments and two distinct entry points, both stemming from the same category of proof-binding failure.
Aztec Labs published a statement in the early hours of June 18th, describing the target simply as "a deprecated Aztec payments product from 2021," confirming the contract's immutability and its position outside their control, and drawing a clear line between this event and the June 14th Aztec Connect incident. The Aztec Foundation posted essentially the same disclaimer one minute later: no ties to the live Aztec Network, no ties to the AZTEC ERC-20 token. Both statements were accurate as far as they went, but neither addressed the actual mechanism of the theft. That technical explanation — the circuit-level binding gap, the fabricated Merkle tree, two witnesses with no constraint forcing them to match — arrived the following morning, via BlockSec Phalcon's analysis and Aztec Labs' own incident writeup, covered below.
02Where the constraint went missing
Withdrawing from Aztec 2.0 required submitting a ZK proof demonstrating that the claimed funds existed within the private note ledger, hadn't already been spent, and belonged to the person making the claim. The verifier checked that proof against a verification key derived from the circuit itself, and the settlement contract simply trusted whatever the verifier concluded before releasing funds.
The problem traced to how the escape-hatch circuit handled a value called old_data_root, which appeared twice. One copy fed into the join-split circuit logic at line 33, serving as the root against which note-membership was checked. A second copy surfaced as a public input at lines 50 and 88, later compared in the Solidity contract against the actual on-chain state through a require(oldDataRoot == dataRoot) check. Nowhere did the circuit itself enforce that these two values matched.
That absent equality constraint was the entire exploit. The attacker constructed a fabricated Merkle tree populated with notes that didn't exist, generated a membership proof against that fake root, and separately supplied the genuine on-chain root as the public input. The circuit accepted the proof, the Solidity-side comparison passed because it was checking against the real root, and the withdrawal executed regardless.
Aztec Labs' incident report noted the tell visible on-chain: the attacker's proof claimed a deposit of 0 alongside a withdrawal of 1,158 ETH, sourced from notes that were entirely fabricated — a combination that a correctly-constrained circuit should never allow. The defect lived in what the verification key encoded, not in how the verifier executed: the circuit simply never required its two references to old_data_root to be identical. The underlying trusted setup remained uncompromised — this was purely a circuit-design flaw.
Notably, the vulnerable escape-hatch circuit had already been deleted from the codebase via PR #402 — but the verifier contract still live on-chain retained the verification key that circuit had generated. The source repository had progressed past the flaw; the deployed contract hadn't. Any proof built against the old, retired circuit logic was therefore still accepted, simply because the key that would validate it had never been rotated out.
03Thirty-seven minutes, three withdrawals
At 18:21 UTC on June 17th, the attacker funded a new wallet with 0.134 ETH for gas, and the first transaction went through thirteen minutes later. At 18:34 UTC, a single call through the escape hatch moved 1,158 ETH out of the contract — the bulk of the total haul. Fifteen minutes after that, at 18:49 UTC, a second transaction pulled out 150,000 DAI. One minute later still, at 18:50 UTC, a third transaction swept approximately 0.47 renBTC. Counting from the initial gas funding to the last withdrawal, the entire operation spanned about 37 minutes.
The three transaction hashes, in sequence:
1,158 ETH withdrawal: 0xab306cd2184d23b6ba3e151b10b3b9a0b81f211cc16f4f3b0c79f0b17a59c2b5
150,000 DAI withdrawal: 0x5c196c37a109d74c9797254287a0331f30e0daa637af241bd28fdc43774705c3
0.46963295 renBTC withdrawal: 0x9e1d6ab7c20ae235409d7dd3a9cd47c04f07293585b3498b8beed82d6f6b03ca
The ETH portion was worth approximately $2.04 million at exploit time, the DAI added $150,000, and the renBTC was valued at roughly $7,000 as an upper-bound estimate — Aztec Labs' report noted renBTC is depegged and effectively deprecated, so the real market value was likely considerably lower. That puts the primary attack's total at approximately $2.197 million.
The attacker's wallet, funded from HitBTC, held the bulk of the proceeds at the main EOA, with a portion of the ETH subsequently split across two holding addresses tracked by MistTrack: roughly 300 ETH to one and 56 ETH to the other, per Aztec Labs' report.
Attacker EOA: 0x6952d9246e9aFE8B887B2877225163436F78E97F
Victim contract (Aztec: Private Rollup Bridge): 0x737901bea3eeb88459df9ef1BE8fF3Ae1B42A2ba
Holding wallet A: 0x15930a0fef3421f48c6553b5691682cc1b22edb3
Holding wallet B: 0x33d6a0d9bc210e823e043d604179cd844eb467df
About 13.5 hours later, the following morning, a second and unrelated actor cleaned out the remaining 0.76 ETH still sitting in the contract — this time through the operator path rather than the escape hatch — adding roughly $1,300 to the total loss.
Second attacker EOA: 0xb6f89d12Ff9A9e394f40B701Ac46428DE0d1bEa5
Secondary attack transaction: 0x389bce3dad78c09900cb4c9e72397a73b39b8217ae37ef264f3439046737cb0c
Combined total across both attackers: $2.197 million
That second route was only reachable because a default Anvil/Hardhat developer test account had, at some point during the 2024 decommissioning, been registered as an authorized operator. Between the two incidents — three transactions for the first attacker, one for the second — the contract had sat unmonitored on-chain since 2022 and by the time it was fully drained had roughly $50 remaining.

04An orphaned contract with no one to call
Aztec Labs released a detailed incident report in the days that followed, confirming the root cause, reconstructing the timeline, and naming Groom Lake as the incident-response firm brought in to help coordinate blocking the stolen funds across exchanges. No compensation plan was announced and no recovery mechanism existed — the contract's immutability, combined with Aztec Labs having renounced all administrative control back in April 2024, left documentation as the only available response.
That April 2024 renunciation is significant in context: it followed roughly a year of supported withdrawal windows and public reminders urging remaining users to exit, after which Aztec Labs formally gave up every administrative role and any on-chain upgrade authority. That posture is consistent with the current Aztec Network's Stage 2 rating on L2Beat — one of the higher decentralization tiers a rollup can achieve, and one few reach. Ironically, the same architectural rigor that earned that rating also meant that when the escape-hatch flaw was discovered three years after the product's retirement, nobody held a key capable of stopping it.
On-chain analyst Specter argued bluntly that an unused, unmonitored contract should simply have its funds withdrawn and be shut down cleanly rather than left as a standing target. Fran, a community member and Foundation contributor within the Aztec ecosystem, offered additional context: Aztec Connect had been wound down roughly three years prior, and while most users withdrew, some balances remained — likely belonging to people who'd lost wallet access or simply never claimed their funds. The prior week's roughly $2 million theft from those remaining balances was now joined by a second theft of a similar size. Fran reiterated that this was an old contract outside Aztec Labs' control, unconnected to Aztec Network or the $AZTEC token, and framed the underlying risk as a broader one: legacy contracts that nobody is actively watching or maintaining.
That framing, however, sidesteps the more precise technical issue: the very immutability and key revocation that made the contract trustless is also what removed any administrative lever Aztec Labs could have pulled. The vulnerable circuit had been deleted from the codebase in PR #402, yet the EscapeHatchVk it had produced stayed live in the deployed verifier — responsible deprecation addressed the operational side of things without altering what the verifier itself would still accept as valid.
Between them, the June 14th Aztec Connect drain and this incident totaled more than $4 million lost across contracts the current team had no ability to touch — and that figure kept climbing once the follow-on $1,300 sweep landed the next morning.
There's a separate, harder question buried in here too: what is a white hat supposed to do upon finding a critical bug in a project nobody administers anymore? TrustSec posed exactly that question in the wake of the Aztec incidents: public disclosure risks tipping off every attacker watching the same feeds; attempting a solo white-hat rescue invites frontrunning bots, legal exposure, and execution risk; and sitting on the discovery just defers the problem to whoever finds it next, with no guarantee they'll weigh the tradeoffs the same way. None of the available options are clean.
05The cryptography held. The sunset didn't
Taken together, two separately-deprecated contracts, two distinct circuit-level defects, and north of $4 million in combined losses over three days sit alongside a team that had, by industry standards, done deprecation the right way: a year of advance notice, functioning exit infrastructure, an on-chain renunciation of admin keys, and a clean walk-away. That's precisely what makes assigning responsibility here unusually difficult.
Defi Edward posed the pointed version of the question: how many L2s claim to be decentralized without ever actually giving up their admin keys? Aztec genuinely did — the contract became fully trustless, which in this instance also meant there was no one left to call once the verifier kept honoring proofs generated against a circuit removed from the codebase years earlier.
The escape hatch itself wasn't the design flaw — it was meant to be the safety valve for users when every other exit closed. The actual defect was the binding gap sitting behind it: the circuit treated one root value as though it were two separate things, with nothing forcing them into agreement, which let a proof succeed even when the Merkle tree it referenced wasn't the tree the contract was actually checking on-chain.
Aztec 2.0 was deprecated back in 2022 and remained on-chain for roughly four years afterward — source code public, balances visible, verification key untouched — until someone finally scrutinized the circuit closely enough to spot the gap. The cryptography itself didn't fail; the sunset process, however carefully executed, ultimately did.
Get new scam files the moment we publish them — usually 2–3 emails a week.