BLOG
September 03, 2026blockchainenterprise3 min readITENHR

Immutable, until you ship a bug

A deployed contract can't be patched, so teams add a proxy and an upgrade key. That key — not the audited logic — becomes the thing worth protecting.

Immutability is the first thing anyone tells you about smart contracts, and it's true: once a contract is deployed, its bytecode can't be changed. It gets sold as a guarantee — nobody can move the goalposts after the fact, not the team, not the founder, not a future acquirer. Then you ship your first real bug, and the guarantee turns into a trap. You can't patch what you can't change. What teams reach for next is well understood and perfectly reasonable, but it quietly undoes the exact property they were selling — and most pitches never say so out loud.

The proxy, and the key it introduces

The standard fix is the proxy pattern. You split the contract in two. A proxy contract holds the state and the address everyone interacts with, and it forwards every call, via delegatecall, into a separate logic contract that holds the code. When you need to fix a bug, you deploy a new logic contract — v2 — and point the proxy at it. The address users trust never changes; the behaviour behind it does.

It's elegant, and it works. It also creates something that didn't exist a moment ago: an administrative key that can decide which logic the proxy runs. Whoever controls that key can change what the contract does, after people have already started trusting it. The trust anchor has quietly moved. It used to be "the bytecode can't change." Now it's "whoever holds the upgrade key won't misuse it."

The key matters more than the audited logic

This is the part that gets lost. You paid for an audit, and the audit certified the logic contract — its arithmetic, its access checks, its handling of edge cases. But the address that can replace that logic sits outside the audit's guarantee. A clean report on v1 says nothing about who can swap in v3 at two in the morning.

If that upgrade key is a single externally owned account — one private key on one laptop — then "immutable and trustless" is marketing copy. You've rebuilt a database administrator with write access to production, just with extra steps and a gas bill. An attacker who phishes that key doesn't need a reentrancy bug or a rounding error. They don't attack the logic at all. They just upgrade it to something that drains the contract, and every guarantee you sold evaporates in one transaction. Your security model has to include the key, not only the code.

The honest design question

So the real question was never "upgradeable or not." Non-upgradeable contracts are a legitimate choice, but only if you can live with a bug being permanent. The question is who can upgrade, and what stands between that person and a silent swap.

Three controls do most of the work. A multisig, so an upgrade needs several independent signatures instead of one person's key. A timelock, so a queued upgrade sits in public view on chain for a fixed delay before it can take effect — long enough that anyone watching can react. And a plain-language disclosure of the mechanism, so a counterparty knows what they're trusting before they commit funds. Immutability you can't fix is a liability. Upgradeability nobody can see coming is worse. The mature position is to pick one deliberately and publish how it works.

If your contract needed an emergency fix tomorrow, who could deploy it — and would anyone see it coming before it went live?