Algo Ssstablecoinsss

AI First Flight #2
Beginner FriendlyDeFi
EXP
View results
Submission Details
Impact: high
Likelihood: medium
Invalid

Missing Price Validation Allows Zero or Negative Oracle Prices to Break Protocol

Missing Price Validation Allows Zero or Negative Oracle Prices to Break Protocol

Description

The oracle library fetches price data from Chainlink but does not validate that the returned price is greater than zero.

This allows zero or negative prices to pass through, causing division by zero errors in liquidation calculations or zero-valued collateral in health factor checks.

// oracle_lib.vy:40-42
(
round_id, price, started_at, updated_at, answered_in_round
) = staticcall price_price.latestRoundData()

// @> No validation that price > 0

assert updated_at != 0, "DSCEngine_StalePrice"
assert answered_in_round >= round_id, "DSCEngine_StalePrice"
// @> Missing: assert price > 0

Risk: Medium

Likelihood:

Chainlink oracle malfunctions or returns corrupted data during network issues or feed deprecation.

Oracle aggregator experiences edge case where price rounds to zero.

Impact: High

_get_usd_value returns zero when price is zero, causing all collateral to be valued at $0 and triggering mass unfair liquidations.

_get_token_amount_from_usd divides by zero when price is zero, reverting all liquidation transactions and freezing the protocol.

Negative prices converted to uint256 cause reverts, creating protocol-wide DoS.

Proof of Concept

  1. Chainlink oracle malfunctions and returns price = 0 for ETH/USD feed.

  2. User calls any function that checks health factor.

  3. _get_usd_value calculates: (0 * ADDITIONAL_FEED_PRECISION) * amount = 0.

  4. User's collateral is valued at $0, health factor becomes zero.

  5. Alternatively, liquidator calls liquidate().

  6. _get_token_amount_from_usd calculates: amount / (0 * PRECISION) = division by zero.

  7. Transaction reverts, liquidations become impossible, protocol freezes.

Recommended Mitigation

// oracle_lib.vy

(
round_id, price, started_at, updated_at, answered_in_round
) = staticcall price_price.latestRoundData()

  • assert price > 0, "DSCEngine_InvalidPrice"

assert updated_at != 0, "DSCEngine_StalePrice"
assert answered_in_round >= round_id, "DSCEngine_StalePrice"


Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 14 hours ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!