DEV Community

Cover image for What I learned trying to revoke an AI agent mid-task
Aneesh Gupta
Aneesh Gupta

Posted on

What I learned trying to revoke an AI agent mid-task

An agent is running, making tool calls, and something's wrong — bad prompt, gone off the rails. You need to stop just that one. Right now.

What do you do? Rotate the API key? It's shared, so you break every other agent. Kill the process? You lose its state and still don't know what it already did. Neither is "revoke this agent" — they're "blow something up and hope."

I went looking for the real version, found mostly duct tape, and built it. Four things got clear:

1. Identity and credentials shouldn't be the same thing. When your agent is its API key, that key is its identity, credential, and permissions all at once — so revoking means rotating and scoping means hoping the prompt holds. Split them: the agent has an identity, its authority is a separate signed grant, and the real secret is custodied elsewhere and injected at use. Now revoking is "invalidate one grant" and everything else keeps running.

2. Revocation has to hit the next action, not the next token refresh. If it "expires in 15 min," the agent keeps working for 15 minutes after you said stop. The only instant kill I found is putting the check in the action's path — for MCP, a proxy in front of the tool server:

chancery mcp wrap --agent deploy-bot --writ <id> -- npx some-mcp-server
Enter fullscreen mode Exit fullscreen mode

Every call passes through it. Revoke → next call denied, mid-session, no restart. A prompt-injected agent still has to go through the proxy, so it can't skip the check — which a client-side "please check permissions" library can't promise.

3. Delegation should only ever narrow. Orchestrators that spawn workers usually hand each one full credentials — now you've got five copies of god-mode. Make delegation structurally attenuating: a worker's grant is a child of the parent's, and the format has no field for widening. A sub-agent can't out-scope its parent, and revoking the parent kills the subtree. You don't trust the logic; the structure can't represent the unsafe case.

4. The audit log has to be the enforcement path. A log the agent writes after acting is worthless the moment it's compromised — that's when it lies. But if every action already flows through a choke point for the permission check, that's where you record it: which agent, which version, under whose authority. The log becomes a byproduct of enforcement, not a favor the agent does you.


I built these into Chancery — self-hosted, single Go binary, Apache-2.0, pre-alpha (gaps written up honestly). The four ideas hold no matter what you build with. Solved any of them cleaner? I'd genuinely like to hear it: https://github.com/chanceryhq/chancery

Top comments (0)