Case Study 2: The Euler Finance Hack — $197M Flash Loan Attack and the Dramatic Recovery
Background
Euler Finance was a non-custodial lending protocol on Ethereum that launched in December 2022. Unlike simpler lending protocols like Compound or Aave, Euler introduced several innovations, including permissionless listing of assets (any ERC-20 token could be used as collateral, not just a curated whitelist), reactive interest rates, and a novel liquidation mechanism. By March 2023, Euler had accumulated over $200 million in total value locked (TVL), making it one of the larger DeFi lending protocols.
Euler had undergone multiple security audits. The protocol was audited by Halborn, Solidified, ZK Labs, Certora, Sherlock, and Omniscia. It had a bug bounty program on Immunefi with payouts up to $1 million. By any measure, Euler took security seriously. The number and reputation of its auditors would have given most users reasonable confidence in the protocol's safety.
On March 13, 2023, all of that confidence evaporated in a single transaction.
The Vulnerability
The vulnerability existed in Euler's donateToReserves function, which was introduced in a code update (EIP-14) in July 2022 — roughly eight months before the attack. This function allowed users to donate their deposited tokens to the protocol's reserve fund. The function was intended as a mechanism for charitable contributions to the protocol, but it had a critical flaw: it did not check whether the donation would leave the donor's account in an undercollateralized (liquidatable) state.
In Euler's architecture, deposits were represented by "eTokens" (earning tokens that accrued interest) and debts by "dTokens" (debt tokens that tracked what was owed). The health of an account was determined by the ratio of eToken value to dToken value. If this ratio fell below the liquidation threshold, the account could be liquidated.
The donateToReserves function reduced the donor's eToken balance without checking the resulting health factor. This meant a user could:
- Deposit collateral and borrow against it (creating both eTokens and dTokens).
- Donate their eTokens to the reserve, destroying their collateral.
- Their account was now undercollateralized — they owed more than they had deposited.
- The account could now be liquidated, but the liquidation process in Euler transferred a bonus of collateral to the liquidator (as an incentive for performing liquidations).
The key insight was that by combining self-liquidation with the donate function and flash loans for amplification, an attacker could extract far more value than they put in.
The Attack
The attacker executed the exploit across six transactions on March 13, 2023. The core attack mechanism, reconstructed from on-chain analysis, followed this pattern:
Step 1: Flash Loan. The attacker borrowed a large amount of DAI from Aave via flash loan. The initial flash loan was 30 million DAI.
Step 2: Deposit and Borrow. The attacker deposited the flash-loaned DAI into Euler, receiving eDAI tokens. They then used the eDAI as collateral to borrow more DAI (via dDAI tokens). Euler's leverage mechanism allowed the attacker to amplify their position through repeated deposit-borrow cycles, reaching approximately 10x leverage.
Step 3: Donate. The attacker called donateToReserves, transferring a large portion of their eDAI to Euler's reserve. This destroyed their collateral while leaving their debt intact. The attacker's account was now deeply undercollateralized.
Step 4: Self-Liquidation. Using a second contract (acting as the liquidator), the attacker liquidated their own undercollateralized position. Euler's liquidation mechanism transferred the remaining collateral to the liquidator plus a liquidation bonus. Because of how Euler calculated the liquidation discount and the interaction with the reserve donation, the liquidator received more value than the total debt.
Step 5: Repay Flash Loan. The attacker repaid the Aave flash loan from the profits.
Step 6: Repeat. The attacker repeated this process with different assets: DAI, USDC, WBTC, and stETH. Across six transactions, they extracted a total of approximately $197 million:
- $8.7 million in DAI
- $18.5 million in WBTC
- $135.8 million in stETH
- $33.8 million in USDC
The total attack cost (gas fees) was less than $50.
Why the Audits Missed It
Six audit firms reviewed Euler's code. The donateToReserves function was introduced after some of these audits, and while subsequent audits reviewed the updated code, the vulnerability was not flagged. Several factors contributed:
Composability of operations. The vulnerability was not in any single function but in the interaction between donateToReserves, the leverage mechanism, and the liquidation system. Each function worked correctly in isolation. The bug emerged only when they were combined in a specific sequence. This is the composability risk discussed in Section 15.7.2 — a contract can be secure in isolation but vulnerable when its components interact in unexpected ways.
Audit scope limitations. Each audit may have focused on specific aspects of the protocol. The donateToReserves function, viewed in isolation, appeared harmless — it simply reduced the caller's eToken balance and increased the reserve. The missing health check was only dangerous in the context of the broader liquidation system.
Point-in-time analysis. Audits review the code as it exists at the time of the audit. EIP-14 (which introduced donateToReserves) may have been audited by some firms but not others, and subsequent code changes may not have been reviewed with full context.
The attack required deep protocol-specific knowledge. The attacker needed to understand the precise mathematics of Euler's liquidation discount, the interaction between eTokens and dTokens during donation and liquidation, and the ability to use flash loans to amplify the effect. This required a level of protocol-specific expertise that even skilled auditors may not develop during a time-limited audit engagement.
The Recovery: Negotiation and Return
What happened after the attack is almost as remarkable as the attack itself.
Day 1-2 (March 13-14): Euler paused the protocol to prevent further damage. On-chain analysis quickly traced the attacker's addresses. Euler sent an on-chain message to the attacker:
"We understand you are responsible for this morning's attack on the Euler protocol. We are writing to see whether you would be open to speaking with us about any potential next steps."
Day 3-7 (March 15-19): Multiple parties attempted to communicate with the attacker. Euler offered a 10% bounty ($19.7 million) for the return of 90% of funds. Blockchain analysis firms traced some of the stolen funds to addresses linked to the Tornado Cash mixer, suggesting the attacker was attempting to launder the proceeds. However, the attacker also began making unexpected moves: they sent 100 ETH ($170,000) to an address affected by the exploit that was identified as belonging to a different protocol's deployment address.
Week 2 (March 20-25): The situation took a dramatic turn. The attacker began returning funds. On March 18, they returned 3,000 ETH ($5.4 million). Then the pace accelerated. On March 25, the attacker sent an on-chain message to Euler:
"I want to make this easy on all those affected. I don't have any intention of keeping what is not mine. Returning all the remaining funds."
Week 3 (March 26-April 3): The attacker returned the remaining funds in multiple transactions. By April 3, 2023, Euler confirmed that all stolen assets had been returned. The total returned was approximately $197 million — virtually the entire stolen amount.
Why did the attacker return the funds? The exact motivation is unknown, but several factors likely contributed:
- Blockchain forensics made laundering difficult. Despite using Tornado Cash, on-chain analysis firms were making progress in linking the attacker's addresses to potentially identifiable information. The FBI was also reportedly involved.
- Legal risk. The Mango Markets exploiter had been arrested by the FBI in December 2022, just three months before the Euler hack. The legal precedent that DeFi exploits could result in criminal prosecution was fresh.
- Bounty negotiation. Euler reportedly negotiated with the attacker, though the exact terms were not publicly disclosed.
- Moral pressure. On-chain messages from affected users, some describing the personal impact of losing their savings, may have influenced the attacker's decision.
The Technical Fix
After the funds were returned, Euler implemented the fix: the donateToReserves function now includes a health check that verifies the donor's account remains sufficiently collateralized after the donation. If the donation would push the account below the liquidation threshold, the transaction reverts.
The fix was a single require statement — a health check that should have been present from the beginning. The entire $197 million exploit was enabled by the absence of one conditional check.
// Simplified representation of the fix
function donateToReserves(uint subAccountId, uint amount) external {
// ... donation logic ...
// THE FIX: Check health after donation
require(
checkLiquidity(account) >= 0,
"e/donate-would-cause-undercollateralization"
);
}
Financial Impact and Aftermath
Direct losses: $197 million stolen, $197 million returned. Net direct loss to users: approximately zero (though users were locked out of their funds for three weeks, suffering opportunity cost and emotional distress).
Protocol impact: Euler's TVL dropped from over $200 million to near zero during the exploit. Even after the funds were returned, user confidence was severely damaged. Euler's TVL did not recover to pre-attack levels. In 2024, Euler relaunched as "Euler v2" with a redesigned architecture, aiming to rebuild trust.
Insurance payouts: Some Euler users had purchased smart contract insurance through Nexus Mutual and other providers. Claims were filed and assessed, though the full return of funds complicated the claims process (if the funds were returned, was there a loss to insure against?).
Audit industry reckoning. The Euler hack intensified the debate about the value of audits. Six firms had reviewed the code, and none caught the vulnerability. This reinforced the principle that audits reduce risk but do not eliminate it, and that the composability of DeFi protocols creates attack surfaces that exceed the scope of any individual audit.
Lessons Learned
1. Composability is the hardest problem in DeFi security. The vulnerability was not in any single function but in the interaction between donation, leverage, and liquidation. Testing and auditing individual functions is necessary but insufficient — the interactions between functions and between protocols must also be analyzed.
2. New code is dangerous code. The vulnerable donateToReserves function was added eight months before the attack, after the initial audits. Any code change, no matter how seemingly minor, can introduce critical vulnerabilities. Every change should be re-audited with the same rigor as the original deployment.
3. Health checks are non-negotiable. Any function that modifies a user's position in a lending protocol must verify that the account remains healthy afterward. This is an invariant — a property that must always hold — and it should be enforced at the function level, not assumed.
4. Flash loans amplify everything. The attack was only possible because flash loans provided the capital to reach the extreme leverage ratios needed to make the exploit profitable. Any protocol design must assume that attackers can temporarily access unlimited capital.
5. Transparency cuts both ways. The blockchain's transparency allowed the community to trace the attacker's transactions, apply social pressure, and ultimately contribute to the fund recovery. But it also allowed the attacker to identify and exploit the vulnerability through open-source code analysis.
6. Fund recovery is possible but not guaranteed. The Euler case had a happy ending — all funds were returned. But this is the exception, not the rule. The Ronin Bridge ($625M), Wormhole ($326M), and many other exploits resulted in permanent losses. Security cannot depend on the hope that an attacker will return the funds.
Discussion Questions
-
Does the full return of funds change your assessment of the attack's severity? Should protocols and auditors treat it differently from an attack where funds were permanently lost?
-
Six audit firms reviewed Euler's code and missed the vulnerability. Does this indicate a systemic problem with the audit industry? What changes to the audit process could help catch composability vulnerabilities?
-
The attacker returned the funds, possibly due to legal pressure and blockchain forensics. As blockchain forensics improve and legal precedents against DeFi exploiters increase, do you expect the rate of fund returns to increase? How might this change the threat landscape?
-
The Euler exploit was enabled by a missing health check — a single
requirestatement. How can protocols ensure that every state-modifying function enforces all necessary invariants? Is formal verification the answer, and if so, why is it not more widely adopted? -
The
donateToReservesfunction was introduced after the initial audits. What processes could ensure that post-audit code changes receive the same security scrutiny as the original codebase? How should continuous security monitoring complement periodic audits? -
Compare the DAO hack (Case Study 1) with the Euler hack. Both involved reentrancy-adjacent issues (the DAO's was classic reentrancy; Euler's involved state manipulation across function calls). Both were exploited despite prior code review. What has the industry learned in the seven years between these events, and what has it failed to learn?