Solidity

Proxy Initialization

Proxy initialization is the setup step that assigns initial state for an upgradeable proxy, usually through an initializer function instead of a constructor.

A proxy must be initialized through the proxy exactly once, because the implementation constructor does not write to proxy storage.

Proxy Initialization Explained in Detail

Upgradeable proxies do not use the implementation constructor to set proxy storage. They need an initializer call, usually initialize(), executed through the proxy.

If initialization is missing, repeated, or callable by the wrong account, an attacker can become owner, upgrader, guardian, or role admin.

Smart contract example

contract Vault {
    address public owner;

    function initialize(address newOwner) external {
        owner = newOwner;
    }
}

Anyone can call initialize() unless an initializer guard and deployment flow protect it.

Proxy Initialization in Auditing

Initialization bugs are access control bugs at deployment time. They can turn a correct-looking implementation into a live proxy takeover.

Red flags in code

  • Public initialize() without initializer.

  • Proxy deployed first and initialized in a later transaction.

  • Implementation contract not locked with _disableInitializers() where appropriate.

  • Parent initializers missing or called in the wrong order.

  • reinitialize() exposed without a strict version and authorization model.

  • Deployment scripts that do not pass initializer calldata atomically.

How to test or review it

  • Try initializing the proxy as an unprivileged user after deployment.

  • Try initializing the implementation contract directly.

  • Confirm deployment uses initializer calldata in the proxy constructor or atomic deploy flow.

  • Check every parent initializer and storage gap, then compare the broader upgradeable proxy setup.

  • Test that initialization cannot be repeated.

  • Verify owner, admin, upgrader, and role-admin addresses after deployment.

Sources