On March 13, 2023, our system detected that Euler Finance's lending pool had suffered a flash loan attack, resulting in losses of $197 million. We first alerted the community and then provided an analysis to help identify the root cause.
1/ @eulerfinance is attacked. The root cause is due to the lack of liquidity check in the function donateToReserves()https://t.co/stWtPWK900— BlockSec (@BlockSecTeam) March 13, 2023
See the detailed attack steps below. https://t.co/bm10OJHiXu pic.twitter.com/TDbYuzVWHe
The root cause of this incident is due to the lack of insolvency check in the function donateToReserves(). Specifically, the vulnerable contract provides a functionality for users to donate their collateral to the protocol without checking if the user's position was solvent. What's worse, to get rid of this bad position, the protocol offered a large discount for liquidators to pay less debt to liquidate this position. The attacker created a large position and made this position insolvent by exploiting this functionality. Then, he was able to buy his collateral at a discount to profit.
Euler Finance is a lending protocol on Ethereum that allows users to lend and borrow specified tokens. When lenders deposit into Euler's liquidity pool, a corresponding amount of ETokens (interest-bearing ERC20 tokens) is minted and sent to them. These ETokens can be redeemed for their deposited underlying assets.
On the other hand, borrowers who take liquidity receive DTokens. These DTokens are ERC20-compliant and prevent holders from burning them independently. Specifically, rather than allowing tokens to be sent to anyone, they can be taken by anyone, but accepting them requires approval. In terms of the underlying asset, borrowers are responsible for paying interest on their loans, and a portion of this interest is used to cover bad debts on the protocol.
Euler Finance's leverage borrowing (aka self-borrow) and soft liquidation mechanisms are two key concepts that help us better understand the cause of this attack.
Euler Finance provides a leverage borrowing feature, which enables users to simulate a recursive borrowing strategy. Simply put, users can deposit collateral and mint ETokens, which can then be used as collateral to borrow more ETokens. The contract will also mint a corresponding amount of dTokens as debt tokens. The health of the user's position is calculated based on the values of the ETokens and dTokens. According to the documentation of Euler Finance, users can leverage up to 19x. The leverage borrowing feature played a crucial role in this incident. Without the assistance of this feature, the attacker would not have been able to profit. Through leverage borrowing, the attacker amplified their position size to nearly 11x the initial funds obtained from the flash loan.
As outlined in Euler Finance’s whitepaper, the soft liquidation mechanism enables liquidators to help the liquidated party repay their debt flexibly, rather than being restricted to a fixed coefficient for liquidation as adopted by protocols like Compound and Aave. Soft liquidation means that the lower the health of a position, the more collateral is eligible for liquidation—up to 75% in the event of bad debt, based on data from this incident. The liquidation of substantially discounted collateral therefore allowed the attacker to settle the flash loan and secure a profit.
The main vulnerability, namely, the lack of an insolvency check, exists within the donateToReserves() function, which is used by users to transfer ETokens from their positions to the protocol's reserve as donations. For regular users, there is typically no incentive or motivation to perform such an action. Indeed, the vulnerability lies in the fact that the donateToReserves() function does not perform a health check when transferring ETokens out from user positions. This allows attackers to directly donate the ETokens from the large position created through leverage borrowing, causing the health of the position to drop below 100% and resulting in bad debt.
According to the design, Euler Finance uses a dynamic close factor to "soft liquidate" positions. In short, the less healthy a position is, the higher the proportion of the collateral in that position that can be liquidated. In the case of bad debt, the liquidation percentage can be as high as 75% of the collateral within the position (as calculated based on the actual attack transaction). As a result, the significant amount of discounted collateral that is liquidated enables the attacker to repay the flash loan and earn profits.
There are multiple attack transactions targeting different pools:
- 0xc310a0affe2169d1f6feec1c63dbc7f7c62a887fa48795d327d4d2da2d6b111d (DAI)
- 0x71a908be0bef6174bccc3d493becdfd28395d8898e355d451cb52f7bac38617 (WBTC)
- 0x62bd3d31a7b75c098ccf28bc4d4af8c4a191b4b9e451fab4232258079e8b18c4 (wstETH)
- 0x465a6780145f1efe3ab52f94c006065575712d2003d83d85481f3d110ed13d9 (USDC)
- 0x3097830e9921e4063d334acb82f6a79374f76f0b1a8f857e89b89bc58df1f311 (stETH)
- 0x47ac3527d02e6b9631c77fad1cdee7bfa77a8a7bfd4880dccbda5146ace4088f (WETH)
The attack steps are as follows (taking the first attack transaction as an example):
- The attacker borrow 30M DAI in AAVE via flashloan.
- The attacker deposited 20M DAI and got back 20M eDAI.
- Since Euler Finance provides the capability of leverage borrow, the attacker can mint 195M eDAI and 200M dDAI. Now the attacker holds 215M eDAI and 200M dDAI.
- Continued above. 10M debt was repaid so that the attacker can mint more eDAI. Now the attacker holds 215M eDAI and 190M dDAI.
- Step 3 was repeated. Now the attacker holds 410M eDAI and 390M dDAI.
- The attacker invoked the function donateToReserve to donate 100M eDAI. However, during this process, the health factor of the attacker was not checked. In this case, the position can now be liquidated (310M eDAI vs. 390M dDAI), which leaves the chance to gain profit.
- The attacker liquidated the position using another address contract as liquidator (0xa0b3...). Liquidator (0xa0b3...) received 310M eDAI and 259M dDAI.
- The attacker burned 38.9M eDAI to withdraw 38.9M DAI (cannot withdraw more due to insolvency checks) in liquidator's position (0xa0b3...).
- The attacker repaid the flashloan.
The key attack steps 2-7 are labeled in the transaction trace.
This was the largest hack in 2023, with a record-breaking $197 million in funds stolen by a 20-year-old Argentinian named Federico Jaime, who provided the media with "a winding, sometimes confusing, and even contradictory narrative." Nonetheless, "all of the recoverable funds" were later restored to Euler Finance's treasury address. However, a small portion (around $200K) was "unwittingly" sent to the Lazarus Group—an alleged state-sponsored North Korean crime syndicate sanctioned by the US Treasury. You can refer to these links, i.e., link2 and link2, for the detailed and interesting story.
The root cause of this incident was a lack of insolvency checks, which serves as a lesson. In fact, for a lending protocol, it is crucial to assess whether position health checks should be implemented for any procedures that might impact user positions. Additionally, project teams should proactively monitor their lending protocol for significant liquidations and establish effective alert systems to promptly detect and respond to such events.