AI agent kill switch: what it has to revoke
A kill switch for an AI agent is revocation, not a process stop. It has to refuse the agent's next request, kill the keys, tokens and cards the agent already holds, and keep a record of the refusal. Stopping the process does none of that for a credential that was copied or issued elsewhere.
Stopping the process does not revoke anything
kill -9 on an agent process, or a stopped container, ends that process. It does not touch the credentials the agent was given. An API key copied from its environment still works. A virtual card still authorizes. A token already handed to a sub-agent still passes the check at the other end.
A kill switch that deserves the name does four things:
- Refuses the next request. The checkpoint that accepts the agent's credentials looks at revocation state on every request, not once at login.
- Kills what the agent already holds. Keys, tokens and cards are revoked at the place that honors them, not only at the place that handed them out.
- Works when the network does not. If the kill needs a call to a third party to take effect, whoever can jam that call can keep the agent running.
- Leaves a record. The refusal after the kill is evidence that the kill landed, and when.
Each credential type has its own revoke call, and each has a delay or a limit. The sections below take them in turn, using the providers' own documentation. The four layers that stop a runaway loop are a different question: that entry is about limits that trip by themselves, this one is about the human pressing the button.
Provider API keys can be switched off, for everyone who holds them
Anthropic's Admin API documents an update call for API keys (read 3 November 2026):
POST /v1/organizations/api_keys/{api_key_id}
# body: {"status": "active" | "inactive" | "archived"}
The page lists active, archived and inactive as the settable values, and expired as a fourth status a key can report. The page does not say whether an inactive key can be switched back, so a runbook should not assume it either way.
The limit is structural. A provider key is shared by whatever holds it. If three agents run on one key, switching the key off stops all three. Per-agent keys make the switch narrower, at the cost of managing more keys, and the key still sits in the agent's environment until it is revoked. A key that never leaves a vault is a different design, covered in what proof of possession fixes after a key theft.
OAuth revocation leaves self-contained tokens to the deployment
RFC 7009, OAuth 2.0 Token Revocation (August 2013), defines a revocation endpoint. The client posts the token and an optional token_type_hint. The requirement is asymmetric between the two token types:
Implementations MUST support the revocation of refresh tokens and SHOULD support the revocation of access tokens
Section 3 then describes why access tokens are harder: they "may be self-contained so that a resource server needs no further interaction with an authorization server". For that case the RFC says some "(currently non-standardized) backend interaction between the authorization server and the resource server may be used when immediate access token revocation is desired."
In practice a self-contained access token stays valid until it expires, unless the resource server asks someone whether it is still good. Two consequences follow for agents:
- Short lifetimes are part of the kill switch. A token that lives 30 minutes bounds the damage of a revocation that arrives late.
- The resource server, not the authorization server, is the real checkpoint. Revocation that never reaches it does nothing.
Cards: inactive is a pause, canceled is permanent
Stripe's Issuing API takes a status on the card update call. From the page, read 3 November 2026:
| Status | What Stripe documents |
|---|---|
active | "The card can approve authorizations." |
inactive | "The card will decline authorizations with the card_inactive reason." |
canceled | "The card will decline authorizations with the card_canceled reason. This status is permanent." |
The call is the same POST https://api.stripe.com/v1/issuing/cards/{CARD_ID} shown on the page, with -d status=canceled. Stripe also accepts a cancellation_reason of lost or stolen.
Two decisions sit inside this table. First, whether a kill should pause or end: a permanent cancel cannot be reversed, so a pause is the safer default for an agent you may want back. Second, who holds the Stripe secret key. If the agent's environment can call this endpoint, the agent can also change its own card. The same reasoning is in virtual card limits for an AI agent: the control belongs where the agent cannot edit it.
A published status list is only as fresh as its cache
When many parties need to check one agent's status, a revocation list is the usual answer. The IETF Token Status List draft (version 21, 21 June 2026, submitted to the IESG, not yet an RFC) packs one status per token into a compressed bit array. Section 7.1 defines the status values, including these three (it also reserves application-specific ones):
0x00VALID0x01INVALID: "revoked, annulled, taken back, recalled or cancelled"0x02SUSPENDED: "temporarily invalid, hanging, debarred from privilege"
The draft's own words on freshness matter more than the format. The ttl claim "MUST specify the maximum amount of time, in seconds, that the Status List Token can be cached by a consumer" (section 5.1). Section 8.4 says a list "only conveys information about the state of Referenced Tokens at the time the Status List Token was issued". So the time from a kill to the last relying party seeing it is bounded by the longest ttl any consumer honors. A list with a one-hour ttl is a kill switch with a one-hour tail for every consumer that caches it.
This is the central trade-off. A shared list scales to many checkers and tolerates their downtime, and it is eventually consistent. A check against the revoker's local state on every request is immediate, and it only covers the checkpoints that can see that state. Pick per checkpoint, and state the delay.
Where Mandare fits
Mandare's kill switch is the second kind: local state, read on every request. The commands are in the CLI reference:
mandare kill <agent-did> [--reason <text>]
mandare kill --mandate <id> # the permission slip dies; the agent survives
mandare kill --all # halt the whole door
mandare reinstate <agent-did>
As of v0.1.0 (checked against the public repository at commit 327442e, 3 October 2026), the CLI documentation says the kill is "local, offline, fail-closed": it writes the revocation entry and flips the revocation projection in one transaction, revokes the actor's vault tokens, and revokes bound virtual cards. The gateway reads the revocation state before spend work on every request. The repository's captured demo (docs/demos/S3-dead-paper-demo.txt, cuts marked) shows the sequence, including the refusal landing in the ledger:
$ mandare kill did:mandare:dev-agent
KILLED did:mandare:dev-agent
subject: agent:did:mandare:dev-agent
ledger entry: a9f8582dd52c1821f4018b8439e6e86975c4550731404e66dcef46ab9d47d4b1 (seq 3)
…
vault: 1 live token(s) revoked
…
status: written to the LOCAL ledger — the gateway fails closed on its next request (offline, un-jammable)
[agent] valid signed call AFTER the kill → 403 AGENT_REVOKED
the refusal is ledger entry fc84d99646ba90a5…
…
subjects:
REVOKED agent:did:mandare:dev-agent (index 0, @ 2026-09-27T05:32:01.506Z, entry a9f8582dd52c…)
…The concepts page adds that a dead witness never blocks a kill, and that the same revocation records render into one Token Status List bitstring. Limits, stated next to the claims they limit:
- The doors are the checkpoint. The kill covers traffic through the gateway, the vault and the card rail. A key the agent holds outside them is not revoked by
mandare kill. - The agent process keeps running. A killed agent receives
403 AGENT_REVOKEDon its next call. Mandare does not stop the process. - In passport mode a killed agent still authenticates. The gateway source notes that a kill does not invalidate the agent's key, so the refusal is attributed to a proven identity and recorded.
- Kill is operator access. The OpenClaw integration page says
mandare killsigns with the door's key, so an environment where the kill works can also reinstate. A kill-only path is described there as planned, not shipped. - Cards were tested against a Stripe mock. The live Stripe test-mode run has not happened. The cancel call at Stripe is best-effort: the local revocation declines authorizations without it, and the CLI prints a warning if it fails.
- Status list consumers. The reference witness can serve the list (
--serve-status-list). No third-party verifier has been tested against it, and no interoperability is claimed.
The threat model lists the wider residuals, and there is no external security audit yet. For the design choice behind a kill that refuses when it cannot check, see fail closed or fail open.
Questions
What is the difference between stopping an AI agent and revoking its access?
Stopping ends one process. Revoking ends what the credentials can do, wherever they are used. A stolen or copied key keeps working after the process stops, so a kill switch has to act on the credentials and on the checkpoint that accepts them.
How fast does a revocation take effect?
It depends on who checks and how often. A check against local state on every request takes effect on the next request. A check against a cached status list takes effect when the cache expires: the Token Status List draft makes the publisher state a maximum cache time, in seconds.
Should a kill switch pause an agent or end it permanently?
Both are useful, and some systems separate them. Stripe has an inactive card status and a canceled one, and calls canceled permanent. The Token Status List draft has SUSPENDED and INVALID. Decide in advance which one a kill uses, because a permanent revoke cannot be undone.
Can the agent be allowed to trigger its own kill switch?
Only if you accept that whatever can kill can usually also reinstate. In Mandare's current release the kill signs a ledger entry with the door's key, so an environment that can kill holds operator-level authority. The safer layout keeps the kill with a human or a supervising process.
Sources
- Update API Key (Claude Developer Platform) · Anthropic
- RFC 7009: OAuth 2.0 Token Revocation · IETF · 2013-08
- Update a card (Stripe API reference, Issuing) · Stripe
- draft-ietf-oauth-status-list-21: Token Status List (TSL) · IETF OAuth Working Group · 2026-06-21
Run it yourself: 3 commands, no API keys.
github.com/mandarelabs/mandare →