Liquid Staking

Stakelink
DeFiHardhatOracle
50,000 USDC
View results
Submission Details
Severity: low
Invalid

Underflow in `withdraw` Function Allows Draining of Funds

Summary

The withdraw function in the LSTRewardsSplitter contract has an underflow vulnerability due to in-validation of the _amount parameter. The function subtracts _amount from principalDeposits without checking if _amount is less than or equal to principalDeposits. This can lead to an underflow if _amount is greater than principalDeposits, causing principalDeposits to wrap around to a very large value.

Vulnerability Details

The withdraw function in the LSTRewardsSplitter contract does not properly validate that the _amount being withdrawn is less than or equal to the current principalDeposits. This can lead to an underflow of principalDeposits, allowing an attacker to drain the contract of its funds.

  1. The withdraw function subtracts the _amount from principalDeposits without checking if _amount is less than or equal to principalDeposits: https://github.com/Cyfrin/2024-09-stakelink/blob/f5824f9ad67058b24a2c08494e51ddd7efdbb90b/contracts/core/lstRewardsSplitter/LSTRewardsSplitter.sol#L79-L83

function withdraw(uint256 _amount, address _receiver) external onlyController {
principalDeposits -= _amount; // <-- Vulnerable line
lst.safeTransfer(_receiver, _amount);
emit Withdraw(_amount);
}
  1. If _amount is greater than principalDeposits, the subtraction will underflow, causing principalDeposits to wrap around to a very large value (2^256 - 1) instead of the expected value.

  2. This allows an attacker to withdraw more funds than they should be able to, effectively draining the contract.

The vulnerability occurs because the withdraw function does not validate the _amount being withdrawn against the current principalDeposits.

Scenario:

  1. An attacker calls the deposit function with a small amount of tokens, e.g., 10 tokens.

  2. The attacker then calls the withdraw function with an _amount greater than the deposited amount, e.g., 11 tokens.

  3. Inside the withdraw function, principalDeposits is decreased by 11, resulting in an underflow since principalDeposits (10) is less than the withdrawn amount (11).

  4. The underflow causes principalDeposits to wrap around to a very large value (2^256 - 1).

  5. The attacker's specified _amount of tokens is transferred to their _receiver address, effectively allowing them to withdraw more tokens than they should be able to.

Impact

If an attacker calls withdraw with an _amount greater than the current principalDeposits, the subtraction will underflow, setting principalDeposits to a very large value.

Tools Used

Manual Review

Recommendations

add a check in the withdraw function to ensure that the _amount being withdrawn is less than or equal to the current principalDeposits:

function withdraw(uint256 _amount, address _receiver) external onlyController {
+ require(_amount <= principalDeposits, "Insufficient principal");
principalDeposits -= _amount;
lst.safeTransfer(_receiver, _amount);
emit Withdraw(_amount);
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 8 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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