Liquid Staking

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

Lack of Access Control in splitRewards Function Enables Abuse of Reward Distribution

Summary

The splitRewards function in the LSTRewardsSplitter contract is publicly accessible and does not check the reward threshold. This allows any external actor to bypass the intended reward distribution mechanism. While this implementation is useful when removing a splitter,since the reward threshold is not necessary,it exposes the contract to potential abuse by triggering reward splits prematurely, even in small amounts that can lead to precision loss that compounds over time to huge amounts.
https://github.com/Cyfrin/2024-09-stakelink/blob/f5824f9ad67058b24a2c08494e51ddd7efdbb90b/contracts/core/lstRewardsSplitter/LSTRewardsSplitterController.sol#L159

https://github.com/Cyfrin/2024-09-stakelink/blob/f5824f9ad67058b24a2c08494e51ddd7efdbb90b/contracts/core/lstRewardsSplitter/LSTRewardsSplitter.sol#L116

Vulnerability Details

The contract implements a reward threshold to ensure rewards are distributed only when sufficient new rewards have accumulated as enforced by the performUpkeep function:
https://github.com/Cyfrin/2024-09-stakelink/blob/f5824f9ad67058b24a2c08494e51ddd7efdbb90b/contracts/core/lstRewardsSplitter/LSTRewardsSplitterController.sol#L159

function setRewardThreshold(uint256 _rewardThreshold) external onlyOwner {
rewardThreshold = _rewardThreshold;
}

However, the LSTRewardsSplitter.splitRewards() is public and does not include this threshold check. This is necessary as the LSTRewardsSplitterController calls it to split any rewards while removing a splitter regardless of the threshold.

The splitRewards() distributes rewards using the formula:

uint256 amount = (_rewardsAmount * fee.basisPoints) / 10000;

Any malicious users will call this function frequently with small _rewardsAmount,Even though precision loss is minimized in the equation,t he long term impact or such repeated calls cannot be ignored.

Impact

Frequent splitting of small reward amounts results in rounding errors(though minimized) due to the use of the formula:

uint256 amount = (_rewardsAmount * fee.basisPoints) / 10000;

This loss becomes more significant over time as multiple small splits can cumulatively result in a substantial loss of reward value.

Tools Used

Manual Review

Recommendations

Limit the ability to call splitRewards to the LSTRewardsSplitterController and the contract owner ensuring it cannot be abused by external actors. In addition their is also a performUpkeep function that routinely calls the _splitRewards function once the threshold is achieved, therefore its not necessary to leave it publicly accessible.

Updates

Lead Judging Commences

inallhonesty Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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