Liquid Staking

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

Griefing Attack via Front-Running Leading to Loss of User Deposits in StakingPool.sol

Summary

A vulnerability exists in the StakingRewardsPool.sol contract, where the logic for minting shares allows a griefing attack. This attack impacts the share distribution and deposit process in the StakingPool.sol contract. A malicious actor can front-run legitimate depositors by artificially inflating the pool's assets before the victim's deposit transaction, resulting in the victim receiving zero shares for their deposit. This leads to a loss of funds for the victim, although the attacker spends more money to execute the attack.

Vulnerability Details

In the current implementation of _mintShares in StakingRewardsPool.sol, the function uses the total staked amount (totalStaked()) to calculate the number of shares to mint for a deposit. However, an attacker can manipulate this process by artificially inflating the total assets in the pool just before a legitimate user's deposit. This can be achieved by front-running the victim's transaction with an asset transfer.

Code Snippet

https://github.com/Cyfrin/2024-09-stakelink/blob/f5824f9ad67058b24a2c08494e51ddd7efdbb90b/contracts/core/StakingPool.sol#L111-L132

function deposit(
address _account,
uint256 _amount,
bytes[] calldata _data
) external onlyPriorityPool {
require(strategies.length > 0, "Must be > 0 strategies to stake");
uint256 startingBalance = token.balanceOf(address(this));
if (_amount > 0) {
token.safeTransferFrom(msg.sender, address(this), _amount);
_depositLiquidity(_data);
// @audit - _mint from StakingRewardsPool is called .
@-> _mint(_account, _amount);
totalStaked += _amount;
} else {
_depositLiquidity(_data);
}
uint256 endingBalance = token.balanceOf(address(this));
if (endingBalance > startingBalance && endingBalance > unusedDepositLimit)
revert InvalidDeposit();
}

https://github.com/Cyfrin/2024-09-stakelink/blob/f5824f9ad67058b24a2c08494e51ddd7efdbb90b/contracts/core/base/StakingRewardsPool.sol#L79-L86

https://github.com/Cyfrin/2024-09-stakelink/blob/f5824f9ad67058b24a2c08494e51ddd7efdbb90b/contracts/core/base/StakingRewardsPool.sol#L176-L181

https://github.com/Cyfrin/2024-09-stakelink/blob/f5824f9ad67058b24a2c08494e51ddd7efdbb90b/contracts/core/base/StakingRewardsPool.sol#L188-L199

function getSharesByStake(uint256 _amount) public view returns (uint256) {
uint256 totalStaked = _totalStaked();
if (totalStaked == 0) {
return _amount;
} else {
return (_amount * totalShares) / totalStaked;
}
}
function _mint(address _recipient, uint256 _amount) internal override {
uint256 sharesToMint = getSharesByStake(_amount);
@-> _mintShares(_recipient, sharesToMint);
emit Transfer(address(0), _recipient, _amount);
}
// @audit-issue : griefing attack is possible .
function _mintShares(address _recipient, uint256 _amount) internal {
require(_recipient != address(0), "Mint to the zero address");
if (totalShares == 0) {
shares[address(0)] = DEAD_SHARES;
totalShares = DEAD_SHARES
_amount -= DEAD_SHARES;
}
totalShares += _amount;
shares[_recipient] += _amount;
}

Impact

  • Financial Loss: A legitimate user can lose their entire deposit due to receiving zero shares for their contribution to the pool.

  • Griefing: While the attacker does not directly benefit from the stolen deposit, they can perform this attack to disrupt the operation of the pool and harm other users.

Proof Of Concept

Setup:

  • Assume the hacker deposits 1,000 shares into the pool using deposit(1000).

  • The pool now has totalStaked() == 1000 and totalShares() == 1000.

  • Attack Sequence:

    • The hacker front-runs the victim’s transaction by transferring 20,000 USDT to the pool.

    • The new totalStaked() becomes 20_000_000e6 + 1000, while totalShares() remains 1000.

  • Victim’s Transaction:

    • The victim attempts to deposit 20,000 USDT.

    • The number of shares the victim receives is calculated as: 20_000e6 * 1000 / (20_000_000e6 + 1000) == 0.

    • The victim gets zero shares, losing their entire deposit to the pool.

Tools Used

Manual review

Reference

https://mixbytes.io/blog/overview-of-the-inflation-attack

Recommendations

  • Mitigate Front-Running: Add mechanisms to prevent front-running attacks, such as limiting the time between transactions or setting a minimum share minting threshold based on recent transaction history.

  • Accurate Share Calculation: Modify the share minting logic to factor in pending deposits or the expected change in total assets. This ensures fair share distribution for all depositors regardless of any preceding transactions.

Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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