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 file alchemix-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

Was this helpful?