The MarginCallSecondaryFacet::liquidateSecondary()
is vulnerable to front-running attacks, allowing attackers to liquidate some Short positions with the collateral ratio above the secondaryLiquidationCR
threshold.
The liquidateSecondary()
liquidates the Short positions (batches) using the liquidator's ERC (cUSD) to buy back the liquidated Shorts' debt. The liquidator will receive the collateral (zETH) for exchange. This function can be invoked by anyone without the need to flag any Short positions.
The liquidateSecondary()
executes LibOracle::getSavedOrSpotOraclePrice()
to query for the latest price from Chainlink if the last updated timestamp is more than or equal to 15 minutes. Otherwise, the function will return the cached oracle price. With the 15-minute update window, an attacker has room to front-run the protocol's oracle price update. In other words, soon after Chainlink has updated its price, the getSavedOrSpotOraclePrice()
cannot guarantee that it will immediately fetch the latest price from Chainlink.
Let's say Chainlink has updated the price to be lower than the protocol's oracle price (cached). The attacker can front-run the protocol's oracle price update and execute the liquidateSecondary()
to liquidate the targeted Short positions.
This way, the stale cached price (oraclePrice
) will be passed to the _setMarginCallStruct()
. The _setMarginCallStruct()
will use the oraclePrice
to calculate the target Short's collateral ratio (m.cRatio
). Since the oraclePrice
contains a higher price (stale) than Chainlink, the resulting calculated m.cRatio
will be lower than the actual.
When the liquidateSecondary()
verifies the liquidation eligibility of the target Short position, that Short position could be considered as liquidatable (even if that Short position might have the cRatio
above the secondaryLiquidationCR
threshold in reality).
As a result, the attacker can liquidate some Short positions with the cRatio
above the secondaryLiquidationCR
threshold.
https://github.com/Cyfrin/2023-09-ditto/blob/a93b4276420a092913f43169a353a6198d3c21b9/contracts/facets/MarginCallSecondaryFacet.sol#L47
https://github.com/Cyfrin/2023-09-ditto/blob/a93b4276420a092913f43169a353a6198d3c21b9/contracts/facets/MarginCallSecondaryFacet.sol#L53-L55
https://github.com/Cyfrin/2023-09-ditto/blob/a93b4276420a092913f43169a353a6198d3c21b9/contracts/facets/MarginCallSecondaryFacet.sol#L63
https://github.com/Cyfrin/2023-09-ditto/blob/a93b4276420a092913f43169a353a6198d3c21b9/contracts/facets/MarginCallSecondaryFacet.sol#L144
The attacker can liquidate some Short positions with the cRatio
above the secondaryLiquidationCR
threshold.
This vulnerability will directly affect the liquidated shorters (i.e., victims) as they will lose a lot of collateral from the liquidation (note that their positions should not get liquidated yet in reality).
Manual Review
Since the cached oracle price is prone to front-running attacks, always execute the LibOracle::getOraclePrice()
to get the accurate price from Chainlink.
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.