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

DOS via Slippage Check Manipulation using the `claimAndSwap()` on Ethereum Mainnet.

Summary

The StrategyMainnet contract is vulnerable to a Denial of Service (DOS) attack through balance manipulation that affects the slippage check mechanism in the claimAndSwap function. The vulnerability arises from using direct token balance checks (asset.balanceOf(address(this))) for slippage protection.

Description

The vulnerability stems from two design decisions:

  1. Using direct token balance checks for slippage protection

  2. Not accounting for potential external balance manipulations

Vulnerable Code

function claimAndSwap(uint256 _amountClaim, uint256 _minOut, uint256 _routeNumber) external onlyKeepers {
transmuter.claim(_amountClaim, address(this));
uint256 balBefore = asset.balanceOf(address(this)); //Vulnerable line
require(_minOut > _amountClaim, "minOut too low");
router.exchange(
routes[_routeNumber],
swapParams[_routeNumber],
_amountClaim,
_minOut,
pools[_routeNumber],
address(this)
);
uint256 balAfter = asset.balanceOf(address(this)); // Vulnerable line
require((balAfter - balBefore) >= _minOut, "Slippage too high"); // Attack point
transmuter.deposit(asset.balanceOf(address(this)), address(this));
}

Attack Scenario

  1. Keeper submits a transaction to execute claimAndSwap

  2. Attacker front-runs the transaction by sending a small amount of ALETH directly to the contract

  3. The balBefore check captures this artificially inflated balance

  4. After the swap, the balAfter - balBefore calculation returns a lower value than expected or it may fail due to underflow as balBefore can be manipulated to higher than balAfter.

  5. The transaction reverts due to the slippage check failing.

Impact

  1. Keeper operations can be consistently blocked

  2. Strategy cannot perform necessary token swaps

Proof of Concept

As the strategy will be deployed on Ethereum Mainnet. Attacker can monitor the mempool and perform the attack.

// Simplified attack flow
function executeAttack(address strategy, IERC20 aleth) external {
// 1. Monitor mempool for claimAndSwap transactions
// 2. Front-run with:
aleth.transfer(strategy, 0.1 ether); // Even small amounts can cause DOS
}

Recommendations

Implement internal balance tracking:

contract StrategyMainnet {
uint256 private strategyBalance;
function deposit(uint256 amount) internal {
strategyBalance += amount;
// ... rest of deposit logic
}
function claimAndSwap(uint256 _amountClaim, uint256 _minOut, uint256 _routeNumber) external onlyKeepers {
uint256 preSwapBal = strategyBalance;
// ... perform swap
uint256 newTokens = calculateActualSwapReturn();
strategyBalance += newTokens;
require((strategyBalance - preSwapBal) >= _minOut, "Slippage too high");
}
}
Updates

Lead Judging Commences

inallhonesty Lead Judge
8 months ago

Appeal created

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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