Skip to main content
Sigvex

Flash Loan Attack Vector Remediation

How to eliminate flash loan attack surfaces by replacing manipulable spot prices with time-weighted average prices and adding sanity bounds on price inputs.

Flash Loan Attack Vector Remediation

Overview

Flash loan vulnerabilities arise when a protocol relies on on-chain spot prices (DEX reserves, slot0 values) that an attacker can manipulate within a single transaction using a large borrowed balance. The remediation is to replace instantaneous price reads with time-weighted average prices (TWAPs) that cannot be manipulated within a single block, or to add sanity bounds that reject implausible price movements.

Related Detector: Flash Loan Attack Vector

Before (Vulnerable)

interface IConstantProductPair {
    function getReserves() external view returns (uint112 reserve0, uint112 reserve1, uint32 blockTimestampLast);
}

contract VulnerableLending {
    IConstantProductPair public pair;

    function getTokenPrice() public view returns (uint256) {
        (uint112 reserve0, uint112 reserve1, ) = pair.getReserves();
        // VULNERABLE: spot price can be manipulated in the same transaction via flash loan
        return (uint256(reserve1) * 1e18) / uint256(reserve0);
    }

    function borrow(uint256 collateralAmount) external {
        uint256 price = getTokenPrice(); // Attacker inflates this
        uint256 loanAmount = collateralAmount * price / 1e18;
        _issueLoan(msg.sender, loanAmount);
    }
}

After (Fixed)

interface IConcentratedLiquidityPool {
    function observe(uint32[] calldata secondsAgos)
        external view returns (int56[] memory tickCumulatives, uint160[] memory);
}

contract SafeLending {
    IConcentratedLiquidityPool public pool;
    uint32 public constant TWAP_PERIOD = 1800; // 30-minute TWAP

    function getTWAPPrice() public view returns (uint256) {
        uint32[] memory secondsAgos = new uint32[](2);
        secondsAgos[0] = TWAP_PERIOD;
        secondsAgos[1] = 0;

        (int56[] memory tickCumulatives, ) = pool.observe(secondsAgos);

        int56 tickDelta = tickCumulatives[1] - tickCumulatives[0];
        int24 avgTick = int24(tickDelta / int56(uint56(TWAP_PERIOD)));

        // Convert tick to price — cannot be manipulated in a single block
        return _tickToPrice(avgTick);
    }

    function borrow(uint256 collateralAmount) external {
        uint256 price = getTWAPPrice(); // TWAP — flash loan resistant
        uint256 loanAmount = collateralAmount * price / 1e18;
        _issueLoan(msg.sender, loanAmount);
    }
}

Alternative Mitigations

off-chain aggregated price feeds — off-chain aggregated prices that are not manipulable within a single block:

import "./interfaces/AggregatorV3Interface.sol";

contract OffchainFeedPricing {
    AggregatorV3Interface public priceFeed;
    uint256 public constant MAX_STALENESS = 1 hours;

    function getPrice() public view returns (uint256) {
        (, int256 price, , uint256 updatedAt, ) = priceFeed.latestRoundData();
        require(block.timestamp - updatedAt <= MAX_STALENESS, "Stale price");
        require(price > 0, "Invalid price");
        return uint256(price);
    }
}

Price deviation bounds — reject prices that deviate too far from a trusted reference:

uint256 constant MAX_PRICE_DEVIATION_BPS = 500; // 5%

function validatePrice(uint256 spotPrice, uint256 twapPrice) internal pure {
    uint256 deviation = spotPrice > twapPrice
        ? (spotPrice - twapPrice) * 10000 / twapPrice
        : (twapPrice - spotPrice) * 10000 / twapPrice;
    require(deviation <= MAX_PRICE_DEVIATION_BPS, "Price manipulation detected");
}

Common Mistakes

Using a constant-product AMM getReserves() with no manipulation check — always manipulable in the same block.

TWAP period too short — a 1-block TWAP provides almost no protection. Use at least 15 minutes, preferably 30 minutes or more for high-value operations.

Mixing oracle sources — using a TWAP for one asset and a spot price for another in the same calculation reintroduces the vulnerability through the spot-priced asset.

References