Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: high
Valid

Incorrect Owner Parameter in Curve Vault Withdrawal

Summary

In the LendingPool contract, the _withdrawFromVault function incorrectly passes msg.sender as the owner parameter when calling the Curve vault's withdraw function. This creates a critical mismatch in ownership validation since msg.sender in this context refers to the user who initiated the deposit, not the LendingPool contract that actually owns the vault shares.

Vulnerability Details

The vulnerability stems from the complex call chain that occurs during a deposit operation:

  1. A user calls the deposit() function, where msg.sender is the user's address

  2. This triggers _rebalanceLiquidity(), which may need to withdraw funds from the Curve vault

  3. The withdrawal is executed through _withdrawFromVault(), which uses:

`curveVault.withdraw(amount, address(this), msg.sender, 0, new address[](0));`

The fundamental issue is that the owner parameter (third argument) should be address(this) since the LendingPool contract is the actual owner of the vault shares. Instead, it's passing msg.sender, which refers to the original depositor's address.

This creates a critical ownership mismatch because:

  1. The vault shares were originally deposited by the LendingPool contract

  2. The withdrawal attempt specifies a different owner (the user)

  3. The Curve vault will likely reject the transaction due to this ownership discrepancy

Code

_rebalanceLiquidity in deposit

/**
* @notice Allows a user to deposit reserve assets and receive RTokens
* @param amount The amount of reserve assets to deposit
*/
function deposit(uint256 amount) external nonReentrant whenNotPaused onlyValidAmount(amount) {
......
// Rebalance liquidity after deposit
_rebalanceLiquidity();
......
}

_withdrawFromVault in _rebalanceLiquidity

function _rebalanceLiquidity() internal {
......
} else if (currentBuffer < desiredBuffer) { /
uint256 shortage = desiredBuffer - currentBuffer;
// Withdraw shortage from the Curve vault
_withdrawFromVault(shortage);
}
......
}

_withdrawFromVault

function _withdrawFromVault(uint256 amount) internal {
curveVault.withdraw(amount, address(this), msg.sender, 0, new address[](0));
totalVaultDeposits -= amount;
}

withdraw in ICurveCrvUSDVault

function withdraw(
uint256 assets,
address receiver,
address owner,
uint256 maxLoss,
address[] calldata strategies
) external returns (uint256 shares);

Impact

  • Failed Rebalancing: The liquidity rebalancing mechanism will fail when trying to withdraw from the vault, potentially leaving the protocol with insufficient buffer liquidity

  • Blocked Deposits: Since rebalancing is called after deposits, this could effectively block new deposits from being processed

  • Potential Fund Lock: In severe cases, this could lead to funds being temporarily locked in the Curve vault if the protocol cannot properly execute withdrawals

Tools Used

Manual

Recommendations

Replace msg.sender with address(this).

curveVault.withdraw(amount, address(this), address(this), 0, new address[](0));
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

LendingPool::_withdrawFromVault incorrectly uses msg.sender instead of address(this) as the owner parameter, causing vault withdrawals to fail

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

LendingPool::_withdrawFromVault incorrectly uses msg.sender instead of address(this) as the owner parameter, causing vault withdrawals to fail

Support

FAQs

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

Give us feedback!