Skip to main content
Sigvex

Flash Loan Exploit Generator

Sigvex exploit generator that validates flash loan vulnerabilities by comparing contract execution under normal vs. temporarily-inflated balance conditions.

Flash Loan Exploit Generator

Overview

The flash loan exploit generator validates findings from the flash_loan detector by executing the target contract’s bytecode under two world-state configurations: one with a realistic attacker balance and one with an artificially inflated balance (simulating a flash loan). If the contract’s behavior changes between the two scenarios — particularly if a transaction that normally fails suddenly succeeds — the contract is vulnerable to flash loan manipulation.

Flash loan attacks have caused some of the largest DeFi losses on record. Common patterns include single-block price manipulation via DEX swaps, collateral inflation in lending protocols, and governance vote manipulation.

Note: Exploit generation in Sigvex is for vulnerability validation purposes only.

Attack Scenario

  1. Setup: The attacker takes a flash loan of 1,000,000,000 tokens. The simulation sets the attacker’s balance to this large amount, creating a temporary window where the attacker appears to hold enormous liquidity within a single transaction.
  2. Trigger: The attacker calls the vulnerable function (typically a swap, trade, or liquidate entry point). The calldata is prefixed with selector 0x0224_08e8 (swap(uint256,uint256,address,bytes)) if no finding location is available.
  3. Exploitation: The protocol reads balances or reserves to calculate prices, collateral ratios, or swap outputs. With a flash-loan-inflated balance, these calculations return values far outside normal operating ranges, allowing the attacker to extract value (e.g., borrow against inflated collateral, execute arbitrage at artificial prices, or trigger a cascade of liquidations).
  4. Impact: The attacker repays the flash loan within the same transaction and keeps the extracted profit. The victim protocol’s reserves or user balances are permanently damaged.

Exploit Mechanics

The generator executes two scenarios and compares their outcomes:

Scenario 1 — Normal balance (attacker_balance = 100_000):

  • Represents an attacker with ordinary funds
  • Used as a baseline for expected contract behavior

Scenario 2 — Flash loan balance (attacker_balance = 1_000_000_000):

  • Simulates a flash loan of 1 billion tokens/wei
  • Pool reserves are also manipulated in the simulated world state to reflect the reserve imbalance after a large buy using the flash-loaned funds

Verdict logic:

Scenario 1 result Scenario 2 result Finding
Reverted Succeeded Critical (confidence 0.90): flash loan makes otherwise-impossible transaction succeed
Succeeded Succeeded, gas delta > 100k Likely (confidence 0.65): different execution paths indicate flash loan sensitivity
Succeeded Succeeded, gas delta ≤ 100k Not vulnerable
Succeeded Reverted Not vulnerable (protection in place)

The generated PoC uses the major DeFi lending venue V3 flash loan interface:

import "@aave/core-v3/contracts/flashloan/base/FlashLoanSimpleReceiverBase.sol";

contract FlashLoanAttacker is FlashLoanSimpleReceiverBase {
    function executeOperation(
        address asset,
        uint256 amount,
        uint256 premium,
        address initiator,
        bytes calldata params
    ) external override returns (bool) {
        // Exploit vulnerable contract here with inflated balance
        // ...
        uint256 amountOwed = amount + premium;
        IERC20(asset).approve(address(POOL), amountOwed);
        return true;
    }
}

Remediation

Use time-weighted average price (TWAP) oracles instead of spot prices. Aggregated price feeds provide manipulation-resistant off-chain data. For DEX-derived prices, a concentrated-liquidity AMM’s TWAP oracle requires sustained price pressure across multiple blocks to manipulate, making single-block flash loan attacks ineffective:

// VULNERABLE: Reads instantaneous spot price
function getPrice() external view returns (uint256) {
    (uint112 reserve0, uint112 reserve1,) = pair.getReserves();
    return reserve1 * 1e18 / reserve0; // flash-loan manipulable
}

// SECURE: Uses TWAP from a concentrated-liquidity AMM
function getPrice() external view returns (uint256) {
    return oracle.consult(token, twapPeriod); // 30-minute TWAP
}