Why an AI agent should never hold a private key
A key grants unlimited authority, and every limit on top is software. A permission can be withdrawn, but a copied key cannot be un-copied.
In short: You are wondering if it is safe to give an AI agent its own private key. A key lets whoever holds it sign anything, for any amount, to any address, and a leaked copy stays usable by everyone who has it, so any rules on top are only software. The safer design gives the agent no key. It is a contract your account gives permission to act, and you can remove it with one transaction from your own wallet, though we have proven four attacks against our own guard.
The fastest way to build an agentic wallet is to generate a private key, hand it to the agent, and write some rules about what it may do with it. Almost every early build works this way, and the industry is now arguing its way out of it. Coinbase has made the case publicly, and the reasoning fits in a sentence.
A private key is all the permission there is, so everything you layer on top of it is only a request.
What a key grants
Spend up to 500 USDC a month. Only these three protocols. Never send to an address not on the list.
Sign any transaction this account can make, for any amount, to any address, on any chain, for ever.
The left column is enforced by whatever code happens to be running between the agent and the chain. The right column is enforced by mathematics. When those two disagree (because of a bug, a compromise, a persuaded model, or a process that was restarted with the wrong config), the right column wins every time.
The asymmetry nobody plans for
You cannot un-copy a key, and that changes the architecture, not just the configuration.
If a key leaks (through a log line, a memory dump, a compromised dependency, a backup that was not supposed to exist), everyone who has a copy has full authority, permanently, and you cannot tell how many copies there are. Rotating means moving every asset to a new address, which is itself a set of transactions you now have to trust.
A permission given to a contract works the other way. It lives on the chain, it is checked on every call, and it can be withdrawn in one transaction that needs nobody’s cooperation.
- How many copies exist
- Key: unknowable. Permission: not a thing that can be copied
- How you stop it
- Key: move every asset. Permission: one transaction from your own wallet
- How fast it takes effect
- Key: once the last asset has moved. Permission: at the next call
- Whose help you need
- Key: enough gas on every chain, and time. Permission: nobody’s
- If the operator is hostile
- Key: they may already have a copy. Permission: they cannot grant themselves one
What replaces the key
Three answers are in circulation, and they are not equivalent.
- Split the key (MPC or multisig)
No single party can sign alone, and a policy engine decides what gets co-signed. This is the dominant commercial answer and it is a real improvement: there is no longer one object whose theft ends the story.
It does not change what the agent can express. The thing being co-signed can still be any transaction, so the policy engine is still a filter deciding whether a destination address is acceptable.
- Keep the key away from the model
Put the signing key in hardware or a separate service the model cannot read, and let the model only request signatures. That is better again, because a persuaded model can no longer exfiltrate the key.
But a persuaded model can still ask for the wrong thing, and something still has to judge the request.
- Give the agent no key and no way to write an address
The agent is a contract your account gives permission to. It picks an operation from a fixed set and fills in its details, and it can’t set a destination or a payload. Destinations are always your own account, looked up when the step runs.
A persuaded model cannot express “send it to me”, so nothing has to detect that it tried.
What we hold
It helps to be concrete here, because “the agent is a contract” invites the question of what is left on our side.
- The agent
- A contract. Your account gives it permission. A plain key cannot be given that permission at all
- The keeper
- A key we hold. The only thing it can do is tell that contract to make one call
- The fee payer
- Pays gas. Holds no assets, has no standing permission to spend anywhere
A stolen keeper key cannot take your account. The contract refuses on the chain, before the call happens: it will not target your account directly, will not run the instructions that install permissions or change ownership, and will not touch an operation you never switched on. It is also bounded by caps set on your account that nothing on our side can raise.
The one-way door
One more property is the other half of “a permission can be withdrawn”.
Your account can never be re-pointed at a different agent. The first agent you approve is the only one, and the only permitted change is to no agent at all.
An account whose agent can be swapped has a role in it: whoever can perform the swap. That role is a target, which is why it must not exist.
This is a real constraint on us, and not one we enjoy. It means we cannot patch a deployed agent underneath you: a new agent is something you move to deliberately, with a new account. That is slower for us, and it is meant to be.
How to evaluate any of this
You do not need to trust a security page. Ask what the agent can write down.
If the answer contains an address, every control that vendor lists is a filter standing between a persuadable model and your money. Filters are judged against the attacks somebody already thought of. If the answer does not contain an address, ask where the spending cap is enforced and whether you can leave with their servers switched off.
Those two questions separate the designs faster than any amount of documentation.