DeFiFoundrySolidity
16,653 OP
View results
Submission Details
Severity: medium
Invalid

Insufficient Swap Price Validation in _swapUnderlyingToAsset Function

Summary

The _swapUnderlyingToAsset function does not validate the swap price beyond a basic minOut parameter check. This could lead to swaps being executed at unfavorable rates, resulting in economic losses for the contract. Additionally, the reliance on external inputs like _path and minOut without further validation increases the risk of inefficiencies and manipulation.

Vulnerability Details

function _swapUnderlyingToAsset(uint256 _amount, uint256 minOut, IRamsesRouter.route[] calldata _path) internal {
// TODO : we swap WETH to ALETH -> need to check that price is better than 1:1
// uint256 oraclePrice = 1e18 * 101 / 100;
require(minOut > _amount, "minOut too low");
uint256 underlyingBalance = underlying.balanceOf(address(this));
require(underlyingBalance >= _amount, "not enough underlying balance");
IRamsesRouter(router).swapExactTokensForTokens(_amount, minOut, _path, address(this), block.timestamp);
}

The function allows swapping WETH for alETH using the Ramses Router, but it does not verify the swap price against an on-chain oracle or any reliable price source. Instead, it relies solely on the minOut parameter provided by the caller. This lack of price validation introduces the following risks:

  • Economic Inefficiency: Swaps may occur at suboptimal rates, especially in volatile markets.

  • Manipulation: A malicious or careless keeper could set an excessively low minOut value, leading to poor trade execution.

  • Market Vulnerability: During periods of low liquidity or high volatility, the function may execute swaps that deviate significantly from the intended value.

Impact

Severity: Medium

  • Likelihood: High

  • Impact Level:

    • Medium in stable market conditions due to minor inefficiencies or slippage.

    • High in volatile markets or during malicious exploitation, leading to substantial economic losses.

Tools Used

Manual Review

PoC

Exploiting Insufficient Swap Price Validation

  1. Setup:

    • The contract interacts with the Ramses Router to swap WETH for alETH.

    • The _swapUnderlyingToAsset function requires only that minOut > _amount, but it does not validate if the swap rate is favorable or above 1:1.

  2. Attack Steps:

    • The attacker observes the function logic and determines that no oracle or price check is in place.

    • They manipulate the market or set up a malicious path that results in a very unfavorable swap rate (e.g., receiving only 0.5 alETH per WETH swapped).

    • They invoke the _swapUnderlyingToAsset function with:

      • _amount: The WETH they want to swap (e.g., 100 WETH).

      • minOut: A value marginally greater than _amount (e.g., 100.1 alETH).

      • _path: A custom malicious swap path leading to poor rates or involving malicious routers/contracts.

  3. Exploit Outcome:

    • The function executes the swap, and the attacker receives 100.1 alETH at a very unfavorable rate (e.g., they could have received 150 alETH at market rates).

    • The contract loses value due to the suboptimal swap, effectively transferring the value difference to the attacker.

PoC Implementation:

Below is a simplified script demonstrating how an attacker might execute the exploit:

pragma solidity ^0.8.0;
import "./TargetContract.sol"; // The target contract containing `_swapUnderlyingToAsset`
import "./FakeRouter.sol"; // A malicious router controlled by the attacker
contract Exploit {
TargetContract public target;
FakeRouter public fakeRouter;
constructor(address _target, address _fakeRouter) {
target = TargetContract(_target);
fakeRouter = FakeRouter(_fakeRouter);
}
function executeExploit() external {
// Set up the malicious path
IRamsesRouter.route;
path[0] = IRamsesRouter.route({from: address(WETH), to: address(fakeRouter), stable: false});
path[1] = IRamsesRouter.route({from: address(fakeRouter), to: address(alETH), stable: false});
// Calculate minOut based on manipulated rates
uint256 amountToSwap = 100 ether;
uint256 manipulatedMinOut = 100.1 ether; // Marginally higher than the input
// Call the vulnerable function
target._swapUnderlyingToAsset(amountToSwap, manipulatedMinOut, path);
}
}

Recommendations

** Price Validation**:

  • Implement a check to validate that the effective swap price is better than or equal to a predefined threshold (e.g., 1:1 or using an on-chain oracle).

  • Example:

    uint256 oraclePrice = getOraclePrice(); // Fetch price from a trusted source
    require((minOut * 1e18) / _amount >= oraclePrice, "Swap price below threshold");
  1. Slippage Control:

    • Ensure that minOut represents a realistic and fair minimum amount for the trade based on the current market conditions.

    • Use a capped percentage difference from the oracle price to set acceptable slippage levels.

  2. Path Validation:

    • Whitelist trusted swap paths and ensure that _path aligns with known safe routes.

  3. Monitoring and Alerts:

    • Implement monitoring to detect and alert for abnormal swap behavior or execution prices.

Updates

Appeal created

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.