Skip to content

Latest commit

 

History

History
68 lines (44 loc) · 2.34 KB

004.md

File metadata and controls

68 lines (44 loc) · 2.34 KB

Deep Orange Bison

Medium

Not Checking For Stale Prices

Summary

Most prices are provided by an off-chain oracle archive via signed prices, but a Chainlink oracle is still used for index prices. These prices are insufficiently validated.

Root Cause

function getThePrice(address tokenAddress) public view returns (int) {
        // falta hacer un chequeo para las l2
        address _priceFeed = priceFeeds[tokenAddress];
        require(!isPaused, "Contract is paused");
        require(_priceFeed != address(0), "Price feed not set");
        AggregatorV3Interface priceFeed = AggregatorV3Interface(_priceFeed);

        // if sequencer is set, check if it's up
        // if it's down, revert
        if (address(sequencerUptimeFeed) != address(0)) {
            checkSequencer();
        }
        (, int price, , , ) = priceFeed.latestRoundData(); // <- here

        require(isFeedAvailable[_priceFeed], "Price feed not available");
        require(price > 0, "Invalid price");
        return price;
    }

This function doesn't check for updatedAt with his own heartbeat.

Internal pre-conditions

No response

External pre-conditions

No response

Attack Path

No response

Impact

The current implementation of DebitaChainlink is used by the protocol to showcase how the feed will be retrieved via Chainlink Data Feeds. The feed is used to retrieve the getThePrice, which is also used afterwards by DebitaV3Aggregator.getPriceFrom(), then by many functions on protocol for create and matching borrowings, calculate collateral and other importants actions.

PoC

Many smart contracts use Chainlink to request off-chain pricing data, but a common error occurs when the smart contract doesn’t check whether that data is stale. If the returned pricing data is stale, this code will execute with prices that don’t reflect the current pricing resulting in a potential loss of funds for the user and/or the protocol. Smart contracts should always check the updatedAt parameter returned from latestRoundData() and compare it to a staleness threshold:

(, int256 price, , uint256 updatedAt, ) = priceFeed.latestRoundData();

if (updatedAt + heartbeat < block.timestamp) {
   revert("stale price feed");
}

The staleness threshold should correspond to the heartbeat of the oracle’s price feed.

Mitigation

No response