oracle_lib._stale_check_latest_round_data validates updated_at, answered_in_round, and staleness but never checks that price > 0. A zero or negative price from Chainlink freezes the protocol completely.
The returned price flows into two functions in dsc_engine.vy:
_get_usd_value (line 302-316): convert(price, uint256) * ADDITIONAL_FEED_PRECISION * amount // PRECISION. If price = 0, all collateral is valued at 0. If price < 0, Vyper 0.4.0's convert(price, uint256) reverts on negative int256.
_get_token_amount_from_usd (line 346-364): divides by convert(price, uint256) * ADDITIONAL_FEED_PRECISION. If price = 0, this is a division by zero and reverts.
With price = 0: _get_usd_value returns 0 (all collateral worthless), making every position undercollateralized. But _get_token_amount_from_usd divides by zero and reverts, so liquidation is impossible. Protocol frozen.
With price < 0: convert(price, uint256) reverts for negative int256 in Vyper 0.4.0. Every function touching prices reverts. Complete protocol freeze.
Likelihood:
Chainlink has returned zero/negative prices during edge cases (e.g., Luna crash in May 2022, where LUNA/USD briefly reported 0).
Chainlink's latestRoundData returns int256 precisely because prices can go negative in some feeds.
Impact:
Complete protocol freeze. No deposits, no withdrawals, no liquidations, no minting, no burning.
Users cannot rescue their own collateral until the oracle returns a positive price.
No PoC needed. The division-by-zero path in _get_token_amount_from_usd is self-evident from the source: dividing by convert(0, uint256) * ADDITIONAL_FEED_PRECISION = dividing by 0.
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.