Summary
Incorrect ReentrancyGuard version results in reentrancy guard not being initialized correctly, which can potentially break reentrancy protection.
Vulnerability Details
The StabilityPool contract in the RAAC protocol aims to be upgradeable. To ensure this, it makes use of some upgradeable variations of Open Zeppelin's contracts, such as OwnableUpgradeable and PausableUpgradeable.
contract StabilityPool is IStabilityPool, Initializable, ReentrancyGuard, OwnableUpgradeable, PausableUpgradeable {
...
}
This is crucial because constructors are not executed in upgradeable contracts. That's why there's a dedicated initialize function that has to be called by the proxy that calls into the implementation contract. It takes care of initializing parent contracts as well.
function initialize(
address _rToken,
address _deToken,
address _raacToken,
address _raacMinter,
address _crvUSDToken,
address _lendingPool
) public initializer {
if (_rToken == address(0) || _deToken == address(0) || _raacToken == address(0) || _raacMinter == address(0) || _crvUSDToken == address(0) || _lendingPool == address(0)) revert InvalidAddress();
__Ownable_init(_initialOwner);
__Pausable_init();
...
}
The ReentrancyGuard however, is imported as the non-upgradeable version. Which means it's not properly initialized and could even cause storage collisions in future upgrades. It's nonReentrant modifier is used on crucial functions of the contract, so it's very important that is set up correctly.
Impact
Using the non-upgradeable version causes the ReentrancyGuard to not be initialized correctly, which could potentially break reentrancy protection.
Tools Used
Manual review.
Recommendations
Import, inherit and initialize the ReentrancyGuardUpgradeable version instead as shown below:
import "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol";
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import "@openzeppelin/contracts-upgradeable/utils/PausableUpgradeable.sol";
+ import "@openzeppelin/contracts-upgradeable/utils/ReentrancyGuardUpgradeable.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
- import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
...
- contract StabilityPool is IStabilityPool, Initializable, ReentrancyGuard, OwnableUpgradeable, PausableUpgradeable {
+ contract StabilityPool is IStabilityPool, Initializable, ReentrancyGuardUpgradeable, OwnableUpgradeable, PausableUpgradeable {
...
function initialize(
address _rToken,
address _deToken,
address _raacToken,
address _raacMinter,
address _crvUSDToken,
address _lendingPool
) public initializer {
if (_rToken == address(0) || _deToken == address(0) || _raacToken == address(0) || _raacMinter == address(0) || _crvUSDToken == address(0) || _.lendingPool == address(0)) revert InvalidAddress();
__Ownable_init(_initialOwner);
__Pausable_init();
+. __ReentrancyGuard_init();
...
}
...
}
Relevant links