sherlock-audit / 2024-06-makerdao-endgame-judging

1 stars 1 forks source link

panprog - There is not enough incentive to call `VoteDelegate.reserveHatch` as it can be abused by attackers to drain gas fees from liquidators #72

Closed sherlock-admin4 closed 1 month ago

sherlock-admin4 commented 1 month ago

panprog

Medium

There is not enough incentive to call VoteDelegate.reserveHatch as it can be abused by attackers to drain gas fees from liquidators

Summary

LockstakeEngine liquidation of unhealthy accounts can be blocked by the attacker if he calls VoteDelegate.lock for the unhealthy vault every block as liquidation in the same block then reverts when trying to VoteDelegate.free (Chief flashloan protection). Liquidator can then call VoteDelegate.reserveHatch, which will disable VoteDelegate.lock function for 5 blocks, allowing liquidator to liquidate the vault.

The issue is that this 2-step liquidation (liquidator has to call VoteDelegate.reserveHatch first, only then he can call Dog.bark within the next 5 blocks) requires 2 transactions in separate blocks and liquidator is only paid for the Dog.bark, but not for the reserveHatch. This means there is lack of incentive for the liquidator to call this function. This can become especially bad if the attacker intentionally forces liquidators to call reserveHatch (by intentionally creating unhealthy vaults with VoteDelegate.lock call every block), and then immediately repaying the debt to make the vault healthy again as soon as reserveHatch is called by anyone. Due to the 2-blocks requirement for the liquidator in such case, attacker can always avoid liquidation and liquidator can never liquidate, but is forced to call reserveHatch all the time, losing gas fees.

Moreover, attacker can use the reserveHatch call as an indication of pending liquidation: so the attacker intentionally keeps unhealthy vault and if liquidators stop calling unprofitable reserveHatch, attacker simply keeps vault unhealthy further until it goes into bad debt to cause loss of funds for the protocol. But if liquidator does try to reserveHatch, attacker immediately repays the debt to make it healthy again and waste liquidator's gas.

Root Cause

VoteDelegate.reserveHatch functionaltiy is cumbersome and creates a 2-steps liquidation process in 2 blocks: https://github.com/sherlock-audit/2024-06-makerdao-endgame/blob/main/vote-delegate/src/VoteDelegate.sol#L104-L109

Internal pre-conditions

None

External pre-conditions

None

Attack Path

  1. Attacker's vault has some VoteDelegate selected
  2. Attacker puts his vault at the edge of being unhealthy (maxes out the debt)
  3. Next block the vault becomes unhealthy
  4. Attacker calls VoteDelegate.lock every block to prevent liquidation in the same block
  5. Liquidator, being unable to liquidate user's vault (due to revert when trying to VoteDelegate.free in the liquidation), calls VoteDelegate.reserveHatch
  6. Attacker immediately repays the tiny debt to make the account healthy again and repeats from 4.
  7. If liquidator doesn't call reserveHatch, attacker simply waits until the vault goes into bad debt to cause funds loss to the protocol

Impact

  1. Liquidators are forced to call VoteDelegate.reserveHatch many times without actual liquidation happening, thus wasting gas fees.
  2. When done frequently, liquidators might be disincentivized from calling reserveHatch at all and liquidating such user, exposing the protocol to uncontained losses from such attacker (easily 5%+ damage with large vault)

PoC

Not needed

Mitigation

Re-design the reserveHatch functionality which is very inconvenient for all parties and creates security issues as well.

telome commented 1 month ago

The competition readme states: "It is also assumed that in case it is needed the Maker community/project would set up a keeper to call reserveHatch periodically (within less than a day)."

If the protocol keeps calling reserveHatch periodically (on its own expense, as stated to be done) then this becomes a non-issue as there is always a liquidation-available window.