In the StakingPool contract, the internal _updateStrategyRewards() function casts a signed integer (int256) back to an unsigned integer (uint256) without checking whether the result is negative. This unchecked type cast introduces a critical risk of integer overflow if the total rewards (which could be negative) exceed the total staked amount. If this occurs, the cast to uint256 would result in an extremely large number, corrupting the totalStaked value and leading to incorrect calculations downstream. This vulnerability could disrupt the entire staking reward system.
The vulnerability lies in the following snippet of the _updateStrategyRewards() function:
In this line, totalStaked is cast from uint256 to int256 so that it can be added to the (potentially negative) totalRewards. The result is cast back to uint256 before being reassigned to totalStaked. However, if the value of int256(totalStaked) + totalRewards is negative, the cast to uint256 will cause an integer overflow, resulting in an extremely large positive number due to the nature of how underflows work with unsigned integers in Solidity.
Assume the following scenario:
totalStaked = 100
totalRewards = -150
When casting totalStaked to int256 and adding totalRewards, the result will be -50. Casting this back to uint256 will cause an overflow, leading to a massive number close to 2^256 - 50 or in a simple words the result of this operation is equal to 115792089237316195423570985008687907853269984665640564039457584007913129639886. This could corrupt all subsequent calculations based on totalStaked and disrupt the protocol’s functionality.
There is a check in place: if (totalRewards != 0). However, this check is insufficient because while it prevents execution when totalRewards is zero, it does not prevent execution when totalRewards is negative. Since negative numbers are still "non-zero," the condition will be true, and the unsafe type cast will still occur. This is why the check does not mitigate the risk of an integer overflow.
If the type casting leads to an integer overflow, the totalStaked value will become an incorrect, large number. This will affect every calculation that depends on totalStaked, including reward distributions and fee allocations, eventually breaking the entire system.
Manual code review
Check for Negative Results Before Casting: Add a check to ensure that the result of int256(totalStaked) + totalRewards is non-negative before casting it back to uint256. This can be done by using a require() statement:
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.