In the LiquidationPool::distributeAssets() function, the Chainlink's latestRoundData() is used to retrieve price feed data of two different assets. However, there is insufficient protection against price staleness.
Return arguments other than int256 answer are necessary to determine the validity of the returned price, as it is possible for an outdated price to be received. The return value updatedAt contains the timestamp at which the received price was last updated, and can be used to ensure that the price is not outdated. See more information about latestRoundID in the Chainlink docs. Inaccurate price data can lead to functions not working as expected and/or loss of funds.
Instances:
https://github.com/Cyfrin/2023-12-the-standard/blob/91132936cb09ef9bf82f38ab1106346e2ad60f91/contracts/LiquidationPool.sol#L207
https://github.com/Cyfrin/2023-12-the-standard/blob/91132936cb09ef9bf82f38ab1106346e2ad60f91/contracts/LiquidationPool.sol#L218
Observe the code below and notice that the only saved value from the latestRoundData() calls is the price of the asset (int answer of the AggregatorV3Interface interface):
For more information, see similar issues from other audits:
https://github.com/code-423n4/2023-06-stader-findings/issues/15
https://github.com/sherlock-audit/2023-04-hubble-exchange-judging/issues/18
The distributeAssets() function of the LiquidationPool contract would accept the use of stale prices for the assets in use.
Manual analysis.
Consider reading the updatedAt return value from the latestRoundData() function and verify that is not older than a specific time tolerance.
For example:
and
Some other solutions found online also make use of the latest returned argument, answeredInRound. However, it was excluded from this recommendation because the latest Chainlink docs indicate that it is deprecated.
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.