The StakingPool contract contains a critical vulnerability that allows an attacker to artificially inflate the totalStaked value through the donateTokens function. This inflation can lead to a Denial of Service (DoS) condition for user deposits and significantly manipulate the reward distribution mechanism, potentially reducing rewards to near-zero levels.
The vulnerability stems from the donateTokens function, which allows any user to increase the totalStaked value without minting corresponding liquid staking tokens:
This function lacks access controls and doesn't have any upper limit on the amount that can be donated. An attacker can exploit this to artificially inflate the totalStaked value to an extremely high amount.
The inflated totalStaked value affects several critical functions:
The canDeposit function may always return 0, preventing new deposits:
The share minting calculation in _updateStrategyRewards is severely impacted:
Denial of Service: Users may be unable to make new deposits for an extended period as the canDeposit function is verified in the depositLiquidity function and also in the getStrategyDepositRoom, which is further used in PriorityPool::checkUpkeep, leading to DoS of critical functions like PriorityPool::performUpkeep.
Reward Manipulation: The number of shares minted for fee distribution can be reduced to near-zero levels, severely impacting the reward mechanism and economic incentives of the protocol.
Misleading Protocol Metrics: An inflated totalStaked value provides false information about the true state of the pool, potentially misleading users and external systems.
If totalStaked is inflated, it will cause the StakingPool::canDeposit function to always return 0. StakingPool::canDeposit is used as a check in the StakingPool::_depositLiquidity function, which may result in incorrect calculations:
StakingPool::canDeposit is called in StakingPool::getStrategyDepositRoom, which is used externally in PriorityPool::checkUpkeep, disrupting the functionalities of PriorityPool::performUpkeep.
This leads to significant issues in functions like PriorityPool::_deposit and PriorityPool::_depositQueuedTokens that depend on the correct return value of getStrategyDepositRoom.
Incorrect calculation and minting of the shares inside StakingPool::_updateStrategyRewards:
Let's assume :
Initial totalStaked = 1,000,000 tokens
Initial totalShares = 1,000,000 shares
totalFeeAmounts = 10,000 tokens
totalStaked inflated to 1e30):This demonstrates a near 100% reduction in minted shares for rewards.
Manual Code Review
Remove the donateTokens function:
Use a separate accounting system for the donated tokens. Introduce a new variable to track total deposits separately from totalStaked.
Modify the Share Minting Calculation: When calculating shares to mint, exclude the donatedTokens from the totalStaked value to ensure the minted shares reflect the actual staked tokens, not the donated ones.
Add rate limiting on the donateTokens function:
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.