← Blog
GuideJuly 11, 2026Updated September 7, 20268 min read

How to revoke an AI agent's access instantly

Six ways to cut an agent off on Naïve: interrupt or cancel the session, delete the vault credential, revoke the connection, revoke the API key, deny the tool. Why network-boundary injection makes each one instant.

Dennis Zax· CTO, Naïve

TL;DR

  • Revocation is a ladder, not one switch: stop the session, remove the credential, revoke the connection, revoke the key, or deny the tool. Pick the narrowest rung that ends the risk.
  • Interrupt stops a running turn at its next commit boundary and keeps the session resumable; cancel is terminal and releases the sandbox. Both work mid-action.
  • Credentials live in the vault and are injected at the network boundary, so deleting one removes the secret from the only place it ever existed. The agent held a placeholder the whole time.
  • A connection is revoked with one call; the provider drops the stored token and every later call is refused. An API key revoked with vetta keys revoke fails in-flight requests with 401.
  • A deny policy removes the tool from the model's catalog entirely; a call a policy blocks is written to the audit log as policy.denied.

Revoking an agent's access means every further action is denied, now, without redeploying anything or rotating a key you share with the rest of production. Earlier versions of this guide described one suspend call on a bundled object; that model is gone. An agent on Naïve is a model, a prompt, tools, skills, a budget and a harness; the things it can reach are held separately, in a session, a vault, a connection, an API key and a policy. Each has its own off switch, and the right revocation is usually the narrowest one that ends the risk.

This guide walks the ladder from narrowest to widest, then explains why every rung takes effect immediately. If you need a pause rather than a stop, read how to add human approval to an AI agent instead.

The revocation ladder

TargetWhat it stopsReachReversible
Session (interrupt)The current turnOne runYes, resume or steer
Session (cancel)The whole run, sandbox releasedOne runNo
Vault credentialEvery use of one secretEvery session that referenced itRe-seal a new value
ConnectionEvery call through one third-party accountOne identity's accountReconnect via Connect Link
API keyEvery request that key authenticatesOne organization's keyMint another
Policy (deny)One tool, from the model's catalogNew sessions of the agentEdit the policy

Most incidents need one rung. A runaway loop is a session problem. A leaked token is a vault or key problem. A departing customer is a connection problem. Reaching for the widest cut first turns one misbehaving run into an outage for every agent in the organization.

Stop the run: interrupt, steer, cancel

A session is one metered, resumable run of an agent. Three operations control it, documented under session operations.

Interrupt stops the current turn at the next commit boundary. You lose at most one turn, never the run. The session lands at idle with stop_reason: "interrupted", its history and sandbox preserved, and the interruption is written to the audit log as session.interrupted.

Interrupt a running session
vetta session interrupt --session $SID

Steer is an interrupt and a new message in one call. The agent wraps up the current turn cleanly and then follows the redirect: the right move when the agent is doing the wrong thing rather than an unauthorized thing.

Interrupt and redirect atomically
vetta session send --session $SID --interrupt --message "Stop. Issue a store credit instead."

Cancel is the terminal operation. The in-flight turn stops, the sandbox is released, and the session moves to cancelled. The record and its events are permanent; files the session produced go with the sandbox, while anything promoted with publish_file or uploaded to the Files API survives. There is no archive and no delete route; cancel is the only terminal operation.

Cancel from the SDK
import { randomUUID } from "node:crypto";
import { createClient } from "@usenaive-sdk/vetta";
 
const client = createClient({
  baseUrl: "https://api.vetta.sh",
  apiKey: process.env.VETTA_API_KEY!,
  fetch: globalThis.fetch,
  idempotencyKey: () => randomUUID(),
});
 
await client.sessions.interrupt(sessionId);          // stop the turn, keep the run
await client.sessions.cancel(sessionId);             // terminal

A session stop does not touch the credentials the agent was using. If a secret may be compromised, keep climbing.

Cut the credential: the vault

The vault is where an agent's secrets live, and its defining property is that the agent never sees them. A credential is sealed once and referenced by ID. Reads return metadata only; there is no reveal route and the schema has no value field. The design is in introducing Vault.

Revoking a secret is therefore a delete. List the vault's credentials to find the ID, then remove it:

Delete one credential
vetta vault credentials --vault vlt_...
vetta vault rm --vault vlt_... --credential vcr_...

There is no update command on purpose. Rotation is set a new credential, then rm the old one, so last_injected_at stays attributable to exactly one secret. During an incident, "when was this value last used?" is the first question, and an in-place update would make it unanswerable.

Rotate a credential
printf '%s' "$NEW_KEY" | vetta vault set --vault vlt_... --env PAYMENTS_API_KEY --host api.payments.example.com
vetta vault rm --vault vlt_... --credential vcr_old...

If the whole vault has to go, vetta vault delete <vault-id> soft-deletes the container and destroys its secrets for good. In the SDK: client.vaults.credentials.delete(vaultId, credentialId) and client.vaults.delete(id); see the vaults reference.

Cut one MCP integration

MCP servers are declared on the agent by name and URL, and their auth is never on the agent definition. A static_bearer or mcp_oauth credential in the vault is matched to the server by URL and injected server-side when the agent connects. The sandbox never receives the token, which is why there is no separately revocable "MCP session" any more: there is no token in the agent's hands to revoke.

To cut one integration without touching the rest, delete that server's vault credential. An auth failure surfaces as a session.error event naming the server; the agent's other tools keep working. Or remove the tools themselves in the agent's tool configs, where every MCP tool is keyed <server>.<tool> and can be set to enabled: false or permission: "deny". The default permission for MCP tools is ask, so a newly exposed server tool never auto-runs. See the MCP connector docs.

