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
The lack of post-liquidation collateral checks in liquidateBadDebt will cause protocol insolvency for the vault as an attacker will exploit collateral valuation changes to leave the vault undercollateralized and retain bad debt.
No check ensures the received collateral is sufficient to cover the liquidated debt.
Internal pre-conditions
1-The borrower must have an outstanding debt (borrowAmountFull > 0).
2-The _percentagePosition1000 parameter must allow partial liquidation.
3-The attacker must have sufficient underlyingBorrow tokens to repay the debt.
External pre-conditions
1-The price of the collateral token must drop significantly (e.g., due to market volatility or oracle manipulation).
2-The collateral token must be redeemable for less than the repaid debt value during liquidation.
Attack Path
1-Create a Vulnerable Borrower Position:
The attacker or a third party opens a position with just enough collateral to meet the liquidation threshold.
2-Trigger a Collateral Value Drop:
The attacker manipulates the oracle price to deflate the collateral’s value or waits for natural market volatility to achieve the same effect.
3-Execute a Partial Liquidation:
The attacker calls liquidateBadDebt with _percentagePosition1000 set to a high value (e.g., 900/1000), ensuring significant collateral is redeemed.
The collateral redeemed (received) is insufficient to cover the debt repaid (repayAmount), leaving the vault with bad debt.
4-Retain Bad Debt:
Post-liquidation, the vault retains undercollateralized debt, effectively leading to protocol insolvency.
Impact
Affected Party: The vault and its users.
Loss: Protocol insolvency due to retained bad debt, making it impossible for the vault to meet future obligations.
PoC
// SPDX-License-Identifier: MITpragma solidity0.8.20;
import"forge-std/Test.sol";
import"../contracts/NumaVault.sol";
import"../contracts/mocks/MockOracle.sol";
import"../contracts/mocks/MockToken.sol";
import"../contracts/mocks/MockLendingProtocol.sol";
contractNumaVaultLiquidationTestisTest {
NumaVault vault;
MockOracle oracle;
MockToken lstToken;
MockToken numaToken;
MockLendingProtocol lendingProtocol;
address borrower =address(0x123);
address liquidator =address(this);
function setUp() public {
// Deploy mock dependencies
lstToken =newMockToken("LST Token", "LST", 18);
numaToken =newMockToken("NUMA Token", "NUMA", 18);
oracle =newMockOracle(1e18); // Initial price of 1
lendingProtocol =newMockLendingProtocol(address(lstToken), address(numaToken));
vault =newNumaVault(
address(numaToken),
address(lstToken),
18,
address(oracle),
liquidator,
0,
0
);
// Fund vault and borrower
lstToken.mint(address(vault), 1_000e18);
lstToken.mint(borrower, 500e18);
// Borrower opens a position
lendingProtocol.borrow(borrower, 300e18, address(lstToken));
}
function testUncheckedLiquidation() public {
// Manipulate oracle price to deflate collateral value
oracle.setPrice(0.1e18); // Set price to 0.1 (90% drop)// Liquidator executes partial liquidation
vault.liquidateBadDebt(borrower, 900, lendingProtocol.getCollateralToken());
// Verify bad debt retaineduint256 vaultDebt = vault.getDebt();
console.log("Vault Debt Post-Liquidation:", vaultDebt);
assertGt(vaultDebt, 0, "Vault should retain bad debt");
}
}
Results
Borrower debt is 300 LST; vault collateral covers this amount.
After Exploit: Oracle price drops by 90%, and partial liquidation redeems insufficient collateral. Vault retains 200 LST of bad debt.
Mitigation
1- Enforce Collateral Sufficiency Checks:
After liquidation, validate that the collateral recovered (received) is sufficient to cover the repaid debt (repayAmount): require(received >= repayAmount, "Insufficient collateral recovered");
2- Cap Liquidation Size:
Limit _percentagePosition1000 to prevent excessive liquidations that could destabilize the vault.
The text was updated successfully, but these errors were encountered:
Refined Bone Bat
High
Unchecked Liquidation Outputs in liquidateBadDebt
Summary
The lack of post-liquidation collateral checks in
liquidateBadDebt
will cause protocol insolvency for the vault as an attacker will exploit collateral valuation changes to leave the vault undercollateralized and retain bad debt.Root Cause
In NumaVault.sol:920, the
liquidateBadDebt
function assumes that the collateral recovered during liquidation is sufficient to cover the repaid debt. However, there is no explicit check to verify this assumption, leaving the vault exposed to bad debt if the collateral value drops significantly.NumaVault.sol:920:
https://github.com/sherlock-audit/2024-12-numa-audit/blob/main/Numa/contracts/NumaProtocol/NumaVault.sol#L920
NumaVault.sol:947-948:
https://github.com/sherlock-audit/2024-12-numa-audit/blob/main/Numa/contracts/NumaProtocol/NumaVault.sol#L947-L948
NumaVault.sol:950-954:
https://github.com/sherlock-audit/2024-12-numa-audit/blob/main/Numa/contracts/NumaProtocol/NumaVault.sol#L950-L954
Internal pre-conditions
1-The borrower must have an outstanding debt (borrowAmountFull > 0).
2-The _percentagePosition1000 parameter must allow partial liquidation.
3-The attacker must have sufficient underlyingBorrow tokens to repay the debt.
External pre-conditions
1-The price of the collateral token must drop significantly (e.g., due to market volatility or oracle manipulation).
2-The collateral token must be redeemable for less than the repaid debt value during liquidation.
Attack Path
1-Create a Vulnerable Borrower Position:
2-Trigger a Collateral Value Drop:
3-Execute a Partial Liquidation:
liquidateBadDebt
with _percentagePosition1000 set to a high value (e.g., 900/1000), ensuring significant collateral is redeemed.4-Retain Bad Debt:
Impact
Affected Party: The vault and its users.
Loss: Protocol insolvency due to retained bad debt, making it impossible for the vault to meet future obligations.
PoC
Results
Mitigation
1- Enforce Collateral Sufficiency Checks:
require(received >= repayAmount, "Insufficient collateral recovered");
2- Cap Liquidation Size:
The text was updated successfully, but these errors were encountered: