☠ Case Studies
← All Case Studies

Euler Finance Exploit

💸 $197,000,000 🔒 Flawed Health Check in Donate/Mint Logic 📅 2023-03-01 00:00:00 +0000

A missing health check in the mint() function allowed an attacker to create leveraged positions and exploit accounting inconsistencies to drain $197M — most of which was later returned.

Background

Euler Finance was a permissionless lending protocol on Ethereum that allowed users to lend and borrow various tokens with leveraged positions. It was audited multiple times and considered secure. The exploit came from a subtle interaction between two features: mint() and donateToReserves().

The Vulnerability

The mint() function allowed creating synthetic leveraged positions — it created both collateral tokens (eTokens) and debt tokens (dTokens) simultaneously. The critical bug: no health check after minting. A healthy position check would have prevented undercollateralized positions from being created.

🚨 Key Vulnerable Concept
// mint() created leveraged positions without a health check function mint(uint subAccountId, uint amount) external { // Creates eToken (collateral) AND dToken (debt) simultaneously eToken.mint(amount); dToken.mint(amount); // BUG: No health check here! // A healthy position check would have prevented the attack // checkLiquidity(msg.sender); <-- this line was missing }

The Attack — Simplified

  1. Flash loan 30M DAI from Aave
  2. Deposit 20M DAI into Euler as collateral (receive eDAI)
  3. Call mint() to create 200M eDAI + 200M dDAI debt (10x leverage, no health check)
  4. Call donateToReserves(100M eDAI) — this reduces attacker's collateral dramatically
  5. Position is now massively undercollateralized and liquidatable
  6. Self-liquidate: claim the donated collateral as a liquidation "bonus" at a steep discount
  7. Repay flash loan, keep the profit from the accounting discrepancy
  8. Repeat with different assets. Total drained: ~$197M across DAI, USDC, WBTC, stETH

Impact & Recovery

This was one of the largest DeFi exploits of 2023. However, through on-chain negotiation and off-chain communication, the attacker returned almost all of the funds within weeks — reportedly motivated by concerns about legal exposure.

Euler Finance has since relaunched with a new codebase.

Lessons Learned

💡 Always Check Position Health After State Changes

Any function that modifies collateral or debt balances must verify that resulting positions are still healthy. This is especially critical for functions that create debt.

  • Health checks everywhere: After every state change involving debt or collateral, verify position health
  • Beware of donate-style functions: Any function that removes collateral should trigger a health check
  • Test feature interactions: Security audits must consider how features combine, not just each feature in isolation
  • Fuzz accounting invariants: Use Foundry's fuzzer to verify that no sequence of operations can break collateralization ratios