Naïve also publishes its own API as an MCP tool catalog at POST /v1/mcp. Every tool call is re-dispatched as an ordinary API call carrying the caller's own bearer, so a tool can never reach further than the key that invoked it, and revoking that key revokes that client. Routes that mint or accept secrets are withheld from the catalog entirely. See the MCP server reference.

Revoke a connection

A connection is an authorized account in a third-party app, bound to one identity. The agent never handles the raw credential; we store it, inject it at call time, and refresh managed OAuth tokens server-side.

Revoking it is one call, client.connections.disconnect(id) in the SDK. The provider drops the stored credential, the account moves to disconnected, and every later call through it is refused.

Disconnect one account
vetta identity disconnect --connection ca_...

Two related cuts: deleting the org-level auth config means connections already minted against it stop refreshing. And vetta identity detach revokes an agent's grant to a persona: the identity is untouched and running sessions are not interrupted, but the next session cannot select it. The full route list is in the connections API.

Revoke or rotate an API key

Keys are organization-scoped and carry explicit scopes, so a CI key or a sandbox credential need not be an admin key. Revocation is immediate: in-flight requests holding the old secret start failing with 401. Rotation mints a replacement secret under the same ID and invalidates the old one.

Revoke or rotate a key
vetta keys revoke key_...
vetta keys rotate key_...

In the SDK these are client.keys.revoke(id) and client.keys.rotate(id); only rotate answers a new secret, once. Both land in the audit log as api_key.revoked and api_key.rotated. vetta keys list shows last_used_at, which makes stale keys easy to find before they become the incident. Reference: vetta keys and authentication.

Deny at the policy layer

Every capability an agent has flows through one place, the tool call, and policies are checked there before a tool runs. Each tool resolves to allow, ask, or deny. A deny means the tool is not offered to the model at all. Connections run under the same filter: connections.mode: "allowlist" keeps a new connector type unreachable until you add it, and an attempt outside the list is refused with a typed forbidden error before any external request is made.

Ship a tighter policy as a new agent version
vetta agent update ops --file ops.json

The thing to know about policy as a revocation tool is versioning. An update mints a new immutable agent version, and every session pins the version it started on. A deny protects every session created from then on, but it does not reach into a run already going. For that, interrupt or cancel first, then let the next session pick up the new version.

Why the boundary makes revocation instant

Every rung above takes effect immediately for one structural reason: the agent never held the thing you are revoking.

A vault value is substituted outside the sandbox, at the network boundary, and only when the request is bound for the credential's destination. Inside the sandbox, in the model's context, in the transcript and in your logs, there is only a placeholder. Delete the credential and the placeholder is inert; there is no cached copy to expire because there was never a copy. The same holds for a connection token, injected at call time, and for MCP auth, injected server-side at connect. Revocation never chases a secret through the agent's memory; it changes one row in a store the agent cannot read.

Policy works the same way. Enforcement is at the tool-call boundary rather than inside a prompt, so a policy holds regardless of what the model decides to attempt. The env_var kind extends the boundary rule to general sandbox egress, substituting only for the bound host, so a prompt-injected agent that sends the placeholder elsewhere sends the placeholder, not the secret. That kind is coming soon and refused today.

Verify the cut

  • After an interrupt, vetta session get $SID shows idle and stop_reason: "interrupted". After a cancel, cancelled.
  • After a credential delete, vetta vault credentials --vault vlt_... no longer lists it.
  • After a disconnect, vetta identity connections show ca_... reads disconnected; that read reconciles against the provider.
  • After a key revoke, any request with the old secret is 401, and GET /v1/audit_logs carries api_key.revoked with the acting principal.
  • After a policy change, a new session of the agent does not see the denied tool, and any blocked call is recorded as policy.denied.

Wire it in before you need it

Revocation under pressure is only reliable if the one-liner already exists. Put the right rung in the right place: a session cancel behind the stop button in your admin UI, a connection disconnect in your offboarding flow, a vault rotation on a schedule, a key revoke in your incident runbook. Each is one command or one SDK call, scoped to exactly what needs to stop.

FAQ

How do I stop a running AI agent immediately?
Interrupt or cancel its session. vetta session interrupt stops the current turn at the next commit boundary and leaves the session idle with stop_reason interrupted, so you can resume or steer it. vetta session cancel is terminal: the in-flight turn stops, the sandbox is released, and the session moves to cancelled. The record and event history are kept either way.
Do I have to rotate my API key to revoke one agent?
No. Keys are one rung on the ladder, not the only one. Cancel the session, delete the vault credential, or revoke the connection the agent was acting through. Rotate or revoke a key when the key itself may have leaked; revoking one key never affects another organization, and in-flight requests holding the old secret start failing with 401.
Can an agent copy a secret before I revoke it?
Not from the vault. Credential values are write-only and never returned by any route; the agent, the transcript, and your logs only ever see an opaque placeholder. The real value is substituted outside the sandbox at the network boundary, so once you delete the credential there is nothing left for the agent to have kept.
Does a deny policy stop a session that is already running?
A policy change mints a new agent version, and every session pins the version it was created with. Sessions created from then on never see the tool. For a session already running, interrupt or cancel it first, then let the next session pick up the new version.
What is the narrowest way to revoke one MCP integration?
Delete the vault credential matched to that server URL, or disable the server's tools in the agent's tool configs. The agent's other tools keep working. If the MCP client is something operating your Naïve account through POST /v1/mcp, revoke the API key it authenticates with; every tool call carries that key and can never reach further than it.