OpenZeppelin's upgradeable pattern requires that the implementation contract (the logic address the beacon points to) be permanently locked against direct initialization. This is done by calling _disableInitializers() in a constructor.
Stratax has no constructor. Any caller can invoke initialize(...) directly on the implementation address (not through a proxy), claiming the owner role on the bare implementation contract. While proxy storage is unaffected, the unlocked implementation is an active attack surface.
Likelihood:
The implementation address is publicly visible on-chain (via beacon.implementation()) and the initialize function is publicly callable with no preconditions
Any bot watching for newly deployed upgradeable contracts without a disabled initializer will call it within seconds of deployment
Impact:
The attacker owns the implementation contract and can call recoverTokens on any tokens accidentally sent directly to the implementation address
The unlocked implementation creates confusion for off-chain tooling and security monitoring systems that inspect the implementation directly, masking the real ownership state
After beacon and implementation deployment, before any defensive measure is taken, an attacker calls initialize directly on the implementation contract address.
The fix is a single line in a constructor. The absence of this line is detectable before deployment and exploitable immediately after.
Add a constructor to Stratax that permanently disables initialization on the implementation:
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.
The contest is complete and the rewards are being distributed.