Stratax Contracts

First Flight #57
Beginner FriendlyDeFi
100 EXP
Submission Details
Impact: medium
Likelihood: low

No zero-address validation in `initialize()` makes misconfigured proxy permanently broken

Author Revealed upon completion

Root Cause + Impact

initialize() sets 5 critical protocol addresses without zero-address validation. The initializer modifier ensures this function runs exactly once per proxy, so a misconfigured deployment produces a permanently non-functional proxy that must be redeployed.

Description

All 5 address parameters are written to storage without checks:

// Stratax.sol:173-187
function initialize(
address _aavePool,
address _aaveDataProvider,
address _oneInchRouter,
address _usdc,
address _strataxOracle
) external initializer {
// @> aavePool = IPool(_aavePool); // no zero check
// @> aaveDataProvider = IProtocolDataProvider(_aaveDataProvider); // no zero check
// @> oneInchRouter = IAggregationRouter(_oneInchRouter); // no zero check
// @> USDC = _usdc; // no zero check
// @> strataxOracle = _strataxOracle; // no zero check
owner = msg.sender;
flashLoanFeeBps = 9;
}

Unlike constructors in non-upgradeable contracts, initialize() cannot be called again if a mistake is made. OpenZeppelin's initializer modifier flips a storage flag on the first call, permanently blocking subsequent calls. This makes input validation especially important: there is no second chance.

Each of the 5 addresses is used in core protocol functions:

  • aavePool -- called in createLeveragedPosition(), unwindPosition(), and executeOperation() for flash loans, supply, borrow, repay, and withdraw

  • aaveDataProvider -- called in calculateOpenParams() and _executeUnwindOperation() for reserve configuration

  • oneInchRouter -- called in _call1InchSwap() for every swap

  • strataxOracle -- called in calculateOpenParams(), calculateUnwindParams(), and _executeUnwindOperation() for pricing

If any of these is address(0), the corresponding low-level call reverts with no meaningful error message. The proxy appears deployed but every user-facing operation fails.

Note that setStrataxOracle() does validate for zero address (L264), but the initial assignment in initialize() does not. This is inconsistent.

Risk

Likelihood: Low -- Requires a deployment error. Automated scripts and test suites reduce this risk, but the contract provides no safety net of its own.

Impact: Medium -- A misconfigured proxy is permanently non-functional. The protocol must deploy a new proxy, update all references, and redirect users. Any tokens sent to the broken proxy address before discovery require manual recovery via a new proxy pointing to the same beacon.

Proof of Concept

The initializer modifier from OpenZeppelin sets _initialized = 1 on first call and reverts on all subsequent calls. Deploying a BeaconProxy with _aavePool = address(0):

1. BeaconProxy constructor calls initialize(address(0), ...) via delegatecall
2. initializer modifier sets _initialized = 1 in proxy storage
3. aavePool = IPool(address(0)) is stored
4. User calls createLeveragedPosition() -> aavePool.flashLoanSimple() calls address(0) -> reverts
5. Owner tries to fix by calling initialize() again -> reverts ("Initializable: contract is already initialized")
6. Proxy is permanently broken

Recommended Mitigation

Validate all addresses before committing them to storage. Since the initializer modifier prevents re-calling, these checks are the only safety net against a misconfigured deployment:

function initialize(
address _aavePool,
address _aaveDataProvider,
address _oneInchRouter,
address _usdc,
address _strataxOracle
) external initializer {
+ require(_aavePool != address(0), "Invalid aavePool");
+ require(_aaveDataProvider != address(0), "Invalid aaveDataProvider");
+ require(_oneInchRouter != address(0), "Invalid oneInchRouter");
+ require(_usdc != address(0), "Invalid usdc");
+ require(_strataxOracle != address(0), "Invalid oracle");
aavePool = IPool(_aavePool);
aaveDataProvider = IProtocolDataProvider(_aaveDataProvider);
oneInchRouter = IAggregationRouter(_oneInchRouter);
USDC = _usdc;
strataxOracle = _strataxOracle;
owner = msg.sender;
flashLoanFeeBps = 9;
}

Support

FAQs

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

Give us feedback!