Skip to content

The Kill Switch Nobody Built: Stopping an AI Agent Mid-Incident

8 min read Fullmakt Team

  • governance
  • agents
  • agentic-actions
  • traceability
  • observability
  • credentials
  • authentication

Every post in this series has covered a way an AI agent’s login handshake, its tool description, or its delegation chain can go wrong before or during a call. This one covers what happens after you’ve already noticed — the five minutes between “this agent is doing something it shouldn’t” and actually making it stop.

The failure: revocation exists, but not in time to matter

Most teams that have thought about agent governance at all have some answer to “how do we cut this agent off.” Usually it’s one of: rotate the API key, disable the OAuth client, delete the service account, or redeploy without the agent’s container. Each of those works, eventually. None of them works in the window that actually matters.

An OAuth access token already in an agent’s hands stays valid until it expires, regardless of what you do to the client that issued it — rotating a client secret stops the next token mint, not the token already circulating. A refresh token sitting in an agent’s memory can mint a fresh access token faster than a human can find the right dashboard to revoke it. Deleting a service account is authoritative but slow — it has to propagate through whatever caches sit between your identity provider and the resource server, and an agent mid-loop doesn’t wait for cache invalidation before firing its next call. By the time any of these standard levers take effect, an agent that’s already off the rails has usually finished doing whatever it was going to do.

This is a different failure from the ones we’ve written about before. It isn’t a spoofed Agent Card, a poisoned tool description, or a confused deputy using a valid token for the wrong purpose. It’s an agent that was legitimately authorized, doing something legitimately requested, that started producing the wrong outcome — a loop that re-sends the same customer email on every retry, a coding agent that keeps modifying files outside the directory it was scoped to, a provisioning agent that misreads a config and spins up ten times the infrastructure it should. Nobody spoofed anything. The handshake was fine. What’s missing is a lever, and someone watching closely enough to pull it in time.

Why “just revoke the token” isn’t the same as a kill switch

A kill switch has three properties that ordinary revocation usually doesn’t:

  • It has to work while the agent is mid-call, not just before the next one. Most credential lifecycles assume revocation matters at the start of a session — the next login handshake fails, and that’s treated as good enough. An agent already inside a multi-step task, or one that holds a credential with hours of nominal lifetime left, keeps acting until that assumption catches up with reality.
  • It has to be scoped to exactly the thing going wrong, not everything the agent might ever do. Killing an agent’s entire access because one action loop misbehaved is a blunt instrument that either takes down workflows that were fine, or gets skipped because an operator doesn’t want that blast radius — and an unused kill switch is the same as no kill switch.
  • It has to be fast enough that a human deciding to pull it is the bottleneck, not the infrastructure. If stopping an agent means finding the right IAM console, the right service, and the right button across three systems, the agent finishes its loop before the third tab loads.

None of these are properties you get by having a revocation mechanism somewhere. They’re properties of where that mechanism sits relative to every call the agent makes.

Why observability has to come first — you can’t pull a switch you can’t see

A kill switch is only as useful as the traceability that tells someone to reach for it. An agent’s tenth duplicate email or hundredth unauthorized file write is only obviously wrong in aggregate — a single call in isolation can look completely legitimate, the same shape as the ninety-nine before it that were fine. This is the same gap covered in our post on the observability trap: watching an agent and being able to act on what you see are two different capabilities, and a lot of stacks have built the first without the second. An audit log that shows what happened an hour after it happened is a good postmortem tool and a useless kill switch trigger — by the time the pattern is visible in a batch export, the incident is already the six-o’clock retro, not the thing you stopped at 9:14 a.m.

Where the fix actually has to live

  • The kill switch has to sit in front of every call, not attached to the credential’s issuance. Revoking at issuance (rotate the key, disable the client) stops future minting. Revoking at the call path stops the call that was about to happen, including ones made with a credential minted five minutes ago and technically still valid everywhere else.
  • It has to be addressable at the level an incident actually happens at — this agent, this workspace, this action class — not only “all access for this identity.” An operator who can only choose between “let it keep running” and “shut off everything this agent has ever touched” will hesitate exactly when hesitation is most expensive.
  • Real-time policy evaluation, not cached authorization. If “is this call still allowed” is answered from a token’s claims at mint time instead of checked against current policy on every call, a kill switch flipped centrally never reaches the agent until that token happens to expire on its own.
  • The trigger has to be cheap to pull. A kill switch behind an approval workflow, a ticket, or a paged on-call engineer who has to find the right runbook is a kill switch that gets pulled too late, or not at all, in exactly the incidents it exists for.

The business case: a broker is the only place this can actually sit

Fullmakt sits as the broker between every agent and every credentialed call — which is the same property that makes an offboarding revocation instant, and it’s what makes a live kill switch possible instead of theoretical:

  • Every call, from every agent, passes through the same policy evaluation — so pausing or killing access takes effect on the very next call, not on the next token refresh, because Fullmakt isn’t reading a cached claim, it’s evaluating current policy against the request in front of it.
  • The kill switch is scoped to whatever the incident is scoped to — one agent, one workspace, one action class, one credential — because policy is evaluated per call against the same structure that already enforces scoped credentials day to day. Nothing about pulling it requires touching the identity provider, the service account, or any other agent sharing the workspace.
  • The same tamper-evident audit trail that gives you traceability after an incident is what surfaces the pattern that should trigger the kill switch in the first place — a loop of near-identical calls, a spike in a specific action class, a single agent suddenly touching data it’s never touched before are all visible from the same call-level record, in something closer to real time than an hourly log export.
  • Because the broker — not the agent, not the individual tool — is what’s actually making every call happen, “stop this agent” is a policy change at one chokepoint, not a checklist across every API key, OAuth client, and service account the agent happens to hold.

The commercial logic is the same one behind every post in this series: a control that has to be enforced consistently, under time pressure, across every tool and protocol an agent might use, is only reliable when it lives at the one place every call already passes through — not re-implemented, or forgotten, inside each individual credential’s own revocation path.

FAQ

Isn’t revoking the API key or OAuth client good enough? It’s necessary, but it’s not fast. It stops future token issuance, not a token the agent is already holding, and propagation through caches and service restarts can take longer than the incident does.

How is this different from agent offboarding? Offboarding is planned — an agent’s task ended, its role changed, and access is cleaned up on a known schedule. A kill switch is unplanned — an agent is still actively misbehaving right now, and the response has to be faster and more precisely scoped than a routine offboarding process is built for.

Doesn’t a human reviewing every action already prevent this? Human-in-the-loop approval helps for the actions it covers, but agentic AI increasingly exists specifically to act autonomously between review points — the whole failure mode described here is a loop of individually plausible actions between the approvals a human actually sees.

What should trigger a kill switch, concretely? Anything a policy can express as unusual for that agent, workspace, or action class — call-volume spikes, repeated near-identical payloads, access to a resource class the agent has never touched, or a manual operator decision after reading the audit trail. The trigger matters less than whether pulling it actually stops the next call.

Does this replace the need for good tool scoping and login handshakes? No — it’s the layer underneath them, for when a well-scoped, well -authenticated agent still produces the wrong outcome. Scoping limits the damage an agent can do; a kill switch limits how long it keeps doing it once you’ve noticed.

A login handshake answers “can this agent start acting.” It has nothing to say about “can we make it stop” once it’s three hundred calls into a loop nobody meant to authorize. That answer has to be built in before the incident, at the one point every call already passes through — because by the time you’re looking for it, the agent isn’t waiting for you to find it.