Your wallet simulates every transaction before you sign. It shows the SOL going out, the tokens coming in, the accounts touched. You have been told, correctly, to read that preview and refuse anything that drains you.
There is an instruction that drains you and shows nothing. No balance changes. No tokens move. The preview reads “no balance change”, you sign, and from that moment your account belongs to someone else’s program. In December 2025 SlowMist reported a case in which one signature with no visible balance change replaced a victim’s owner permission: more than $3 million was drained, and about $2 million held inside a DeFi position was later recovered with that protocol’s help.
The instruction is Assign, in the System program. Here is what it does, why simulators are blind to it, and the one check that catches it.
Every Solana account has an owner, and the owner is the only writer
An account on Solana is a balance, some data, and an owner — the program allowed to modify the data and debit the balance. Your wallet’s main account is owned by the System program, which is why the System program’s Transfer instruction can move your SOL when you sign. A token account is owned by the token program; a stake account by the stake program.
The rule the runtime enforces is strict: only the owning program can change an account’s data or reduce its lamports. Any other program may read it and may add lamports to it, nothing more.
Assign changes the owner. It is a legitimate instruction — every program-derived account starts life as a System account and is assigned to its program — and it requires the account’s signature. Your signature. Which is exactly what a phishing transaction asks for.
Why the preview says “no balance change”
Wallet simulators run the transaction and diff the result: lamports before and after, token balances before and after. Assign changes neither. The account holds the same SOL after the instruction as before. The diff is empty, and the preview says so, in the reassuring green that every simulator uses for a transaction that costs you nothing.
The preview is not lying. It is answering the wrong question. “Did my balance change” is the question for a transfer. The question for Assign is “can I still move this balance”, and no simulator asks it, because the answer is not a balance.
Worth knowing: an Assign that sets the owner to the owner the account already has is a no-op the program accepts without even checking for a signature. A transaction that includes one is odd, but harmless. The dangerous one names a program you do not control.
What you can and cannot do afterwards
After the reassignment, the account’s SOL is still there and still yours in every sense except the one that matters.
You cannot transfer it. The System program’s Transfer requires the source to be a System-owned account, and will also refuse any account that carries data. Your account now has a different owner, and whichever program that is decides what happens to the lamports.
You cannot reassign it back. Assign requires the current owner program’s cooperation, and the attacker’s program will not give it.
You cannot close it, or recover its rent, or use it as a fee payer in any transaction that touches its balance.
The attacker’s program, meanwhile, can debit the account at will, which is how the SOL leaves. Tokens held in your wallet’s token accounts are a separate matter: those accounts are owned by the token program, and Assign on your main account does not touch them. But the same phishing transaction routinely includes a token SetAuthority on each of them, changing the authority to the attacker — a different instruction, the same empty preview.
The one check
Read the owner. getAccountInfo returns it for any address. For a wallet’s main account it must be the System program, 11111111111111111111111111111111. For a token account it must be the token program, and the authority recorded inside the account’s data must be your wallet.
If either has changed, the account is no longer yours to operate, and no amount of revoking or re-signing fixes it. Move what can still be moved — tokens in accounts whose authority is still you, SOL in accounts still owned by the System program — and treat the reassigned account as gone.
Before you sign, the check is different: read the instruction list, not the balance diff. An Assign naming an unfamiliar program, or a SetAuthority on any of your token accounts, is a refusal regardless of what the preview says. Most wallets now flag these; the campaign in January is why.
What this post cannot offer
A fix. There is none. A reassigned account cannot be reclaimed by its former owner, and any page that offers to “recover” such an account is either describing something else or is the next scam. What exists is prevention — read the instructions, not the diff — and limitation: keep the balance you cannot afford to lose in an account you do not sign transactions from.
The sibling hazard is the pre-signed transaction that never expires, which is a different mechanism with the same lesson: the decisive moment is signing, and the simulator is not the judge.
Owner Reassignment: Questions People Actually Ask
What does the System program’s Assign instruction do?
It changes an account’s owner to another program. Only the owning program can modify an account’s data or reduce its balance, so after an Assign the previous owner cannot move the SOL in it.
Why did my wallet’s simulation show no balance change?
Because Assign does not move lamports or tokens. Simulators diff balances, and the diff is empty. The harm is a change of control, which a balance diff cannot show.
Can I get a reassigned Solana account back?
No. Reassigning requires the current owner program’s cooperation. Move anything that is still under your control and treat the reassigned account as lost.
How do I check whether my accounts are still mine?
Call getAccountInfo and read the owner. A wallet’s main account must be owned by the System program; a token account by the token program, with your wallet as the authority inside its data.
Two rules
A preview that shows no balance change is not a preview that shows no harm. Read the instructions.
Check your accounts’ owners today. It is one RPC call per account, the answer is a program id, and for a wallet it must be the System program. If it is anything else, the account is not yours any more, and the time to find out is before you need it.
Its closest relative is a signed transaction that never expires, and its counterpart on the token side is a honeypot that passes your simulation.
Constants read from the Agave validator source at commit beee69b958: programs/system/src/system_processor.rs and the transaction-context crate.