The OperatorVault.sol contract within the stake.link platform exhibits a critical reentrancy vulnerability in its withdrawRewards function. This flaw allows malicious actors to exploit the contract's reward withdrawal mechanism, enabling them to withdraw more funds than intended by manipulating the unclaimedRewards state variable through reentrant calls.
Function: withdrawRewards
Explanation: The withdrawRewards function is restricted to be called solely by the rewardsReceiver. It internally invokes the private function _withdrawRewards, which handles the actual withdrawal logic.
_withdrawRewardsExplanation: The _withdrawRewards function performs two external calls:
External Call to withdrawOperatorRewards: Interacts with the vaultController to withdraw operator rewards.
External Call to safeTransfer: Transfers the remaining rewards to the rewardsReceiver.
Crucially, the state variable unclaimedRewards is updated after these external calls, leaving a window for potential reentrancy attacks.
Malicious Contract Setup
Explanation: The MaliciousReceiver contract is crafted to exploit the reentrancy vulnerability. Its fallback function is triggered during the safeTransfer call in _withdrawRewards, allowing it to re-enter the withdrawRewards function multiple times before unclaimedRewards is decremented.
Attack Execution Steps:
Deployment: The attacker deploys the MaliciousReceiver contract and sets it as the rewardsReceiver in the OperatorVault.
Initiate Withdrawal: The attacker calls withdrawRewards(), triggering the _withdrawRewards function.
Reentrancy Trigger: During the safeTransfer to MaliciousReceiver, the fallback function is invoked, which calls withdrawRewards() again.
Repeated Exploitation: This process repeats, allowing the attacker to withdraw rewards multiple times before unclaimedRewards is properly updated.
Expected Outcome: The attacker can drain more rewards than they are entitled to, exploiting the reentrancy vulnerability to manipulate the unclaimedRewards state variable.
Exploiting this vulnerability can lead to significant financial losses for the stake.link platform and its users. Attackers can withdraw excessive rewards, undermining the integrity and trustworthiness of the staking mechanism. This breach not only affects the immediate financial aspects but also damages the platform's reputation and user confidence.
Manual Review
To safeguard the withdrawRewards function against reentrancy attacks, the following mitigation strategies should be implemented:
Utilize OpenZeppelin's ReentrancyGuard to prevent reentrant calls.
Explanation: The nonReentrant modifier ensures that the withdrawRewards function cannot be called while it is already in execution, effectively blocking reentrant attempts.
Rearrange the order of operations to update critical state variables before making any external interactions.
Explanation: By updating unclaimedRewards before executing external calls, the contract ensures that even if a reentrant call is attempted, the state has already been modified to prevent multiple withdrawals.
Ensure that all state changes (effects) occur before any external interactions.
Explanation: This pattern minimizes the risk of reentrancy by ensuring that all necessary state changes are completed before any external calls are made.
Where feasible, redesign functions to minimize or eliminate external calls, or employ the pull over push mechanism for withdrawals.
Explanation: By emitting an event instead of directly transferring funds, the contract delegates the responsibility of transferring rewards to the receiver, reducing the risk of reentrancy.
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.