30682 - [SC - Critical] Insufficient slippage control in RevenueHandler...
Insufficient slippage control in RevenueHandler leads to loss of funds
Submitted on May 4th 2024 at 10:35:52 UTC by @infosec_us_team for Boost | Alchemix
Report ID: #30682
Report type: Smart Contract
Report severity: Critical
Target: https://github.com/alchemix-finance/alchemix-v2-dao/blob/main/src/RevenueHandler.sol
Impacts:
Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield
Description
Brief
Due to insufficient slippage control, an attacker can sandwich Alchemix revenue checkpoints with a flash loan, stealing a portion of the tokens that should be distributed to veALCX stakers.
Description
When the poolAdapter is set, the revenue token (WETH
for example) is swapped in a Curve pool for an "alchemic-token" (alETH
for instance) during each revenue checkpoint.
The flagged logic is inside the _melt
function of the RevenueHandler.sol smart contract:
The comments in the code snippet are from the Alchemix team.
Link to the snippet of code: https://github.com/alchemix-finance/alchemix-v2-dao/blob/main/src/RevenueHandler.sol?utm_source=immunefi#L275-L295
The comments make a correct assumption about the price of "alAssets", but the code implementation does not protect the protocol from losses due to sandwich attacks.
Vulnerable Implementation
The pseudo-code of the _melt(address revenueToken)
implementation that uses the CurveEthPoolAdapter
is:
1- Swap the revenueToken
(WETH) for ETH by calling WETH.withdraw(_amount)
2- Swap the ETH for the debtToken
(alETH).
3- Enforce that the amount of debtToken
we receive is equal to or bigger than the same amount of revenueToken
we sent.
Hopefully flowcharts are rendered correctly, we will see.
Alchemix's test suite runs at block number 17133822.
This can be verified in the
alchemix-v2-dao/Makefile
file.
The eth/alETH exchange rate in the curve pool when running the test suite is 10.00 eth => 10.12 alETH
This can be verified by adding to the
testSlippageCheckpointETH
function of the test filealchemix-v2-dao/src/test/RevenueHandler.t.sol
the 2 lines below and running the test at block number 17133822:
Alchemix created tests simulating a checkpoint for 10 WETH of revenue.
Under these market conditions the RevenueHandler should receive 10.12 alETH.
Because the implementation of the code only cares for receiving at least 10 alETH, it is possible to manipulate the price of the pool with a flash loan and sandwich attack so the RevenueHandler receives exactly 10 alETH and the attacker profits 1.14 % of the protocol's revenue during that epoch (0.114 ETH).
Increasing Economic Damage
With the exchange rate of 10 ETH
== 10.12 alETH
used in the tests, we prove in a PoC attached to this report that losses are ~1.14% of the protocol's revenue every epoch.
Currently, the exchange rate in Curve is 10 ETH
== 11.02 alETH
.
Exploiting this attack vector in current market conditions for a 10 ETH
protocol revenue leads to losing close to ~9.26% of protocol revenue (1.02 alETH).
The protocol should receive 11.02 alETH but only receives 10 alETH.
The economic damage of this attack vector keeps increasing every time the price of alETH decreases.
Requirements
Anyone can call RevenueHandler.checkpoint()
so flash loans can be used to fund the attack. No capital or permissions are required to execute it.
Impact Details
Loss of funds.
Proof of Concept
We modified your current testCheckpointETH()
in alchemix-v2-dao/src/test/RevenueHandler.t.sol
, adding the price manipulation before and after the checkpoint, to demonstrate the impact of the exploit.
Remember to run the code with the correct block number (the one used in your tests: 17133822)
We run the test executing:
Replace {API_KEY} with your API key.
The code for the test:
Last updated