The protocol uses a liquidation mechanism that utilizes asset prices that are seconds old. This temporal inconsistency enables liquidators to initiate liquidations based on outdated price information, potentially causing substantial financial losses for users, it enables liquidators to earn profit from arbitrage in addition to reward penalty. The protocol's liquidation process relies on asset prices that are only updated every few seconds or minutes. The liquidation process should use the most recent and accurate asset prices, ensuring fair liquidations.
however yang_prices are being updated using execute_task function at seer module periodically, this period is set as update_frequency which would be between 15 seconds to 30 minutes, since the liquidation function doesn't update the price so the price may be at least 15 seconds old, also there is no guarantee that price is updated at last period so can be even older, this old price leads to unfair liquidations.
https://github.com/code-423n4/2024-01-opus/blob/4720e9481a4fb20f4ab4140f9cc391a23ede3817/src/core/seer.cairo#L181-L184
this would enable the liquidator to arbitrage liquidations and earn profit in addition to their liquidation penalty, despite this fact that price change is limited in short timeframes but it's a considerable loss in volatile market conditions especially for troves with large amounts of collaterals.
Impact
Liquidators can conduct liquidations at prices that do not reflect the current market conditions, leading to financial losses for affected users.
Proof of Concept
Consider Alice has a trove with a deposit of 1 BTC worth of 1000 USD and 800 yin debt.
threshold is 0.7 so this trove is liquidatable
after 20 seconds price of BTC goes to 1050 USD
Bob tries to liquidate the trove without updating the price
if we ignore penalty (to simplify) he would repay 170 yin and get 0.17 BTC worth of 178.5 USD while he repaid 170 USD as debt so he earned an additional 8.5 USD.
Tools Used
Manual Review
Recommended Mitigation Steps
update prices in the liquidate and absorb function of the purger module before liquidations.
Lines of code
https://github.com/code-423n4/2024-01-opus/blob/4720e9481a4fb20f4ab4140f9cc391a23ede3817/src/core/purger.cairo#L227 https://github.com/code-423n4/2024-01-opus/blob/4720e9481a4fb20f4ab4140f9cc391a23ede3817/src/core/shrine.cairo#L509 https://github.com/code-423n4/2024-01-opus/blob/4720e9481a4fb20f4ab4140f9cc391a23ede3817/src/core/shrine.cairo#L1318 https://github.com/code-423n4/2024-01-opus/blob/4720e9481a4fb20f4ab4140f9cc391a23ede3817/src/core/shrine.cairo#L1181 https://github.com/code-423n4/2024-01-opus/blob/4720e9481a4fb20f4ab4140f9cc391a23ede3817/src/core/seer.cairo#L181-L184
Vulnerability details
Summary
The protocol uses a liquidation mechanism that utilizes asset prices that are seconds old. This temporal inconsistency enables liquidators to initiate liquidations based on outdated price information, potentially causing substantial financial losses for users, it enables liquidators to earn profit from arbitrage in addition to reward penalty. The protocol's liquidation process relies on asset prices that are only updated every few seconds or minutes. The liquidation process should use the most recent and accurate asset prices, ensuring fair liquidations.
Vulnerability Details
liquidate function at purger module gets trove information(value,debt,ltv) from get_trove_helth https://github.com/code-423n4/2024-01-opus/blob/4720e9481a4fb20f4ab4140f9cc391a23ede3817/src/core/purger.cairo#L227
In the following line of code, get_trove_health retrieves trove value using get_thrshold_value function which calculates trove value based on yang_prices mapping which stores the price of each yang. https://github.com/code-423n4/2024-01-opus/blob/4720e9481a4fb20f4ab4140f9cc391a23ede3817/src/core/shrine.cairo#L509 https://github.com/code-423n4/2024-01-opus/blob/4720e9481a4fb20f4ab4140f9cc391a23ede3817/src/core/shrine.cairo#L1318 https://github.com/code-423n4/2024-01-opus/blob/4720e9481a4fb20f4ab4140f9cc391a23ede3817/src/core/shrine.cairo#L1181
however yang_prices are being updated using execute_task function at seer module periodically, this period is set as update_frequency which would be between 15 seconds to 30 minutes, since the liquidation function doesn't update the price so the price may be at least 15 seconds old, also there is no guarantee that price is updated at last period so can be even older, this old price leads to unfair liquidations. https://github.com/code-423n4/2024-01-opus/blob/4720e9481a4fb20f4ab4140f9cc391a23ede3817/src/core/seer.cairo#L181-L184
since value of yang is not updated it's possible that a wrong percentage of collaterals is freed and transferred to the liquidator, https://github.com/code-423n4/2024-01-opus/blob/4720e9481a4fb20f4ab4140f9cc391a23ede3817/src/core/purger.cairo#L235-L237 https://github.com/code-423n4/2024-01-opus/blob/4720e9481a4fb20f4ab4140f9cc391a23ede3817/src/core/purger.cairo#L598-L608
this would enable the liquidator to arbitrage liquidations and earn profit in addition to their liquidation penalty, despite this fact that price change is limited in short timeframes but it's a considerable loss in volatile market conditions especially for troves with large amounts of collaterals.
Impact
Liquidators can conduct liquidations at prices that do not reflect the current market conditions, leading to financial losses for affected users.
Proof of Concept
Consider Alice has a trove with a deposit of 1 BTC worth of 1000 USD and 800 yin debt. threshold is 0.7 so this trove is liquidatable after 20 seconds price of BTC goes to 1050 USD Bob tries to liquidate the trove without updating the price if we ignore penalty (to simplify) he would repay 170 yin and get 0.17 BTC worth of 178.5 USD while he repaid 170 USD as debt so he earned an additional 8.5 USD.
Tools Used
Manual Review
Recommended Mitigation Steps
update prices in the liquidate and absorb function of the purger module before liquidations.
Assessed type
Oracle