Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Strong Linen Dog - MasterPriceOracle.sol might return stale prices #1050

Open
sherlock-admin4 opened this issue Dec 30, 2024 · 0 comments
Open

Comments

@sherlock-admin4
Copy link

Strong Linen Dog

Medium

MasterPriceOracle.sol might return stale prices

Summary

the masterPriceOracle.sol contains logic that implements the AggregatorV3interface which eventually returns the current price for tokens from the chainlink service provider. The issue lies in the fact that the logic that queries chainlink doesn't return the current timestamp of the price received which might be a stale price. The vulnerability is further exploited because the protocol compares current price and deposit price in the calculation of borrowing health and in cases where the discrepancy is further from the tenable amount, user operations are hindered due to the lapses in prices gotten from the oracles.

Root Cause

root cause is the MasterPriceOracle.sol#_price which fails to check if the prices are stale by returning and handling the timestamp

https://github.com/sherlock-audit/2024-11-autonomint/blob/main/Blockchain/Blockchian/contracts/oracles/MasterPriceOracle.sol#L61-L95

 return (uint128((priceInUsd * 1e18) / priceOfNativeInUsd), uint128(priceOfNativeInUsd / 1e16));
        } else if (block.chainid == 10) {
            AggregatorV3Interface oracle = AggregatorV3Interface(oracles[underlying]);

            // Get the eth price
            (, int256 price_, , , ) = oracle.latestRoundData();// doesn't return timestamp
            // If the token is ETH
            if (underlying == assetAddress[IBorrowing.AssetName.ETH]) {
                // Return Exchange rate as 1 and ETH price with 2 decimals
                return (1 ether, uint128((uint256(price_) / 1e6)));
            } else {
                (, uint128 ethPrice) = _price(assetAddress[IBorrowing.AssetName.ETH]);
                // Return Exchange rate and ETH price with 2 decimals
                return (uint128(uint256(price_)), ethPrice);
            }
        } else {

cds.sol also calls MasterPriceOracle.sol#_price through this function

https://github.com/sherlock-audit/2024-11-autonomint/blob/main/Blockchain/Blockchian/contracts/Core_logic/CDS.sol#L134-L136

function getLatestData() private view returns (uint128 ethPrice) {
        (, ethPrice) = oracle.price(0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE);    no response about the price state
    }

Internal pre-conditions

stale price is returned by the chainlink oracle

External pre-conditions

No response

Attack Path

No response

Impact

The function may return stale token/eth price data, leading to inaccurate calculations and possible Dos for users. During withdraw. the BorrowLib.sol#withdraw function compares the currentETH price and the eth price at the point of deposit through calculateETHPriceRatio below

 function calculateEthPriceRatio(
        uint128 depositEthPrice,
        uint128 currentEthPrice
    ) public pure returns (uint128) {
        return (currentEthPrice * 10000) / depositEthPrice;
    }

In a scenario whereby an incorrect eth price is passed as currentETH price. The ratio needed for for withdraw might fail to meet the expected borrowingHealth needed for withdrawal leading to DOS

PoC

No response

Mitigation

Add logic to return timestamp for prices received from the chain-link oracle and handle the timestamp to revert in scenarios where they are stale.

return (uint128((priceInUsd * 1e18) / priceOfNativeInUsd), uint128(priceOfNativeInUsd / 1e16));
} else if (block.chainid == 10) {
    AggregatorV3Interface oracle = AggregatorV3Interface(oracles[underlying]);

    // Get the eth price
    (, int256 price_, , uint256 timeStamp, ) = oracle.latestRoundData(); // include timestamp and handle properly
    // Check if the price data is fresh
    if (block.timestamp - timeStamp > 1 hours) {
        revert("Stale price data");
    }
    // If the token is ETH
    if (underlying == assetAddress[IBorrowing.AssetName.ETH]) {
        // Return Exchange rate as 1 and ETH price with 2 decimals
        return (1 ether, uint128((uint256(price_) / 1e6)));
    } else {
        (, uint128 ethPrice) = _price(assetAddress[IBorrowing.AssetName.ETH]);
        // Return Exchange rate and ETH price with 2 decimals
        return (uint128(uint256(price_)), ethPrice);
    }
} else {
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant