Submitted by nonseodion
When a user deposits in the WiseLending contract he can make a private deposit (pure) which allows his deposits not to be used as collateral or a normal deposit. He can also set his position to be collateralized or uncollateralized. If a position is collateralized, the normal deposit can be used as collateral and vice-versa.
When a user uncollateralizes his position, he can only use his private deposit as collateral. If the position becomes liquidatable, it means the private deposit can no longer cover the amount borrowed. In the call to getFullCollateralETH() below only the private collateral is returned immediately as full collateral if it is uncollateralized.
WiseSecurityHelper.sol#L198-L208
In a liquidation, the amount to be liquidated is expressed as a percentage of the full collateral. In an uncollateralized position, the full collateral is the private collateral. The calculateWishPercentage() call calculates this percentage.
WiseSecurityHelper.sol#L760-L786
The amount to be liquidated, i.e. the amount the liquidator receives, is calculated in _calculateReceiveAmount() using the percentage from calculateWishPercentage() and applied to the positions pure collateral first in line 557 below.
It calculates the percentage of the users normal balance to be reduced in line 569 without checking if it is uncollateralized. If the amount it gets, i.e. potentialPureExtraCashout, is greater than zero and less than the current private balance (pureCollateral) in line 576, it is reduced from the private balance.
WiseCore.sol#L564-L586
The issue is the implementation applies the percentage meant for only the private collateral to both the normal and private collateral. It should reduce only the private collateral, but may also reduce the public collateral and send it to the liquidator.
Heres how a malicious liquidator can profit and steal user funds:
A liquidator can set it up to drain the private collateral balance and only pay for a portion of the liquidation. The user ends up losing funds and the protocols bad debt increases.
This vulnerability allows the liquidator to steal the users balance and pay for only a portion of the shares. It has these effects:
The testStealPureBalance() test below shows a liquidator earning more than the amount he paid for liquidation.
The test can be put in any test file in the contracts directory and ran there.
To ensure the code does not also consider the normal balance at all we can check if the position is uncollateralized early. Currently, this check is done but is done too late in the _calculateReceiveAmount() function. We can fix it by moving the check.
WiseCore.sol#L560-L594
Invalid Validation
vm06007 (Wise Lending) commented:
Trust (judge) commented:
Wise Lending commented:
