Part 2

Zaros
PerpetualsDEXFoundrySolidity
70,000 USDC
View results
Submission Details
Severity: medium
Invalid

Price Oracle Round Validation Omission in Liquidation System Enables Stale and Incomplete Data Processing

Summary

The liquidation system's liquidateAccounts() triggers a chain of operations that rely on Chainlink price feed data. The execution flow starts with margin calculations for each account being liquidated, where getAccountMarginRequirementUsdAndUnrealizedPnlUsd() is called to determine the account's current state. This function fetches prices to calculate position values and margin requirements.

The critical vulnerability emerges in ChainlinkUtil.getPrice() where price data is retrieved without proper round validation. When latestRoundData() is called, the returned round metadata is only partially validated:

try params.priceFeed.latestRoundData() returns (uint80, int256 answer, uint256, uint256 updatedAt, uint80) {
if (block.timestamp - updatedAt > params.priceFeedHeartbeatSeconds) {
revert Errors.OraclePriceFeedHeartbeat(address(params.priceFeed));
}

Impact

The vulnerability creates a cascading failure pattern in the oracle price validation system. When latestRoundData() is called, the returned round data flows through the liquidation calculations without proper validation gates. First, the system processes incomplete round data since there's no verification between answeredInRound and roundId, allowing price calculations to proceed with potentially partial oracle updates.

This incomplete data then propagates through the system because the code lacks verification that the returned round represents the latest oracle update, effectively permitting stale price data to influence liquidation decisions. The problem compounds during liquidation execution, where multiple price checks occur across position value calculations, margin requirement assessments, and final liquidation determinations - all potentially operating on different round data since there's no mechanism to enforce round consistency across these sequential price queries. This fragmented price validation creates a systemic vulnerability where liquidation conditions can be manipulated by exploiting the gaps between oracle update rounds.

An attacker could exploit this by targeting the liquidation process when price rounds are in transition. For example, an account's unrealized PnL calculation might use data from round N, while margin balance calculations use round N+1, creating inconsistent liquidation conditions.

Mitigation

The fix requires implementing comprehensive round validation:

function getPrice(GetPriceParams memory params) internal view returns (UD60x18 price) {
(uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) =
params.priceFeed.latestRoundData();
if (answeredInRound != roundId) {
revert Errors.IncompleteRound();
}
if (updatedAt == 0) {
revert Errors.StaleRound();
}
// Existing heartbeat check retained
if (block.timestamp - updatedAt > params.priceFeedHeartbeatSeconds) {
revert Errors.OraclePriceFeedHeartbeat(address(params.priceFeed));
}
}

This vulnerability is particularly severe in the context of liquidations, where price accuracy directly impacts position solvency determinations and liquidation execution timing. The lack of proper round validation could lead to systemic failures in the platform's risk management system.

Updates

Lead Judging Commences

inallhonesty Lead Judge 6 months ago
Submission Judgement Published
Invalidated
Reason: Out of scope

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.