Red Team Playbook: Anatomy of a Flash Loan Attack

On October 26, 2020, an attacker drained $34 million from Harvest Finance in under seven minutes. The weapon: a flash loan — an uncollateralized loan that exists for exactly one transaction. No seed capital required. No trace of identity. Just code.

Flash loans are the great equalizer of DeFi exploitation. They give any attacker temporary access to hundreds of millions in capital, enough to bend prices, manipulate oracles, and extract value from protocols that assumed no single actor could move markets that far in a single block.

This playbook walks through the methodology a red team uses to discover and validate flash loan attack vectors against DeFi protocols.

Phase 1: Reconnaissance

The first question is: where does the target get its prices?

Every lending protocol, yield vault, and AMM needs price information. The vulnerability surface depends entirely on which oracle the protocol trusts. There are three tiers of oracle security, from most to least vulnerable:

Tier 1 — Spot price reads. The protocol calls getReserves() on a Uniswap V2 pair or reads balanceOf() to calculate a virtual price. These are trivially manipulable within a single transaction.

Tier 2 — TWAP oracles. Time-Weighted Average Prices smooth out manipulation, but short observation windows (under 30 minutes) or low-liquidity pairs can still be vulnerable.

Tier 3 — Off-chain oracles. Chainlink feeds aggregate from multiple off-chain sources. Manipulation requires compromising the oracle network itself — outside the scope of a flash loan attack.

A red team analyst decompiles the target contract and traces every price-dependent code path backward to its oracle source. The specific things to look for:

  • getReserves() calls on Uniswap/SushiSwap pairs
  • balanceOf() used to calculate share prices or collateral ratios
  • Single-source oracle dependencies with no fallback
  • Missing staleness checks on Chainlink feeds (a different vulnerability, but related)
  • Price deviation bounds set too high or absent entirely

If the protocol reads spot prices from a DEX, it is almost certainly vulnerable.

Phase 2: Attack Design

Once you’ve identified a manipulable price source, the attack follows a consistent pattern. The details vary by protocol, but the skeleton is always the same:

flowchart TD
    classDef attack fill:#331a1a,stroke:#d97777,stroke-width:2px,color:#f0c0c0
    classDef process fill:#1a2233,stroke:#7ea8d4,stroke-width:2px,color:#c0d8f0
    classDef data fill:#332a1a,stroke:#d4b870,stroke-width:2px,color:#f0e0c0

    A["1. Flash borrow capital"]:::process
    B["2. Manipulate price source"]:::attack
    C["3. Interact with target at distorted price"]:::attack
    D["4. Reverse manipulation"]:::process
    E["5. Extract profit"]:::data
    F["6. Repay flash loan + fee"]:::process

    A --> B --> C --> D --> E --> F

The critical insight is that the entire sequence executes atomically. If any step fails — including repayment — the entire transaction reverts. This makes flash loan attacks risk-free for the attacker: either the exploit succeeds completely, or nothing happens.

Here is the general structure in Solidity:

contract FlashLoanProbe {
    IFlashLoanProvider public lender;
    IUniswapV2Router public router;
    IVulnerableVault public vault;

    function probe() external {
        // Step 1: Borrow $50M in stablecoins
        lender.flashLoan(
            address(this),
            address(USDC),
            50_000_000e6,
            ""
        );
    }

    function onFlashLoan(
        address,
        address token,
        uint256 amount,
        uint256 fee,
        bytes calldata
    ) external returns (bytes32) {
        // Step 2: Swap to move the price
        IERC20(token).approve(address(router), amount);
        router.swapExactTokensForTokens(
            amount,
            0,
            path,      // USDC -> target token
            address(this),
            block.timestamp
        );

        // Step 3: Interact with vault at manipulated price
        uint256 targetBalance = targetToken.balanceOf(address(this));
        targetToken.approve(address(vault), targetBalance);
        vault.deposit(targetBalance);   // Deposit at inflated price
        vault.withdraw(targetBalance);  // Withdraw at deflated price

        // Step 4: Reverse the swap
        router.swapExactTokensForTokens(
            targetToken.balanceOf(address(this)),
            0,
            reversePath, // target token -> USDC
            address(this),
            block.timestamp
        );

        // Step 5-6: Repay, keep the difference
        IERC20(token).approve(address(lender), amount + fee);
        return keccak256("ERC3156FlashBorrower.onFlashLoan");
    }
}

Phase 3: Profitability Analysis

Not every manipulable oracle leads to a profitable attack. Before building a full exploit, a red team calculates the economics:

Cost side:

  • Flash loan fee (typically 0.05-0.09% on Aave, zero on dYdX)
  • Swap slippage on the manipulation trade (the larger the swap, the more slippage)
  • Swap slippage on the reversal trade
  • Gas costs (complex flash loan txs can cost 1-5M gas)

Revenue side:

  • Price delta between manipulated and true price, multiplied by the position size
  • Minus any withdrawal fees or deposit caps on the target protocol

The Harvest Finance attacker solved this problem elegantly: instead of one large manipulation, they executed 32 smaller cycles within the same transaction. Each cycle moved the price less (reducing slippage costs) but extracted a consistent profit margin. Total cost was roughly $2M in trading fees. Total extraction: $34M.

The key variables that determine profitability:

  • Pool liquidity: Lower liquidity means cheaper manipulation but smaller extraction
  • Vault TVL: More assets in the vault means more to extract per cycle
  • Fee structure: Deposit/withdrawal fees eat into margins
  • Block gas limit: Limits how many cycles fit in one transaction

Phase 4: Validation

A responsible red team validates the vulnerability without exploiting it in production. The standard approach:

  1. Fork mainnet at a recent block using Foundry or Hardhat
  2. Deploy the exploit contract on the fork
  3. Execute the full attack sequence and verify profitability
  4. Vary parameters (loan size, number of cycles, timing) to find the optimal configuration
  5. Document the exact path from initial state to fund extraction
# Foundry fork testing
forge test --fork-url $RPC_URL --fork-block-number 15000000 -vvvv

The fork test proves exploitability without risking real funds. This is the artifact that goes into a vulnerability disclosure or audit report.

What Defenders Get Wrong

The most common mistake is treating flash loans as the vulnerability. Flash loans are a tool — the vulnerability is the oracle. Banning flash loan interactions (which some protocols tried) does not fix the underlying price manipulation risk. An attacker with enough capital can execute the same manipulation without a flash loan; it just costs more.

Effective defenses address the oracle layer:

  • TWAP oracles with observation windows of 30+ minutes make single-block manipulation impractical
  • Chainlink price feeds aggregate from off-chain sources that cannot be manipulated on-chain
  • Price deviation bounds reject any price update that moves more than a threshold (typically 10%) from the last accepted price
  • Deposit/withdraw delays across separate transactions break the atomic execution that flash loans depend on

The Harvest Finance attack specifically exploited the fact that Curve pool virtual prices could be moved by large swaps and that the vault read those prices synchronously. After the incident, the protocol added TWAP-based price validation — the attacker’s exact technique would no longer work.

The Attacker’s Advantage

Flash loan attacks are asymmetric. The attacker can test unlimited variations on a mainnet fork at zero cost, iterating until they find a profitable configuration. Defenders must protect against all possible manipulation paths simultaneously.

This is why oracle design is the single highest-leverage security decision a DeFi protocol makes. Every other defense — reentrancy guards, access control, formal verification — is irrelevant if the price source can be bent.