The dissolveValidator function is susceptible to a reentrancy attack. This function makes an external call to the pirexEth.dissolveValidator{value: _amount}(_pubKey) function without any reentrancy guard. An attacker could exploit this vulnerability by crafting a malicious contract that reenters the dissolveValidator function multiple times before the initial execution completes. This could lead to severe consequences, such as draining the contract’s funds or causing unexpected state changes.
proof of concept
1.A malicious pirexEth contract is deployed that, when its dissolveValidator function is called, makes a recursive call back to RewardRecipient.dissolveValidator.
2.The recursive call occurs before the original function call completes, allowing the attacker to execute unintended code paths or manipulate the contract's state
Impact
Unauthorized Validator Dissolution: The attacker could potentially dissolve validators multiple times, causing disruption to the validator management process.
ETH Draining: If the function is used to transfer ETH, an attacker could repeatedly call dissolveValidator, draining funds from the contract.
Recommendation
Implement a reentrancy guard using the nonReentrant modifier from OpenZeppelin’s ReentrancyGuard contract to prevent re-entry into the function.
Alternatively, rearrange the function logic to ensure that all state changes are made before the external call to pirexEth.dissolveValidator.
Lines of code
https://github.com/dinero-protocol/pirex-eth-contracts/blob/11f30c7e35b67d45deefe405c22a30f352bc5b21/src/RewardRecipient.sol#L102
Vulnerability details
Summary
The dissolveValidator function is susceptible to a reentrancy attack. This function makes an external call to the pirexEth.dissolveValidator{value: _amount}(_pubKey) function without any reentrancy guard. An attacker could exploit this vulnerability by crafting a malicious contract that reenters the dissolveValidator function multiple times before the initial execution completes. This could lead to severe consequences, such as draining the contract’s funds or causing unexpected state changes.
proof of concept
1.A malicious pirexEth contract is deployed that, when its dissolveValidator function is called, makes a recursive call back to RewardRecipient.dissolveValidator. 2.The recursive call occurs before the original function call completes, allowing the attacker to execute unintended code paths or manipulate the contract's state
Impact
Unauthorized Validator Dissolution: The attacker could potentially dissolve validators multiple times, causing disruption to the validator management process.
ETH Draining: If the function is used to transfer ETH, an attacker could repeatedly call dissolveValidator, draining funds from the contract.
Recommendation
Implement a reentrancy guard using the nonReentrant modifier from OpenZeppelin’s ReentrancyGuard contract to prevent re-entry into the function.
Alternatively, rearrange the function logic to ensure that all state changes are made before the external call to pirexEth.dissolveValidator.
function dissolveValidator( bytes calldata _pubKey, uint256 _amount ) external onlyOracleAdapter nonReentrant { // Added nonReentrant pirexEth.dissolveValidator{value: _amount}(_pubKey); }
References:
->OpenZeppelin ReentrancyGuard
->Reentrancy Attacks - Ethereum Smart Contract Best Practices