15,000 USDC
View results
Submission Details
Severity: medium
Valid

Unsafe Chainlink integration

Summary

Vulnerability Details

Chainlink Oracles store answers with as int256, allowing for negative values. In the DSCEngine, however, answer is explicitly cast to uint256 and is then used to calculate the value of collateral. For example in getUsdValue():

function getUsdValue(address token, uint256 amount) public view returns (uint256) {
AggregatorV3Interface priceFeed = AggregatorV3Interface(s_priceFeeds[token]);
(, int256 price,,,) = priceFeed.staleCheckLatestRoundData();
return ((uint256(price) * ADDITIONAL_FEED_PRECISION) * amount) / PRECISION;
}

Explicit casts in Solidity are unsafe by design and this one in particular will underflow:

  • uint256(int256(-1)) will evaluate to 2^256 - 1

  • uint256(int256(-10e8)) will evaluate to 2^256 - 10e8

Therefore negative prices will be treated as exceedingly large prices (77 OOM), allowing for an essentially unlimited minting power.

Read more: https://degensec.hashnode.dev/everything-you-need-to-know-about-integrating-chainlink#heading-fundamentals-first

Impact

Medium.

Severity is critical, but the likelihood is very low.

Tools Used

Manual Review.

Recommendations

// OracleLib.sol
function staleCheckLatestRoundData(AggregatorV3Interface priceFeed)
public
view
returns (uint80, int256, uint256, uint256, uint80)
{
(uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound) =
priceFeed.latestRoundData();
uint256 secondsSince = block.timestamp - updatedAt;
if (secondsSince > TIMEOUT) revert OracleLib__StalePrice();
if (answer <= 0) revert OracleLib__BadPrice(); // <-- added checks
return (roundId, answer, startedAt, updatedAt, answeredInRound);
}

Support

FAQs

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