Open sherlock-admin opened 1 year ago
1 comment(s) were left on this issue during the judging contest.
141345 commented:
m
The self liquidations do seem possible here, we'll look further into the downstream impacts to figure out any fixes we want to implement.
panprog
medium
It is possible to open and liquidate your own position in 1 transaction to overcome efficiency and liquidity removal limits at almost no cost
Summary
The way the protocol is setup, it is possible to open positions or withdraw collateral up to exactly maintenance limit (some percentage of notional). However, this means that it's possible to be at almost liquidation level intentionally and moreover, the current oracle setup allows to open and immediately liquidate your own position in 1 transaction, effectively bypassing efficiency and liquidity removal limits, paying only the keeper (and possible position open/close) fees, causing all kinds of malicious activity which can harm the protocol.
Vulnerability Detail
The user can liquidate his own position with 100% guarantee in 1 transaction by following these steps:
Since all liquidation fee is given to user himself, liquidation of own position is almost free for the user (only the keeper and position open/close fee is paid if any).
Impact
There are different malicious actions scenarios possible which can abuse this issue and overcome efficiency and liquidity removal limitations (as they're ignored when liquidating positions), such as:
The same core reason can also cause unsuspecting user to be unexpectedly liquidated in the following scenario:
The user is unsuspectedly liquidated even though he thought that he was at leverage = 1. But since collateral is withdrawn immediately, but position changes only later, user actually brought his position to max leverage and got liquidated. While this might be argued to be the expected behavior, it might still be hard to understand and unintuitive for many users, so it's better to prevent such situation from happening and the fix is the same as the one to fix self-liquidations.
Proof of concept
The scenario of liquidating unsuspecting user is demonstrated in the test, add this to test/unit/market/Market.test.ts:
Console output for the code:
Self liquidation is the same, just the liquidator does this in 1 transaction and is owned by userB.
Code Snippet
Account solvency is calculated as meeting the minimum collateral of maintenance (percentage of notional): https://github.com/sherlock-audit/2023-07-perennial/blob/main/perennial-v2/packages/perennial/contracts/types/Position.sol#L305
It is possible to bring user to exactly the edge of liquidation, when minimum loss makes him liquidatable.
Tool used
Manual Review
Recommendation
Industry standard is to have initial margin (margin required to open position or withdraw collateral) and maintenance margin (margin required to keep the position solvent). Initial margin > maintenance margin and serves exactly for the reason to prevent users from being close to liquidation, intentional or not. I suggest to implement initial margin as a measure to prevent such self liquidation or unsuspected user liquidations. This will improve user experience (remove a lot of surprise liquidations) and will also improve security by disallowing intentional liquidations and cheaply overcoming the protocol limits such as efficiency limit: intentional liquidations are never good for the protocol as they're most often malicious, so having the ability to liquidate yourself in 1 transaction should definetely be prohibited.