require(uint128(block.number) > us.coolDownEnd, "Cooldown period has not ended");
However, combined with the function redelegateUnstaked, some validators can bypass the coolDown mechanism, thereby completing instant unstakes and withdrawals.
The attack scenario is as follows:
The protocol adds a validator A (the attacker), and initially disabledAtBlock is 1.
Validator A acts as a delegator to stake on other active validators.
Validator A unstake from other active validators (labeled usX for convenience).
For usX, validator A uses the function redelegateUnstaked to delegate it to himself/herself.
The only check is:
require(newStaked <= validatorMaxStake, "Validator max stake exceeded");
Unstake from himself/herself. Since disabledAtBlock is 1, coolDownEnd will be 1+validatorCoolDown, which means there is a high probability that it is smaller than block.number. So withdrawals can be made directly.
Impact
The coolDown mechanism can be bypassed for some validators
qmdddd
medium
The coolDown mechanism can be bypassed for some validators
Summary
The coolDown mechanism can be bypassed for some validators
Vulnerability Detail
When a user makes a unstake, the protocol will use a coolDown mechanism to delay the user's actual withdrawal.
function _unstake:
function transferUnstakedOut:
However, combined with the function
redelegateUnstaked
, some validators can bypass the coolDown mechanism, thereby completing instant unstakes and withdrawals.The attack scenario is as follows:
The protocol adds a validator A (the attacker), and initially disabledAtBlock is 1.
Validator A acts as a delegator to stake on other active validators.
Validator A unstake from other active validators (labeled usX for convenience).
For usX, validator A uses the function
redelegateUnstaked
to delegate it to himself/herself.The only check is:
Unstake from himself/herself. Since disabledAtBlock is 1, coolDownEnd will be 1+validatorCoolDown, which means there is a high probability that it is smaller than block.number. So withdrawals can be made directly.
Impact
The coolDown mechanism can be bypassed for some validators
Code Snippet
https://github.com/sherlock-audit/2023-11-covalent/blob/main/cqt-staking/contracts/OperationalStaking.sol#L523-L536
https://github.com/sherlock-audit/2023-11-covalent/blob/main/cqt-staking/contracts/OperationalStaking.sol#L664-L684
Tool used
Manual Review
Recommendation
In function
redelegateUnstaked
, disable msg.sender as newValidator.Duplicate of #78