Price Deviation Exploit Generator
Sigvex exploit generator that validates price deviation vulnerabilities by submitting extreme price updates (10x increase, 90% crash) and confirming whether the contract accepts them without bounds checking.
Price Deviation Exploit Generator
Overview
The price deviation exploit generator validates findings from the price_deviation, oracle_price_bounds, and related detectors by submitting four price updates — normal ($2000), a 10x increase ($20,000), a 90% crash ($200), and a reasonable 5% increase ($2100) — and confirming whether the contract accepts extreme changes without bounds checking. Contracts that process a 900% single-block price increase are confirmed vulnerable.
Unbounded price acceptance enables flash-loan price manipulation attacks. An attacker uses a flash loan to move an on-chain spot price by an extreme amount within a single transaction, exploits the contract at the manipulated price, and repays the loan — all atomically. Mango Markets lost $116M (October 2022) when an attacker manipulated the MNGO token price from $0.038 to $0.91 (2,300% increase) using a self-funding scheme, then borrowed against the inflated collateral. Venus Protocol lost $100M+ from a similar BNB price manipulation. Both protocols lacked deviation checks that would have rejected the extreme price as implausible.
Note: Exploit generation in Sigvex is for vulnerability validation purposes only.
Attack Scenario
Flash loan price manipulation:
- Attacker takes a large flash loan of ETH.
- Attacker buys a large amount of the target token on a DEX, moving the spot price from $2000 to $20,000 (10x).
- If the protocol uses spot price directly, the attacker’s collateral is now worth 10x.
- Attacker borrows the maximum amount against the inflated collateral.
- Attacker sells the token, restoring the price to $2000.
- Attacker repays the flash loan; the borrowed funds are profit.
Crash exploitation:
- An attacker or market event drops the price from $2000 to $200 (90% crash).
- Contracts that accept this without circuit breakers trigger mass liquidations.
- Liquidators receive bonus collateral at the artifically depressed price.
- If the crash is manipulation, the attacker profits from liquidation bonuses.
Exploit Mechanics
The generator executes four scenarios using a simulated oracle with price stored in slot 0. The fallback selector 0x8d6cc56d (updatePrice) is used when no specific selector is available from the finding location.
| Scenario | Price value | Change | Expected behavior | Confirmed if |
|---|---|---|---|---|
| 1 — Normal | 200000000000 ($2000) | Baseline | Executes successfully | Baseline |
| 2 — 10x increase | 2000000000000 ($20,000) | +900% | Should revert | Succeeds (0.85 confidence) |
| 3 — 90% crash | 20000000000 ($200) | -90% | Should revert | Succeeds (0.85 confidence) |
| 4 — Reasonable 5% | 210000000000 ($2100) | +5% | Should execute | Baseline validation |
Verdict:
- Normal succeeds and 10x increase succeeds → extreme price increase accepted (confidence 0.85): no upper deviation bound.
- Normal succeeds and 90% crash succeeds → extreme price crash accepted (confidence 0.85): no lower deviation bound.
- Reasonable 5% succeeds but extremes revert → protected: deviation check in place.
// VULNERABLE: No bounds on accepted price
contract VulnerableAmm {
uint256 public lastPrice;
function updatePrice(uint256 newPrice) external onlyOracle {
lastPrice = newPrice; // Accepts 10x or 0.1x price with no validation
emit PriceUpdated(newPrice);
}
function getCollateralValue(uint256 amount) external view returns (uint256) {
return amount * lastPrice / 1e8;
}
}
// SECURE: Deviation check prevents manipulation
contract SafeAmm {
uint256 public lastPrice;
uint256 constant MAX_DEVIATION_BPS = 1000; // 10% max per update
function updatePrice(uint256 newPrice) external onlyOracle {
if (lastPrice != 0) {
uint256 deviation = newPrice > lastPrice
? (newPrice - lastPrice) * 10000 / lastPrice
: (lastPrice - newPrice) * 10000 / lastPrice;
require(deviation <= MAX_DEVIATION_BPS, "Price deviation too large");
}
lastPrice = newPrice;
emit PriceUpdated(newPrice);
}
}
Remediation
- Detector: Price Deviation Detector
- Remediation Guide: Price Deviation Remediation
Implement circuit breakers and deviation bounds at multiple levels:
// 1. Per-update deviation check
uint256 constant MAX_SINGLE_UPDATE_BPS = 500; // 5% per update
// 2. Time-weighted average prevents single-block manipulation
// Use a Uniswap V3 TWAP with a minimum observation window
uint256 constant MIN_TWAP_PERIOD = 1800; // 30 minutes
uint256 twapPrice = uniswapPool.observe(MIN_TWAP_PERIOD);
// 3. Absolute bounds for the asset class
uint256 constant ETH_MIN_PRICE = 100e8; // $100 minimum
uint256 constant ETH_MAX_PRICE = 100_000e8; // $100,000 maximum
// 4. Circuit breaker: pause on extreme deviation from TWAP
function validatePrice(uint256 spotPrice) internal view {
uint256 twap = getTwapPrice();
uint256 deviation = abs(spotPrice - twap) * 10000 / twap;
if (deviation > CIRCUIT_BREAKER_BPS) {
_pauseProtocol();
revert("Price deviation triggered circuit breaker");
}
}
// 5. Use TWAP instead of spot price for all lending decisions
// Spot price for display; TWAP for collateral calculations
For protocols that cannot avoid spot price use (e.g., AMMs), enforce minimum liquidity requirements: manipulating a deep pool requires far more capital, making attacks uneconomical.