The mitigation was adding a check if isRepayAllowed:
function liquidate(
uint256 positionId,
address debtToken,
uint256 amountCall
) external override lock poke(debtToken) {
if (!isRepayAllowed()) revert Errors.REPAY_NOT_ALLOWED();
However, this mitigation is not entirely correct. Once unpaused, if the position is in a liquidatable state, it will be a race between the repayer and liquidators who will call the corresponding functions (repay or liquidate) first.
Impact
Repayments and liquidations share the same enable flag. Once repayments are allowed, if the user's loan is liquidatable, then liquidators can front-run repayments and take advantage of the current state.
If repayments were disabled, then after unpausing, I think there should be a gap, a safe period when the borrower first has a choice to repay or abandon the loan.
HonorLt
medium
Repay and liquidate race after unpausing
Summary
The mitigation to prevent liquidations when repayments are disabled is not robust enough.
Vulnerability Detail
In the previous audit, an issue was accepted, that liquidations should not be possible when repayments are disabled: https://github.com/sherlock-audit/2023-02-blueberry-judging/issues/290
The mitigation was adding a check if
isRepayAllowed
:However, this mitigation is not entirely correct. Once unpaused, if the position is in a liquidatable state, it will be a race between the repayer and liquidators who will call the corresponding functions (repay or liquidate) first.
Impact
Repayments and liquidations share the same enable flag. Once repayments are allowed, if the user's loan is liquidatable, then liquidators can front-run repayments and take advantage of the current state.
Code Snippet
https://github.com/sherlock-audit/2023-04-blueberry/blob/main/blueberry-core/contracts/BlueBerryBank.sol#L492
Tool used
Manual Review
Recommendation
If repayments were disabled, then after unpausing, I think there should be a gap, a safe period when the borrower first has a choice to repay or abandon the loan.
Duplicate of #117