HardhatDeFi
15,000 USDC
View results
Submission Details
Severity: high
Invalid

Stuck Funds

Summary

The _createContingentPool function does not validate whether the collateral token matches the expected wToken decimals or Aave’s aToken. This oversight introduces the risk of mismatched token interactions, which could cause redemption failures, incorrect calculations, or liquidity issues.

By exploiting this gap, a user could create a pool using an unintended collateral token (e.g., USDT instead of USDC), leading to serious inconsistencies in redemption and yield claims.


Technical Analysis

Vulnerable Code

function _createContingentPool(...) internal {
address _wToken = _collateralTokenToWToken[_poolParams.collateralToken];
if (_wToken == address(0)) revert CollateralTokenNotRegistered();
}

Root Cause

The function only checks if the collateral token is registered but does not validate:
Whether the token decimals match the expected standard.
Whether the collateral is correctly mapped to its aToken in Aave.
Whether the wToken is compatible with the collateral’s supply and withdrawal mechanics.

This creates a mismatch risk where:
A user selects a token with different decimals, breaking calculations.
A wToken does not correspond to the expected aToken, leading to liquidity failures.


Attack Scenario: Mismatched Collateral Tokens Breaking Redemptions

Step 1: Malicious or Misconfigured Pool Creation

  1. A user creates a contingent pool with USDT as the collateral token.

  2. USDT has 6 decimals, but the wToken expected USDC with 6 decimals.

  3. The function does not check for decimals or aToken mismatches, so the pool is created successfully.

Step 2: Liquidity and Redemption Failure

  1. Users supply liquidity to the pool with USDT, expecting normal operations.

  2. Yield accumulates, but the protocol tracks wTokens incorrectly due to decimal mismatches.

  3. When users try to redeem wTokens, the withdrawal function fails because:

    • The USDT aToken balance does not match the expected wToken supply.

    • Aave may reject the withdrawal due to liquidity issues.

Step 3: Funds Get Stuck

  1. Users cannot withdraw their collateral, as Aave rejects the mismatched token redemption.

  2. Funds remain trapped in the protocol, causing financial losses for users.

  3. Protocol trust erodes, as users experience failed withdrawals and incorrect balances.


**Impact **

🔴 Severity: Medium-High

Likelihood: High – Any user can create misconfigured pools.
Impact: High – Funds may become stuck or misallocated, leading to liquidity failures.

Financial Consequences

Liquidity gets stuck in pools due to redemption failures.
Users cannot withdraw their collateral, leading to direct financial losses.
Incorrect calculations affect yield distribution and protocol stability.


Proof of Concept (PoC): Exploiting Mismatched Collateral Tokens

Step 1: Create a Pool With a Mismatched Token

function testMismatchedCollateralPool() public {
// Assume the protocol expects USDC (6 decimals)
address expectedCollateral = USDC;
address wrongCollateral = USDT;
// Attacker creates a pool with USDT instead of USDC
protocol.createContingentPool(wrongCollateral, ...);
// The pool gets created, but USDT has different handling rules than USDC
}

Step 2: Users Deposit Liquidity Into the Pool

function testLiquidityDeposit() public {
uint256 depositAmount = 1000000 * 10**6; // USDT amount
IERC20(USDT).approve(address(protocol), depositAmount);
protocol.addLiquidity(poolId, depositAmount, msg.sender, msg.sender);
// Liquidity is added, but tracking uses the wrong decimals
}

Step 3: Attempt to Redeem Collateral

function testRedemptionFailure() public {
// User tries to withdraw
protocol.redeemWToken(wToken, wTokenBalance, msg.sender);
// Expected: Reverts due to incorrect collateral balance
vm.expectRevert("Aave: insufficient liquidity");
}

This PoC shows that a mismatched token causes redemption failures, leaving funds trapped.


Mitigation Strategies

Fix 1: Validate Collateral Token Decimals

Ensure the selected collateral token has the expected number of decimals to prevent calculation errors.

Updated Code

function _createContingentPool(...) internal {
address _wToken = _collateralTokenToWToken[_poolParams.collateralToken];
if (_wToken == address(0)) revert CollateralTokenNotRegistered();
// Ensure collateral token has expected decimals
uint8 expectedDecimals = IERC20Metadata(_wToken).decimals();
uint8 actualDecimals = IERC20Metadata(_poolParams.collateralToken).decimals();
require(expectedDecimals == actualDecimals, "Collateral decimals mismatch");
}

Prevents token mismatches from breaking calculations.
Ensures wTokens and collateral are correctly mapped.


Fix 2: Enforce Aave Compatibility Checks

Verify that the collateral token matches the correct aToken in Aave before creating a pool.

Updated Code

function _createContingentPool(...) internal {
address _wToken = _collateralTokenToWToken[_poolParams.collateralToken];
if (_wToken == address(0)) revert CollateralTokenNotRegistered();
// Ensure collateral matches Aave’s aToken
address expectedAToken = IAave(_aaveV3Pool).getReserveData(_poolParams.collateralToken).aTokenAddress;
require(expectedAToken != address(0), "Invalid collateral for Aave");
}

Ensures only supported tokens are used.
Prevents liquidity failures due to unsupported aTokens.

Updates

Lead Judging Commences

bube Lead Judge 9 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.