Summary
The assetPrice() function in contracts/Auditor.sol:356 uses Chainlink's deprecated latestAnswer() instead of latestRoundData(), with no staleness check on the returned price.
Vulnerability Details
// contracts/Auditor.sol:353-358
function assetPrice(IPriceFeed priceFeed) public view returns (uint256) {
if (address(priceFeed) == BASE_FEED) return basePrice;
int256 price = priceFeed.latestAnswer(); // <-- DEPRECATED, no staleness check
if (price <= 0) revert InvalidPrice();
return uint256(price) * baseFactor;
}
The IPriceFeed interface only exposes latestAnswer():
// contracts/utils/IPriceFeed.sol:7
function latestAnswer() external view returns (int256);
Risk
latestAnswer() is explicitly deprecated by Chainlink
- No check on
updatedAt timestamp — contract will use stale prices indefinitely if oracle stops updating
- Affects ALL liquidation calculations (
liquidate(), accountLiquidity()) through assetPrice()
- During network congestion or oracle downtime, stale prices could lead to unfair liquidations
Recommended Fix
Update IPriceFeed to include latestRoundData() and add staleness validation:
function assetPrice(IPriceFeed priceFeed) public view returns (uint256) {
if (address(priceFeed) == BASE_FEED) return basePrice;
(, int256 price, , uint256 updatedAt, ) = priceFeed.latestRoundData();
require(price > 0, "Invalid price");
require(block.timestamp - updatedAt < STALENESS_THRESHOLD, "Stale price");
return uint256(price) * baseFactor;
}
References
Summary
The
assetPrice()function incontracts/Auditor.sol:356uses Chainlink's deprecatedlatestAnswer()instead oflatestRoundData(), with no staleness check on the returned price.Vulnerability Details
The
IPriceFeedinterface only exposeslatestAnswer():Risk
latestAnswer()is explicitly deprecated by ChainlinkupdatedAttimestamp — contract will use stale prices indefinitely if oracle stops updatingliquidate(),accountLiquidity()) throughassetPrice()Recommended Fix
Update
IPriceFeedto includelatestRoundData()and add staleness validation:References