Liquid Staking

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

Unsafe type casting in `_updateStrategyRewards` function could lead to integer overflow potentially breaking the entire System

Summary

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.

Vulnerability Details

The vulnerability lies in the following snippet of the _updateStrategyRewards() function:

function _updateStrategyRewards(uint256[] memory _strategyIdxs, bytes memory _data) private {
int256 totalRewards;
...
// update totalStaked if there was a net change in deposits
if (totalRewards != 0) {
totalStaked = uint256(int256(totalStaked) + totalRewards); // @audit unsafe typecast
}
...
}

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.

Example of the Risk:

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.

NOTE:

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.

Impact

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.

Tools Used

Manual code review

Recommendations

  1. 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:

int256 newTotalStaked = int256(totalStaked) + totalRewards;
require(newTotalStaked >= 0, "StakingPool: total staked cannot be negative");
totalStaked = uint256(newTotalStaked);
Updates

Lead Judging Commences

inallhonesty Lead Judge
about 1 year ago
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.