skills/vulnerability-patterns/oracle-manipulation/SKILL.md
Oracle manipulation techniques, case studies, and secure pricing integration controls for DeFi.
npx skillsauth add apegurus/solidity-argus oracle-manipulationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Oracle manipulation attacks exploit price feeds to extract value. Attackers manipulate the price source, then use the manipulated price to profit (liquidations, swaps, borrows).
Total Losses: $500M+ across DeFi
Using AMM spot prices directly instead of TWAPs.
// VULNERABLE: Spot price from Uniswap
function getPrice() external view returns (uint256) {
(uint112 reserve0, uint112 reserve1,) = pair.getReserves();
return reserve1 * 1e18 / reserve0; // Manipulatable in same tx!
}
Fix: Use TWAP (Time-Weighted Average Price) or Chainlink.
// VULNERABLE: No freshness check
function getPrice(address token) external view returns (uint256) {
(, int256 price,,,) = priceFeed.latestRoundData();
return uint256(price); // Could be hours old!
}
// SECURE: Freshness validation
function getPrice(address token) external view returns (uint256) {
(
uint80 roundId,
int256 price,
,
uint256 updatedAt,
uint80 answeredInRound
) = priceFeed.latestRoundData();
require(price > 0, "Invalid price");
require(updatedAt > block.timestamp - MAX_DELAY, "Stale price");
require(answeredInRound >= roundId, "Stale round");
return uint256(price);
}
Even TWAPs can be manipulated if:
What happened:
Root cause: Spot price oracle on low-liquidity pool
Lesson: Never use spot prices. Use TWAPs with sufficient window.
What happened:
Root cause: Self-referential oracle (own perp price as collateral value)
Lesson: Don't use your own market prices as oracle for that same market.
What happened:
Root cause: Short TWAP window on low-liquidity pair
Lesson: TWAP window must be long enough to make manipulation unprofitable.
What happened:
Root cause: Spot price oracles vulnerable to flash loan manipulation
answeredInRound >= roundId checked?function getPrice(address token) public view returns (uint256) {
AggregatorV3Interface feed = priceFeeds[token];
require(address(feed) != address(0), "No feed");
(
uint80 roundId,
int256 price,
,
uint256 updatedAt,
uint80 answeredInRound
) = feed.latestRoundData();
// Validation
require(price > 0, "Invalid price");
require(updatedAt > 0, "Round not complete");
require(answeredInRound >= roundId, "Stale round");
require(block.timestamp - updatedAt < HEARTBEAT, "Stale price");
return uint256(price);
}
uint256 public lastPrice;
uint256 public constant MAX_DEVIATION = 10; // 10%
function getPriceWithCircuitBreaker() external returns (uint256) {
uint256 newPrice = oracle.getPrice();
if (lastPrice > 0) {
uint256 deviation = newPrice > lastPrice
? (newPrice - lastPrice) * 100 / lastPrice
: (lastPrice - newPrice) * 100 / lastPrice;
require(deviation <= MAX_DEVIATION, "Price deviation too high");
}
lastPrice = newPrice;
return newPrice;
}
testing
Specialist profile for mechanically applying the attack-vector deck and classifying vectors as skip, drop, or investigate.
tools
Specialist profile for libraries, helpers, base contracts, adapters, encoders, wrappers, and integration glue.
testing
Specialist profile for rounding, scale, decimal, downcast, and arithmetic accounting edge cases.
testing
Specialist profile for extracting conservation laws and state couplings, then searching for violating paths.