Missing unstake-amount validation
Description
The _requestUnstake function in the ValidatorStaking contract does not properly validate whether the unstaking amount is less than or equal to the user's staked amount. This oversight could potentially allow users to unstake more tokens than they have actually staked.
The _assertUnstakeAmountCondition function only checks whether the unstaking amount is greater than or equal to the minimum unstaking amount; it fails to verify that the amount is within the user's available stake:
function _assertUnstakeAmountCondition(StorageV1 storage $, address valAddr, address staker, uint256 amount)
internal
view
{
uint256 currentStaked = $.staked[valAddr][staker].latest();
uint256 minUnstaking = $.minUnstakingAmount;
if (amount != currentStaked) {
require(amount >= minUnstaking, IValidatorStaking__InsufficientMinimumAmount(minUnstaking));
}
}This issue is particularly concerning because the state storage system uses checkpoints that operate with the unchecked keyword, which allows underflows when subtracting values:
function _storeUnstake(StorageV1 storage $, uint48 now_, address valAddr, address staker, uint208 amount)
internal
virtual
{
_push($.staked[valAddr][staker], now_, amount, _opSub);
_push($.stakerTotal[staker], now_, amount, _opSub);
_push($.validatorTotal[valAddr], now_, amount, _opSub);
}
// ...
function _opSub(uint208 x, uint208 y) private pure returns (uint208) {
unchecked {
return x - y;
}
}When a user attempts to unstake more than they have staked, the _opSub function would cause an underflow due to the unchecked block, potentially allowing users to drain the vault with arbitrary unstaking amounts.
Impact
This issue could allow malicious users to unstake more tokens than they have staked, potentially draining the entire vault and affecting all users' funds.
Recommendations
Add a validation check in the _assertUnstakeAmountCondition function to ensure that the unstaking amount is less than or equal to the user's current staked amount.
Remediation
This issue has been acknowledged by Mitosis, and a fix was implemented in commit 7be2b3ba↗.