Core Contracts

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

Users can drain the lendingPool during withdraw()

Summary

When the withdraw() function is called in the lendingPool, it calls the withdraw() in the reserveLibrary which makes sure aomunt >= 1 and then further calls the burn function in the RToken.sol. The issue lies in the fact that the amount burnt is amount.rayDiv(liquidationIndex) which can be 0 but the crvUSD transferred is of amount amount. Users can manipulate this error and drain the entire lending pool.

Vulnerability Details

Assume the following scenario:

  1. A user has a non-zero balance (by depositing some amount first into the lendingPool). Current LiquidationIndex = 3e27 (note that liquidationIndex always increases and never decreases so over time it will reach this amount).

  2. The user calls the withdraw with amount = 1.

  3. the burn function in the RToken makes sure that 1 <= balanceOf(user) (which is satisfied since he has deposited first).

  4. Then it calls the _burn(from, amount.toUint128()); function which internally tries to burn amount.rayDiv(liquidationIndex) => 1.rayDiv(3e27) => (1*RAY + (3e27/2))/3e27 => (1e27+1e27)/3e27 => 0

    (this is the calculation in the WADRAYMATH with all the rounding)
    So 0 amount will be burnt from the user's internal balance.

  5. Then 1 _assetAddresstoken will be transferred to the user.
    Thus essentially the user has withdrawn 1 wei crvUSD without reducing his balance. The user can continue using this method to completely drain the lending pool and thus the other users funds.

function _update(address from, address to, uint256 amount) internal override {
// Scale amount by normalized income for all operations (mint, burn, transfer)
uint256 scaledAmount = amount.rayDiv(ILendingPool(_reservePool).getNormalizedIncome());
super._update(from, to, scaledAmount);
}
function burn(
address from,
address receiverOfUnderlying,
uint256 amount,
uint256 index
) external override onlyReservePool returns (uint256, uint256, uint256) {
if (amount == 0) {
return (0, totalSupply(), 0);
}
uint256 userBalance = balanceOf(from);
_userState[from].index = index.toUint128();
if(amount > userBalance){
amount = userBalance;
}
uint256 amountScaled = amount.rayMul(index);
_userState[from].index = index.toUint128();
_burn(from, amount.toUint128());
// internally calls the _update function which makes scaledamount = amount.rayDiv(index)
// and then calls the super._update(user,scaledamount) (scaledamount == 0 in this case)
if (receiverOfUnderlying != address(this)) {
IERC20(_assetAddress).safeTransfer(receiverOfUnderlying, amount);
// transfers 1 wei in this case
}
emit Burn(from, receiverOfUnderlying, amount, index);
return (amount, totalSupply(), amount);
}

Impact

The complete draining of the lending Pool. Note that as the liquidation index increases this attack becomes more profitable for the attacker. Even if the attack is not profitable for the user, the attacker can make the other users funds = 0. This should make the bug a HIGH severity one.

Tools Used

manual Review

Recommendations

Make sure that the burnt amount ! = 0.

Updates

Lead Judging Commences

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

RToken::burn should check that burnt amount ! = 0

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

RToken::burn should check that burnt amount ! = 0

Appeal created

anonymousjoe Submitter
4 months ago
anonymousjoe Submitter
4 months ago
inallhonesty Lead Judge
4 months ago
anonymousjoe Submitter
4 months ago
inallhonesty Lead Judge
3 months ago
inallhonesty Lead Judge 3 months ago
Submission Judgement Published
Validated
Assigned finding tags:

StabilityPool allows free DEToken minting when liquidityIndex ≥ 2e27 due to integer rounding in RToken transfers, enabling pool draining

Support

FAQs

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