Core Contracts

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

Incorrect msg.sender in Vault Withdrawal Leads to DOS

Summary

An issue was identified in the LendingPool.sol contract where the _withdrawFromVault() function always reverts when called due to an incorrect msg.sender. This occurs when the borrower attempts to borrow funds, and there is insufficient liquidity in the reserves, triggering a withdrawal from the CurveVault. However, since the borrower lacks the required shares to withdraw from the vault, the transaction fails.

Vulnerability Details

_withdrawFromVault(uint256 amount) in LendingPool.sol

https://github.com/Cyfrin/2025-02-raac/blob/89ccb062e2b175374d40d824263a4c0b601bcb7f/contracts/core/pools/LendingPool/LendingPool.sol#L809-L812

The borrow() function allows an RAAC NFT owner to borrow funds based on the NFT’s value. If sufficient liquidity is available in the RToken, the borrow proceeds without issues. However, if there is insufficient liquidity, the internal function _ensureLiquidity() is triggered, which calls _withdrawFromVault(amount). This function attempts to withdraw funds from the CurveVault but incorrectly uses msg.sender, leading to a transaction failure.

Root Cause:

  • The CurveVault.withdraw() function requires the msg.sender to be the owner of the shares being withdrawn.

  • In _depositIntoVault(), the LendingPool contract receives the shares when funds are deposited.

  • However, in _withdrawFromVault(), msg.sender is the borrower, who does not own the required shares, causing the transaction to revert.

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

POC

Preconditions:

  • The borrower owns an RAAC NFT.

  • The borrower deposits the NFT via depositNFT().

  • The protocol lacks sufficient liquidity in RToken.

Steps to Trigger:

  1. The borrower calls borrow().

  2. _ensureLiquidity() is triggered, detecting low liquidity.

  3. _withdrawFromVault(amount) is called.

  4. The function fails because msg.sender (borrower) does not have any vault shares.

  5. Transaction reverts, preventing borrowing.

Impact

This issue effectively locks borrowing functionality whenever liquidity is insufficient in the reserves. Since withdrawals from the CurveVault always revert due to an incorrect msg.sender, the protocol will be unable to provide additional liquidity when needed, leading to borrowing failures.

Tools Used

Manual

Recommendations

The msg.sender in _withdrawFromVault() should be corrected to the entity that actually holds the shares—LendingPool.sol. This can be fixed by modifying the withdrawal call as follows:

function _withdrawFromVault(uint256 amount) internal {
curveVault.withdraw(
amount,
address(this),
address(this), // Corrected msg.sender to LendingPool
0,
new address
);
totalVaultDeposits -= amount;
}

Updates

Lead Judging Commences

inallhonesty Lead Judge 4 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 4 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.