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
- The attacker borrows a large amount atomically via a flash loan.
- Within the same transaction, they use the capital to move a manipulable target (price, vote weight, reserve ratio).
- They interact with the victim protocol at the forged state to extract value.
- They repay the loan plus fee and keep the profit — all atomic, so no capital risk.
Vulnerable vs. fixed
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 ... */ }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
- Identify the sensitive value or permission the pattern can influence.
- Trace every path that can update or consume that value, including callbacks, routers, and privileged helpers.
- 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'.
Related cases
Related tools
