Stratax Contracts

First Flight #57
Beginner FriendlyDeFi
100 EXP
View results
Submission Details
Impact: high
Likelihood: low
Invalid

`initialize()` Can Be Front-Run on Proxy Deployment

initialize() Can Be Front-Run on Proxy Deployment

Description

  • If the proxy deployment and initialize() call are not performed atomically (e.g., not in a factory contract or deployProxy helper), an attacker monitoring the mempool can front-run the initialize() transaction and become the owner of the proxy.

function initialize(
address _aavePool,
address _aaveDataProvider,
address _oneInchRouter,
address _usdc,
address _strataxOracle
) external initializer {
// ...
owner = msg.sender; // @audit Whoever calls initialize() first becomes owner
}
  • The initializer modifier only prevents calling initialize() a second time — it does not restrict who can call it the first time.

Risk

Likelihood:

  • Low — most modern deployment scripts use atomic proxy deployment (e.g., OpenZeppelin's deployProxy or Foundry scripts that deploy + initialize in one transaction)

  • Only exploitable if the deployment and initialization are separate transactions

Impact:

  • If exploited, the attacker becomes the full owner of the proxy contract

  • As owner, the attacker controls all leveraged positions, can drain funds via recoverTokens(), and can change the oracle

Proof of Concept

How the attack works:

  1. Deployer sends transaction 1: deploy proxy pointing to Stratax implementation

  2. Deployer sends transaction 2: call initialize(aavePool, dataProvider, router, usdc, oracle) on the proxy

  3. Attacker observes transaction 2 in the mempool and front-runs it with higher gas

  4. Attacker's initialize() call is mined first — attacker becomes owner

  5. Deployer's initialize() call reverts because the initializer modifier detects it has already been called

Expected outcome: The attacker takes ownership of the proxy contract before the legitimate deployer.

Recommended Mitigation

The root cause is that initialize() is permissionless — anyone can call it first. The fix is to ensure deployment and initialization are atomic.

Primary fix — Deploy and initialize atomically:

// In deployment script — single transaction
address proxy = Upgrades.deployUUPSProxy(
"Stratax.sol",
abi.encodeCall(Stratax.initialize, (aavePool, dataProvider, oneInchRouter, usdc, oracle))
);

Why this works: The proxy is deployed and initialized in a single transaction, leaving no window for front-running. By the time the transaction is mined, the proxy is already initialized with the correct owner.

Updates

Lead Judging Commences

izuman Lead Judge 16 days 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!