Curve Finance Vyper Reentrancy Compiler Bug (July 30, 2023)

On July 30, 2023, multiple Curve Finance stable pools were drained via a previously-unknown bug in the Vyper smart-contract compiler's @nonreentrant decorator. Vyper versions 0.2.15, 0.2.16, and 0.3.0 generated reentrancy-guard bytecode that did not actually enforce mutual exclusion across functions sharing the same lock identifier, contradicting the documented and assumed behavior of the decorator. The bug had existed in production-deployed Curve pools since their original 2021-2022 deployment and went undetected by Curve's auditors and by the Vyper team itself for approximately two years. Total losses across the affected pools (JPEG'd's pETH/ETH, Metronome's msETH/ETH, Alchemix's alETH/ETH, plus Curve's own CRV/ETH pool) reached approximately $73.5M before the attacks were halted by liquidity withdrawals and whitehat counter-action. A figure publicly known as c0ffeebabe.eth executed MEV frontruns of the original attackers, returning 2,879 ETH (about $5.4M) to Curve along with funds taken from the Metronome pool. After a week of public 10% bounty offers, exploiters returned the Alchemix and JPEG'd funds; cumulative recovery reached approximately $52.3M, about 73% of the gross loss, and Curve DAO voted in December 2023 to reimburse remaining LP losses with a $49.2M distribution. Curve founder Michael Egorov's heavily-leveraged personal CRV position became briefly systemic-risk territory before being unwound through OTC sales to Justin Sun, DCFGod, and others.

Timeline of events

On July 30, 2023, attackers began draining Curve stable pools compiled with vulnerable Vyper versions, exploiting a reentrant pattern that should have been impossible given the pools' @nonreentrant lock decorations. JPEG'd's pETH/ETH pool lost approximately $11.4M, Metronome's msETH/ETH pool approximately $1.6M, and Alchemix's alETH/ETH pool approximately $13.6M. Security researchers including BlockSec and PeckShield quickly identified that the common factor was Vyper compiler version: each affected pool had been compiled with a Vyper version in the 0.2.15-0.3.0 range, and the Vyper development team confirmed the compiler bug the same day. Curve responded by deploying public guidance to liquidity providers to withdraw from affected pools; many pools that would have been vulnerable were drained of LP positions before they could be exploited. A separate front, Curve's own CRV/ETH pool, was also drained, with roughly 32M CRV worth over $22M taken from the pool. During the attacks, c0ffeebabe.eth - a sophisticated MEV searcher - executed whitehat frontruns of in-progress drain attempts, returning 2,879 ETH (about $5.4M) to Curve and later returning funds taken from the Metronome pool. Total gross losses were approximately $73.5M. Curve, Alchemix, Metronome and JPEG'd publicly offered the attackers a 10% bounty for returning funds; the Alchemix exploiter returned all of Alchemix's stolen funds by early August, and JPEG'd's funds were returned against a 610 ETH bounty. Recovered funds ultimately reached approximately $52.3M of the gross $73.5M, an effective recovery rate near 73%.

Attack mechanism

Vyper's @nonreentrant(key) decorator is documented to provide mutual-exclusion semantics: any two functions tagged with the same key cannot execute concurrently within a single transaction, preventing reentrancy attacks. The decorator works by reserving a storage slot identified by the key, setting it to 1 on function entry, asserting it is 0 on entry, and clearing it on exit. The bug introduced in Vyper 0.2.15 and present through 0.3.0 was that the storage slot allocation for the key was performed per-function rather than per-key during code generation: each function tagged with @nonreentrant(\"lock\") received its own distinct storage slot rather than sharing a slot identified by the \"lock\" string. The result was that two functions both decorated with @nonreentrant(\"lock\") - which the developer assumed would mutually exclude - were in fact gated by entirely separate storage slots and could be invoked reentrantly with respect to each other. In Curve's stable pools, the add_liquidity, remove_liquidity, and exchange functions all carried the same @nonreentrant decorator and were therefore assumed to be mutually exclusive. The attacker exploited this in pools holding native ETH: withdrawing liquidity triggers a raw ETH transfer to the caller, which hands execution to the attacker contract's fallback function mid-call. From that fallback the attacker reentered the pool while its internal balance state had not yet been finalized. Because the functions had different storage-slot reentrancy guards, the reentrant call succeeded, letting the attacker interact with the pool at manipulated prices and extract more value than contributed.

Root cause analysis

The proximate root cause is a Vyper compiler defect: the @nonreentrant decorator's storage-slot allocation logic in versions 0.2.15-0.3.0 used a per-function rather than per-key indexing scheme, contradicting the documented contract of the decorator. The bug was introduced by a refactor of the storage-allocation pass in version 0.2.15 and was not caught by Vyper's own test suite, which apparently lacked a test case for the multi-function-shared-key scenario despite the decorator being explicitly documented to support exactly that pattern. The contributing causes are several. First, Curve's pool audits by Trail of Bits, MixBytes and others had reviewed the pool source code and the assumed Vyper semantics but had not independently verified the compiled bytecode against the assumed reentrancy semantics; this is a deeper issue because audit firms generally trust compiler correctness as an axiom. Second, the Vyper compiler at the time had a smaller user community than Solidity and a correspondingly thinner ecosystem of compiler-correctness tooling; bugs in the compiler had longer mean-time-to-detection than equivalent Solidity bugs. Third, Curve's pool-deployment process did not pin compiler versions explicitly per pool; the affected pools had been deployed at various points in 2021-2022 with whatever Vyper version was current, and the compiler-version diversity was not centrally tracked or audited. The structural lesson is that the compiler is part of the trusted computing base of any smart contract, and protocols holding nine-figure value must treat compiler behavior as a verified rather than assumed property of the system.

Initial response and recovery

Curve's response was rapid in execution but exposed structural fragility in protocol governance. Within the first hour of the attacks, Curve and the Vyper team had publicly confirmed the compiler bug and issued guidance for liquidity-provider withdrawal from affected pools. Within four hours, Curve had identified all pools deployed with affected Vyper versions and was coordinating withdrawal flow. The whitehat work by c0ffeebabe.eth returned 2,879 ETH (about $5.4M) to Curve within days, with Metronome-pool funds returned as well. The negotiation tracks with the original attackers were unusual: Curve, Alchemix, Metronome, and JPEG'd publicly offered each attacker a 10% effective bounty for returning the principal, with a deadline of August 6; after the deadline passed, Curve extended a $1.85M public bounty for information identifying and convicting the exploiter. The Alchemix exploiter returned all of Alchemix's stolen funds, and JPEG'd's funds came back against a 610 ETH bounty. By mid-August, gross recovery had reached approximately $52.3M of the original $73.5M, with the remainder either still on attacker addresses or laundered. In December 2023, Curve DAO tokenholders voted 94% in favor of a $49.2M reimbursement covering remaining LP losses across the CRV, JPEG'd, Alchemix, and Metronome pools. Beyond the direct exploit losses, the secondary crisis was Michael Egorov's personal CRV-collateralized loan position: Egorov had borrowed approximately $100M against CRV collateral on Aave, Frax, and other lending venues, and the post-exploit CRV price decline of nearly 30% - to a low around $0.48 - threatened to liquidate that position with cascading on-chain consequences that would have driven CRV further down and potentially produced bad debt on Aave. Egorov defused the crisis in early August through a series of OTC CRV sales at $0.40 per token to Justin Sun (Tron founder), Machi Big Brother, DWF Labs, and several other large buyers, raising tens of millions of dollars to pay down the most exposed loans.

Funds tracking and laundering

The fund flows in the Curve incident were unusually heterogeneous because of the multiple distinct attackers. The principal whitehat actor, c0ffeebabe.eth, captured funds via MEV frontrunning and returned them publicly within days, including 2,879 ETH (about $5.4M) sent back to Curve. Original attackers subsequently returned funds under the protocols' public 10% bounty offers: the Alchemix exploiter returned all of Alchemix's stolen funds by early August, and JPEG'd's funds were returned against a 610 ETH bounty. The exploiters used direct on-chain messaging to communicate with the protocol teams; the messages were public and have been preserved on-chain. Roughly $21M of the gross loss was never returned. On-chain tracking indicated that a portion of the residual remained in identifiable attacker-controlled positions; the remainder was obfuscated. No attribution to known threat groups (Lazarus or otherwise) was made by any major investigator, and the heterogeneity of the attackers - some sophisticated whitehats, some clearly opportunistic, some negotiation-willing, some not - suggested no single coordinated actor.

Legal and regulatory aftermath

The Curve Vyper incident produced no publicly reported regulatory enforcement, primarily because no clear sanctionable actor was identified. The negotiations between Curve / Alchemix / JPEG'd and the attackers raised informal questions about whether the 10% effective bounty payments to actors who had clearly committed unauthorized access constituted illegal payments under U.S. computer-fraud and wire-fraud statutes; legal commentary at the time was divided, with some arguing that a payment to a ransom actor in exchange for return of stolen property could be a violation of OFAC guidance even absent a sanctionable counterparty. No enforcement action followed. The longer-running regulatory effect was on smart-contract-language standardization: the Vyper bug accelerated discussions about whether protocol issuers should be held to disclosure requirements regarding compiler versions and whether audit firms should be required to verify compiler behavior as part of an audit. No formal rules emerged, but several institutional auditors revised their published standards to include compiler-bytecode verification as a recommended (though not always required) step for protocols holding above-threshold value. The Vyper team itself undertook a substantial post-incident security program, including audits, security competitions, and a reworked storage-allocation and reentrancy-lock design shipped in the major 0.4.0 release in 2024.

Industry implications

Curve's Vyper incident reshaped four areas of practice. First, compiler trust assumptions: the era of treating the compiler as an axiomatic component of the trusted computing base ended for nine-figure protocols; subsequent audits by Trail of Bits, OpenZeppelin and others have increasingly included a bytecode-verification step that confirms compiler-generated code matches assumed semantics. Second, Vyper-specific scrutiny intensified, with post-incident investment in audits, security competitions, and a re-architected compiler with deliberate testing of compiler-correctness properties. Third, the founder-leverage problem became publicly visible: Egorov's $100M+ CRV-collateralized loan position created systemic risk that could have produced a Curve protocol collapse from a non-protocol cause, prompting widespread reassessment of governance-token founder-leverage as a risk factor in DeFi protocol due diligence. Subsequent protocols (Aave, Compound, Maker) tightened their governance policies on accepting founder-controlled tokens as collateral. Fourth, the negotiation-with-attackers model proved partially viable: the 73% recovery rate via combination of whitehat frontrunning and 10%-bounty negotiation became a reference outcome for subsequent incidents (Euler Finance's full recovery after its March 2023 exploit was structurally similar though achieved at higher recovery rate), establishing public negotiation as a legitimate post-exploit recovery mechanism in the DeFi practitioner's toolkit.

Verdict and lessons

The Curve Vyper incident is the canonical case for compiler-as-trusted-computing-base risk in smart-contract development. The contracts were correctly written, the audits were performed by reputable firms, and the protocol's economic and architectural design was sound. The failure was below the source-code layer entirely: the compiler generated bytecode that did not implement the documented semantics of a critical decorator. Nine-figure value was protected by what the developers assumed was mutex semantics but was in fact two distinct storage slots that could be reentered against each other. The lessons are concrete. First, for high-value protocols, compiler bytecode must be verified against assumed semantics, ideally via formal methods, and audit scope must explicitly include compiler-correctness assumptions. Second, compiler-version pinning at deployment must be tracked, audited, and surfaced in protocol documentation; users of a protocol have no current mechanism to know which compiler version produced the contracts they are interacting with, and that opacity is itself a risk factor. Third, the negotiation-with-attackers pathway is valuable but legally fraught and should be treated as a planned-for-but-not-relied-upon recovery mechanism. Fourth, founder-leverage in governance-token positions must be a first-class governance risk, with disclosure requirements and ideally protocol-level constraints. The CRV protocol survived the incident in a nominal sense - the recovery was substantial and the protocol continues to operate - but the second-order damage to Vyper's adoption trajectory and the widespread re-examination of compiler trust assumptions has been broadly beneficial to smart-contract security overall.

Root cause

Vyper compiler versions 0.2.15, 0.2.16, and 0.3.0 generated bytecode for the @nonreentrant(key) decorator that allocated storage slots per-function rather than per-key, meaning two functions decorated with the same key did not actually share a mutex and could be reentered against each other. Multiple Curve stable pools (alETH/ETH, msETH/ETH, pETH/ETH, CRV/ETH) had been compiled with affected versions and assumed mutex semantics that did not exist in the deployed bytecode. Attackers exploited the gap by calling add_liquidity and reentering remove_liquidity through the LP-token mint callback, extracting value from the disrupted pool invariant.

Recovery and aftermath

Approximately $52.3M (73%) of gross losses recovered: c0ffeebabe.eth returned 2,879 ETH (~$5.4M) to Curve plus Metronome-pool funds via whitehat frontrunning, and exploiters returned the Alchemix and JPEG'd funds under 10% bounty offers, leaving ~$21M residual unrecovered. Curve DAO voted in December 2023 to distribute $49.2M to make remaining LP losses whole. Protocol survived; founder Michael Egorov defused his $100M+ CRV-collateralized loan position via OTC CRV sales at $0.40 to Justin Sun and others in early August 2023.

Lessons

Precedent

Established compiler bytecode verification as a recommended audit step for nine-figure protocols. Validated negotiation-with-attackers (10% effective bounty) as a legitimate post-exploit recovery mechanism. Surfaced founder-leverage in governance tokens as a first-class governance risk factor. Drove a major post-incident security overhaul of the Vyper compiler (shipped as 0.4.0 in 2024).

Frequently asked questions

How much was stolen in the Curve Finance hack?

Approximately $73M was stolen from multiple Curve stable pools.

What caused the Curve Finance exploit?

A vulnerability in the Vyper compiler's @nonreentrant decorator that failed to prevent reentrancy.

Who was responsible for the Curve Finance exploit?

Multiple actors, including a whitehat known as c0ffeebabe.eth who frontran attackers and returned funds.

Did Curve Finance recover the funds?

About 73% of losses were recovered through returns from whitehat and negotiations with attackers, leaving ~$21M unrecovered.

When did the Curve Finance hack happen?

July 30, 2023.