Liquid Staking

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

Critical Token Transfer Vulnerability in _deposit() Function would drain the contract funds

Description

When a user calls the deposit() function, the internal _deposit() function is invoked. However, there is a critical issue in how the safeTransfer function is implemented, which mistakenly transfers tokens from the contract to the user, potentially allowing them to drain the contract's funds.

function _deposit(
address _account,
uint256 _amount,
bool _shouldQueue,
bytes[] memory _data
) internal {
if (poolStatus != PoolStatus.OPEN) revert DepositsDisabled();
uint256 toDeposit = _amount;
if (totalQueued == 0) {
uint256 queuedWithdrawals = withdrawalPool.getTotalQueuedWithdrawals();
if (queuedWithdrawals != 0) {
uint256 toDepositIntoQueue = toDeposit <= queuedWithdrawals
? toDeposit
: queuedWithdrawals;
withdrawalPool.deposit(toDepositIntoQueue);
toDeposit -= toDepositIntoQueue;
// critical bug => when depositing this part of function mistakenly sends => potentially draining the contract
IERC20Upgradeable(address(stakingPool)).safeTransfer(_account, toDepositIntoQueue);
}
....
}

Impact

  • Critical Loss of Funds: This line erroneously transfers the tokens (toDepositIntoQueue) to the user's address (_account) after depositing them into the withdrawal pool. The result is that the contract could double spend the tokens, transferring them to the user even though they should remain within the contract.

  • Exploitation Risk: A malicious user could repeatedly call the deposit() function while there are queued withdrawals, continuously receiving free tokens from the contract. This can eventually deplete the contract’s funds, potentially leading to its insolvency.


Recommendations

  1. Remove the Erroneous Transfer: The line where IERC20Upgradeable(address(stakingPool)).safeTransfer(_account, toDepositIntoQueue); is called should be removed. This line mistakenly transfers tokens to the user's account and should not exist.

    Instead, the tokens should only be deposited into the withdrawalPool as follows:

    withdrawalPool.deposit(toDepositIntoQueue);
    toDeposit -= toDepositIntoQueue;
Updates

Lead Judging Commences

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

Support

FAQs

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