On this page
On Ethereum, an upgradeable contract is an architectural choice. You write a proxy, you route through delegatecall, you fight storage layout for the life of the project, and auditors treat the upgrade path as an attack surface because it is one.
On Solana, upgradeability is the default. A program deployed through the standard loader is upgradeable unless someone explicitly made it not so, and the mechanism is not in your code at all. It is in the loader, and it is controlled by one key: the upgrade authority. Whoever holds that key can replace every byte of the program’s executable in a single transaction, with no timelock, no governance vote and no notification to users beyond the transaction itself.
This is well understood by Solana developers and almost invisible to everyone else, including many of the people who integrate with a program, hold its tokens, or audit it. So it is worth laying out plainly.
Where the program actually is
A program deployed through the upgradeable loader is two accounts, not one.
The program account is the address everyone uses. It is small and it is, in effect, a pointer: it says “my executable lives at this other address”. The program data account is where the bytecode is, and it carries two more things: the slot at which it was last deployed, and the upgrade authority, an optional public key.
An upgrade is an instruction to the loader that says: here is a buffer account I have filled with new bytecode; copy it into the program data account. The loader checks exactly one thing about permission: that the transaction was signed by the key currently recorded as the upgrade authority. That is the whole access control.
The program account does not change address on upgrade. Every PDA derived from it stays valid, every client keeps working, and every integration that trusted the program’s behaviour yesterday is now trusting whatever the authority deployed today.
Reading the authority
Anyone can read it. The program data account is a normal account; decoding it gives the deployment slot and the authority. Explorers show it as “Upgrade Authority” on the program page. From the command line, solana program show <PROGRAM_ID> prints it along with the program data address and the last deployed slot.
The four things to look at are what the authority is:
- A single hot key. The authority is an ordinary keypair, held by a developer. This is the state every program starts in, and for anything holding user funds it is the state that should end at launch. One compromised laptop is a total compromise of the program.
- A multisig. The authority is a PDA of a multisig program (Squads is the common one), so an upgrade needs several signers. Better. Note who the signers are and how many are required; a 1-of-3 multisig is a hot key with extra steps.
- A governance program with a timelock. The authority is held by an on-chain governance program that queues upgrades before executing them. This is the first state in which users can see an upgrade coming and exit before it lands, and it is the one that makes “the code is what you audited” a checkable claim.
- None. The authority has been set to
None, and the program is immutable. Nobody can upgrade it, including its authors, ever. This is the strongest guarantee available, and it is a one-way door: the only way to ship a fix is to deploy a new program and migrate.
A program’s page should say which of the four it is in. If a project’s documentation does not, the on-chain data does.
What can go wrong at each state
Hot key. The obvious risk is key theft, but the quieter one is key loss: a program whose authority keypair is gone is immutable by accident, with whatever bugs it had at the time. Both have happened. If the authority is a hot key, the questions are where it is stored, who has access, and what the plan is when either answer changes.
Multisig. The risks move to the signer set. Are the signers distinct people? Distinct devices? Are any of them the same key that holds the treasury? A multisig where two of three signers sit on one person’s machine is a hot key that costs more to use. There is also the question of what the multisig program itself is: it is a program, with its own upgrade authority, and the chain of trust runs through it.
Governance and timelock. The risk is that the delay is decorative. A timelock that governance can shorten with the same vote that queues the upgrade is not a timelock. Read the governance program’s rules, not its description. And note who can cancel a queued upgrade; a guardian role that can veto is a feature until it is the only remaining hot key.
Immutable. The risk is the one everyone thinks of last: the program cannot be patched. A critical bug in an immutable program is a critical bug forever, and the response has to be at the integration layer: front-ends stop routing to it, other programs stop calling it, and funds are migrated by users one at a time. Immutability is right for a small, finished program, and it is right for a large one only once the team is genuinely done with it.
The upgrade itself
Whatever the authority, an upgrade is a transaction, and transactions can be watched. The loader’s upgrade instruction has a fixed shape: it names the program, the program data account, the buffer, and the authority. A monitor that watches for that instruction against a program you depend on will see the upgrade in the same slot it lands.
Two things are worth checking after any upgrade, whether it is your program or one you depend on. First, that the new executable matches a build you can reproduce. Solana’s verifiable-build tooling hashes a deterministic build and compares it to the on-chain bytes; a program whose upgrades cannot be verified is a program whose source is decoration. Second, that the behaviour is what the release notes claim. A decompiler diff of the previous and current program data, at the level of recovered instructions and account constraints, will show whether an upgrade described as “fee tweak” also changed who can withdraw. The upgrade diff view in Sigvex does that comparison for two deployed versions, and the interesting rows are always the ones the changelog did not mention.
A short checklist
For a program you are shipping:
- Decide the end state before launch. For anything holding funds, a hot key is not an end state.
- Move the authority to its end state as a deliberate, announced step, and make the transaction easy to find.
- If you keep upgradeability, keep a timelock, and make the delay long enough that a user who checks once a day would see it.
- Publish verifiable builds so anyone can confirm the on-chain program is the audited one.
For a program you depend on:
- Read the authority off-chain and write down which of the four states it is in.
- If it is a hot key or a small multisig, treat the program as “can change without notice” in your risk model, because it can.
- Watch for the upgrade instruction. It is the single most important event that can happen to a dependency, and it is public.