You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Assets that has not entered markets can still be seized during a liquidation.
Summary
NumaComptroller.liquidateBorrowAllowed() never checks for accountMembership i.e. whether the market has been entered by the user.
As a result, assets that were only deposited for lending and not collateralized can still be seized during a liquidation.
Root Cause
When a user wants to borrow tokens, they have to deposit assets, and then enter market for that particular asset. The asset for the entered market will then be used for account liquidity calculation.
/** * @notice Add assets to be included in account liquidity calculation * @param cTokens The list of addresses of the cToken markets to be enabled * @return Success indicator for whether each corresponding market was entered */function enterMarkets(
address[] memorycTokens
) publicoverridereturns (uint[] memory) {
When a user becomes unhealthy and is liquidatable, liquidators can call liquidateBorrow() on the collateral CNumaToken to seize the asset in exchange for repaying the debt. The liquidator specifies a collateral token to seize, in exchange for a debt token to repay.
The call flow will lead into NumaComptroller.liquidateBorrowAllowed(), where it will revert if and only if the liquidation is not allowed for the collateral/debt pair, and will otherwise allow the tx to go on
/** * @notice Checks if the liquidation should be allowed to occur * @param cTokenBorrowed Asset which was borrowed by the borrower * @param cTokenCollateral Asset which was used as collateral and will be seized * @param liquidator The address repaying the borrow and seizing the collateral * @param borrower The address of the borrower * @param repayAmount The amount of underlying being repaid */function liquidateBorrowAllowed(
addresscTokenBorrowed,
addresscTokenCollateral,
addressliquidator,
addressborrower,
uintrepayAmount
) externalviewoverridereturns (uint) {
However, liquidateBorrowAllowed() never checks if the cTokenCollateral has actually entered market yet, in fact never touches the accountMembership mapping, updated to True when the user has entered the market.
Thus the user may be wrongfully liquidated for an asset that they never collateralized.
Internal pre-conditions
No response
External pre-conditions
No response
Attack Path
Alice collateralizes 1 ETH to borrow 2000 USDC.
Alice deposits 0.5 WBTC, without entering market for it. This is because Alice specifically wants WBTC to only earn lending interest, but she doesn't want to lose her WBTC exposure.
ETH price drops, dropping Alice's borrow power to less than 2000 USDC. Alice is now liquidatable.
Liquidator chooses to liquidate WBTC. The liquidation still passes and Alice still loses her WBTC, despite it never being collateralized.
Alice has lost her WBTC to liquidation, despite the WBTC not used to collateralize anything, and has not even entered the market.
Impact
Assets that are not used for collateralization can still be seized during a liquidation. Users face a loss of the asset that they never intend to risk.
PoC
No response
Mitigation
liquidateBorrowAllowed() must additionally check if the market for cTokenCollateral is entered or not.
The text was updated successfully, but these errors were encountered:
Muscular Yellow Haddock
High
Assets that has not entered markets can still be seized during a liquidation.
Summary
NumaComptroller.liquidateBorrowAllowed()
never checks foraccountMembership
i.e. whether the market has been entered by the user.As a result, assets that were only deposited for lending and not collateralized can still be seized during a liquidation.
Root Cause
When a user wants to borrow tokens, they have to deposit assets, and then enter market for that particular asset. The asset for the entered market will then be used for account liquidity calculation.
https://github.com/sherlock-audit/2024-12-numa-audit/blob/main/Numa/contracts/lending/NumaComptroller.sol#L150-L157
When a user becomes unhealthy and is liquidatable, liquidators can call
liquidateBorrow()
on the collateral CNumaToken to seize the asset in exchange for repaying the debt. The liquidator specifies a collateral token to seize, in exchange for a debt token to repay.https://github.com/sherlock-audit/2024-12-numa-audit/blob/main/Numa/contracts/lending/CNumaToken.sol#L343-L358
The call flow will lead into
NumaComptroller.liquidateBorrowAllowed()
, where it will revert if and only if the liquidation is not allowed for the collateral/debt pair, and will otherwise allow the tx to go onhttps://github.com/sherlock-audit/2024-12-numa-audit/blob/main/Numa/contracts/lending/NumaComptroller.sol#L557
However,
liquidateBorrowAllowed()
never checks if thecTokenCollateral
has actually entered market yet, in fact never touches theaccountMembership
mapping, updated to True when the user has entered the market.Thus the user may be wrongfully liquidated for an asset that they never collateralized.
Internal pre-conditions
No response
External pre-conditions
No response
Attack Path
Alice has lost her WBTC to liquidation, despite the WBTC not used to collateralize anything, and has not even entered the market.
Impact
Assets that are not used for collateralization can still be seized during a liquidation. Users face a loss of the asset that they never intend to risk.
PoC
No response
Mitigation
liquidateBorrowAllowed()
must additionally check if the market forcTokenCollateral
is entered or not.The text was updated successfully, but these errors were encountered: