On July 30, 2023, multiple Curve.Fi liquidity pools were exploited due to a latent vulnerability in the Vyper compiler, specifically in versions 0.2.15, 0.2.16, and 0.3.0, resulting in approximately $70 million in losses. This caused panic within the DeFi community.
The hacks led to a 5% decline in CRV, Curve’s native token, and triggered fears of contagion effects for some DeFi protocols. The lending protocol AAVE appeared to be at risk due to a massive borrow position secured by CRV token collateral.
This report provides a deep-dive into the Vyper compiler’s vulnerability, its root cause, and the lessons learned from the incident.
What is Vyper?
Vyper is a contract-oriented, domain-specific, pythonic programming language targeting the Ethereum Virtual Machine (EVM). Its main goals include simplicity, pythonicity, security, and auditability.
Re-Entrancy: A Widespread Web 3.0 Problem
Re-entrancy is a common problem in blockchain programs. It occurs when the control flow of a contract is relinquished to another invoked program, allowing the invoked contract to re-enter the original caller while it is frozen.
The ecosystem has developed two ways to combat re-entrancy attacks: the Checks-Effects-Interactions (CEI) pattern and re-entrancy guards. Vyper introduced a re-entrancy guard at the language level via the special `@nonreentrant` function decorator.
Vyper Vulnerability Historical Timeline
The @nonreentrant` decorators were introduced in the v0.1.0-beta.9 release of Vyper, offering flexibility by allowing a key to be set.
Beginning in 2018, the Vyper compiler started a multi-year effort to refactor its architecture. This culminated in 2023 with PR#3390.
PR#2308 and PR#2379 were part of efforts to make storage allocation smarter and avoid corruption. However, these updates introduced bugs, leading to the “yanking” of v0.2.13 and v0.2.14 releases.
Issue #2393 revealed that re-entrancy guard tests were failing in v0.2.14, leading to an overlap in storage.
The v0.2.15 release attempted to fix the corruption but introduced a vulnerability where all `@nonreentrant` decorators within a Vyper contract would utilize a unique storage offset regardless of their key.
The vulnerability went undetected for a 4-month period between July 21, 2021, and November 30, 2021.
The v0.3.1 release resolved the vulnerability through two different PRs, PR#2439 and PR#2514.
Versions Affected: v0.2.15, v0.2.16, v0.3.0
Root Cause: Improper remediations to re-entrancy guard data corruption issues introduced in v0.2.13
Vulnerability in Brief:** Cross-function re-entrancy is possible on all contracts compiled with the susceptible versions.
The Vyper team has outlined several practical steps to improve the correctness of smart contracts compiled with Vyper, including improved testing, providing developers with better tools, tighter feedback with protocols, and focusing on securing past releases.
New security-related initiatives within and beyond the Vyper team include:
1. A short-term, competitive audit in partnership with Codehawks
2. Bug bounty programs in partnership with Immunefi
3. The Vyper Security Alliance
4. Collaboration with multiple audit firms
5. Expansion of the team, including a dedicated security engineering role
6. Collaboration with existing security toolkits
7. Design of a language specification
The Vyper team’s commitment to learning from this incident and implementing these initiatives reflects their dedication to making Vyper a rock-solid and secure smart contract language and compiler project.
Image source: Shutterstock