Core Contracts

Regnum Aurum Acquisition Corp
HardhatReal World AssetsNFT
77,280 USDC
View results
Submission Details
Severity: high
Invalid

Proxy Deployment Initialization Vulnerability in StabilityPool Contract

Summary

The StabilityPool contract is designed as an upgradeable contract using OpenZeppelin's Initializable pattern. However, the contract contains a constructor that sets critical state variables (e.g., _initialOwnerand a state varible uint256 public index = 1e18 . When deployed via a proxy, the constructor is not executed and this state varible is not set, leaving these values uninitialized. This oversight can result in the contract operating with default or zero values for these important variables, potentially compromising the contract's security and intended functionality.

Vulnerability Details

The StabilityPool contract includes a constructor intended to initialize vital state variables:

address private immutable _initialOwner;
constructor(address initialOwner) {
_initialOwner = initialOwner;
}

In an upgradeable contract deployed via a proxy, constructors are bypassed, and initialization must occur in an initialize function. Since the constructor is not called during proxy deployment:

  • The _initialOwner variable remains uninitialized (defaulting to the zero address).

  • The index variable is also not explicitly set by the initializer.

POC

  1. Deployment via Proxy:

    • The StabilityPool contract is deployed behind a proxy.

    • The proxy’s delegatecall bypasses the constructor, so _initialOwner is not set to the intended owner address.

  2. Ownership Exploitation:

    • Since _initialOwner is not set, the OwnableUpgradeable logic might fall back on the zero address or an uninitialized state.

    • An attacker could potentially assume control by exploiting the absence of a proper owner, thereby invoking restricted functions (e.g., adding/removing managers, updating allocations, or setting the liquidity pool).

Impact

An uninitialized owner variable can leave the contract vulnerable to unauthorized access, potentially allowing an attacker to seize control of critical admin functions.

Tools Used

Manual Review

Recommendation

Replace the constructor with an initializer function to properly set the _initialOwner and any other critical state variables (such as index) when the contract is deployed via a proxy. For example:

function initialize(
address _rToken,
address _deToken,
address _raacToken,
address _raacMinter,
address _crvUSDToken,
address _lendingPool,
address initialOwner
) 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();
rToken = IRToken(_rToken);
deToken = IDEToken(_deToken);
raacToken = IRAACToken(_raacToken);
raacMinter = IRAACMinter(_raacMinter);
crvUSDToken = IERC20(_crvUSDToken);
lendingPool = ILendingPool(_lendingPool);
// Initialize decimals and other state variables
rTokenDecimals = IRToken(_rToken).decimals();
deTokenDecimals = IDEToken(_deToken).decimals();
// Properly initialize index
index = 1e18;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!