Summary
The StabilityPool's initialize()
function lacks access control and initializer modifiers, allowing attackers to repeatedly call initialization to reset critical contract parameters and state.
Vulnerability Details
StabilityPool.initialize
lacks access control, allowing re-initialization.
/StabilityPool.sol#initialize
function initialize(
address _rToken,
address _deToken,
address _raacToken,
address _raacMinter,
address _crvUSDToken,
address _lendingPool
) public initializer {
rToken = IRToken(_rToken);
deToken = IDEToken(_deToken);
raacToken = IRAACToken(_raacToken);
raacMinter = IRAACMinter(_raacMinter);
crvUSDToken = IERC20(_crvUSDToken);
lendingPool = ILendingPool(_lendingPool);
}
Path:
Attacker calls initialize()
after deployment
Contract state is reset to new values
Token addresses can be changed
Protocol functionality hijacked
Impact
Attackers could reset contract state.
Tools Used
manual
Recommendations
Add initializer
modifier and access control.
import "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
contract StabilityPool is Initializable, OwnableUpgradeable {
function initialize(
address _rToken,
address _deToken,
address _raacToken,
address _raacMinter,
address _crvUSDToken,
address _lendingPool
) external initializer onlyOwner {
__Ownable_init();
if (_rToken == address(0)) revert InvalidAddress();
if (_deToken == address(0)) revert InvalidAddress();
if (_raacToken == address(0)) revert InvalidAddress();
if (_raacMinter == address(0)) revert InvalidAddress();
if (_crvUSDToken == address(0)) revert InvalidAddress();
if (_lendingPool == address(0)) revert InvalidAddress();
rToken = IRToken(_rToken);
deToken = IDEToken(_deToken);
raacToken = IRAACToken(_raacToken);
raacMinter = IRAACMinter(_raacMinter);
crvUSDToken = IERC20(_crvUSDToken);
lendingPool = ILendingPool(_lendingPool);
emit PoolInitialized(_rToken, _deToken, _raacToken);
}
}