In ChainlinkUtil::getPrice
function, the roundId
is not checked or validated at all. Stale prices could result in mass liquidations and huge bad debts that could even challenge the going concern of the protocol.
Zaros protocol is solely relying on Chainlink for most of the critical functionalities of the protocol. This actually introduces the chances of single point of failure. For off-chain price feeds, Zaros is using Chainlink's aggregator only.
While getting the off-chain price of an asset using ChainlinkUtil::getPrice
function, the roundId
is not checked or validated at all. However, updatedAt
is compared with the priceFeedHeartbeatSeconds
, but this sole check is not enough. As we can see in this report how important the validation of roundId
is.
This another report is also suitable for our case because the protocol has used the updatedAt
and some sort of stalePriceDelay
in order to accept only the fresh prices and avoid any stale prices. The reason that this report is valid because roundId
is not validated at all, that makes this logic vulnerable to disastrous exploits.
The Chainlink docs also emphasize the validation of roundId
. Using the roundId
we can ensure the data freshness, sequential data integrity, stale data detection and round completion.
Among others, a devastating example and lesson as a result of Chainlink price oracle malfunction we have TERRA LUNA. We have to implement as many controls as we can to avoid such mishaps.
Source: ChainlinkUtil.sol#L59C1-L76C6
As an impact of wrong price feeds, positions may be liquidated prematurely or fail to liquidate when they should and eventually resulting bad debts. Positions open on wrong collateral prices which may cost major financial losses to the protocol. Incorrect collateral valuation can cause under-collateralization.
Manual review
To mitigate the risk, latestRoundData
function returns the answeredInRound
value among other returned values. Although this value is depreacated as mentioned in the docs but still this can be used to validate the roundId
. If Zaros don't want to validate the roundId
using answeredInRound
(deprecated) then atleast it must check the startedAt
timestamp because each roundData has this prop. The implication should be like, startedAt
should be greater than last startedAt
this will ensure that price does not pertain to previous round and the price is fresh and udpated.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.