Caloogy Article
中文

Upgradeable Contracts and Administrator Private Keys

Date
Sep 9, 2025
Series
Onchain
Reading
4 min
Topics
OnchainSmart contractProxyUpgradeable

The one-sentence version

Once contract code is deployed on the blockchain, it cannot be modified; even if there is a bug, it cannot be fixed. Therefore, many projects use a proxy pattern: users interact with a fixed "proxy contract" address, which then forwards calls to a replaceable "implementation contract." This enables upgrades. The cost is: whoever can upgrade, can take everything. Stolen administrator private keys, incorrect storage layouts during upgrades, and uninitialized implementation contracts have all caused massive losses. Defenses rely on multi-sig, timelocks, and rigorous upgrade audits.

This article has three layers:

  1. Layer 1: The Intuition: Swapping the core without changing the shell
  2. Layer 2: Real-World Use: Parity multi-sig freeze, Audius, and stolen administrator private keys
  3. Layer 3: Principles and engineering key points: How proxies work, storage conflicts, initialization, and upgrade governance

Layer 1: The Intuition

1.1 Swapping the core without changing the shell

Imagine a vending machine where the shell (the address, the money stored inside, and the inventory) remains fixed, but the "brain chip" (the logic code) can be unplugged and replaced with a new one.

1.2 Users are actually trusting the administrator

Many users assume "Smart Contract = Code is Law, no one can change it." But for upgradeable contracts, the reality is "Code is Law, until the administrator decides to change the code." Users are actually trusting the administrator's private key and their integrity.


Layer 2: Real-World Use

Event Description
Parity Multi-sig Wallet (November 2017) Many multi-sig wallets shared a single "library contract" to provide logic. This library contract itself was not initialized; a user called the initialization function and became its owner, then subsequently (allegedly by mistake) called the self-destruct function. All wallets depending on it lost their logic code, resulting in approximately 510,000 ETH being permanently frozen.
Audius (2022) A storage layout conflict occurred between the proxy contract and the implementation contract, causing the "is initialized" flag to be read incorrectly. An attacker was able to re-initialize the governance contract, set themselves as the administrator, and drain approximately $6 million worth of tokens.
Stolen Administrator Private Keys (Commonly seen) The project's deployment private key or administrator private key is stolen, allowing the attacker to directly upgrade the contract to a malicious version or call management functions like "emergency withdraw" to drain funds.

Layer 3: Principles and Engineering

3.1 How proxies work

Calls

delegatecall

Upgraded to

User

Proxy Contract
(Fixed address, stores all data)

Implementation Contract v1
(Code only)

Implementation Contract v2

The key is delegatecall: The proxy borrows the code from the implementation contract but executes it on the proxy's own storage. Therefore, all data is stored in the proxy, so data is not lost when switching implementation contracts. (The danger of delegatecall is discussed in "EOA vs. Smart Contract Wallets".)

3.2 Storage conflicts

Contract state variables are placed in storage slots numbered 0, 1, 2... according to their declaration order. The proxy and the implementation contract share the proxy's storage. If:

Then modifying the total supply will overwrite the administrator address, and vice versa.

Countermeasures:

3.3 Initialization

In the proxy pattern, the implementation contract's constructor does not run on the proxy's storage, so a initialize function is used instead. Common errors:

Error Consequence
Forgot to call initialize after deployment Anyone can call it first and become the owner
initialize can be called multiple times An attacker re-initializes and seizes control
The implementation contract itself is not initialized An attacker initializes the implementation contract directly to cause damage (Parity incident)

Countermeasures: Add a "can only be called once" protection to the initialization function; call _disableInitializers() in the implementation contract's constructor to lock it down; complete deployment and initialization within the same transaction.

3.4 Upgrade governance

Measure Function
Multi-sig Administrator A single stolen private key is insufficient to perform an upgrade (see "EOA vs. Smart Contract Wallets")
Timelock After an upgrade proposal is announced, there must be a waiting period (e.g., 48 hours) before it can be executed. This gives users and security researchers time to audit; those who disagree can withdraw their funds (an on-chain cooling-off period)
Public Upgrade Content The source code of the new implementation contract is verified and made public on the block explorer
Relinquishing Upgrade Rights Once the protocol matures, transfer administrator rights to a governance contract or renounce them entirely, making the contract truly immutable

3.5 How users can judge

Check the contract on a block explorer:

If a contract holding large amounts of user funds has an administrator that is just a regular address and has no timelock, it means a single private key decides the fate of everyone's funds.


Summary

Layer Key points
Intuition Swapping the core without changing the shell; whoever can swap the core can take everything
Principles Proxy uses delegatecall to borrow code but uses its own storage
Pitfalls Storage conflicts (Audius), uninitialized (Parity), stolen administrator private keys
Defense EIP-1967 slots, append-only variables, locked initialization, multi-sig + timelock