Web3Exploit logoWeb3Exploit
← Back to Attack Patterns
Attack pattern

Flash Loan Attack

Uncollateralized, single-transaction capital amplifies another bug — usually oracle manipulation or governance — to profitable scale.

Definition

A flash loan is not itself a vulnerability: it is uncollateralized capital borrowed and repaid within one transaction. It becomes an attack when it supplies the scale needed to exploit a second weakness, such as manipulating a spot-price oracle or passing a token-weighted governance vote.

How it works

  1. The attacker borrows a large amount atomically via a flash loan.
  2. Within the same transaction, they use the capital to move a manipulable target (price, vote weight, reserve ratio).
  3. They interact with the victim protocol at the forged state to extract value.
  4. They repay the loan plus fee and keep the profit — all atomic, so no capital risk.

Vulnerable vs. fixed

Vulnerable: 'EOA-only' guard used as flash-loan protectionsolidity
modifier onlyEOA() {
    // Classic guard: assumes a contract cannot be tx.origin.
    require(tx.origin == msg.sender, "no contracts");
    _;
}
function stake() external onlyEOA { /* ... reads a spot price ... */ }
Fixed: remove the assumption, protect the invariantsolidity
function stake() external {
    // Do not rely on tx.origin == msg.sender (broken by EIP-7702).
    // Protect the actual invariant: use a manipulation-resistant price and
    // bound single-block state changes.
    uint256 price = manipulationResistantPrice();
    require(price >= minPrice && price <= maxPrice, "price out of band");
    // ...
}

Detection steps

  1. Identify the sensitive value or permission the pattern can influence.
  2. Trace every path that can update or consume that value, including callbacks, routers, and privileged helpers.
  3. Reproduce the worst-case attacker flow with adversarial ordering, manipulated inputs, and maximum feasible capital.

Common signals

  • Security depends on an assumption that is not enforced by code.
  • A critical value is consumed immediately after an attacker-controlled interaction.
  • A privileged call path crosses multiple contracts without one clear authorization boundary.

False positives

  • The risky-looking operation is read-only and cannot affect settlement or authorization.
  • The value is bounded by independent checks before it moves assets.
  • All privileged entry points share the same tested guard and monitoring path.

Review questions

  • Which invariant would fail if this input or caller were attacker-controlled?
  • Can the attacker compose setup, trigger, settlement, and cleanup atomically?
  • What independent check stops the exploit if the first guard is wrong?

Defensive checklist

  • Assume any caller can command flash-loan-scale capital in one transaction.
  • Do not depend on `tx.origin == msg.sender` as an 'EOA-only' guard (EIP-7702 breaks it).
  • Harden the underlying target: manipulation-resistant oracles, per-block change limits.
  • Model attacker profitability, not just 'can a contract call this'.