Stopping a rogue AI agent: kill switches, token revocation and what OAuth can't do yet
Part 2 of our AI agent governance series. Switching off an agent's login doesn't always stop the agent, so we cover the kill switch step by step, what OAuth can say about an agent acting alone, trust signals after sign-in, telemetry that joins up, orphaned credentials and policy enforced at the gateway.
part 6 of 6 · Identity security, from the ground upthe ideaStop the calls first, then the tokens, then the keys. Order matters.
after reading, you can- Explain why a disabled agent keeps working
- Set up tokens that name who may act, where and for which task, so a stolen one is worth less
- Spot credentials that outlived their project, and the keys your logs need to join up
Most companies can switch off an AI agent's login. Ask how long the agent keeps working afterwards and you'll usually get a shrug. Drill your kill switch, put your rules in the request path and get your logs joining up before an incident makes you. This is part 2 of our agent governance series, and it picks up once the agent is running.
Switching off an agent's login doesn't always stop it straight away. Its tokens can keep working for a while
An AI agent works with tokens. They're short-lived passes that let it call an app or a tool without signing in each time. Disable the agent and your identity provider stops handing out new ones. The ones it already holds can keep working until they expire, unless the app checks back. That's the gap this post is about. You want to be able to stop the agent everywhere, know what each pass allows, see what the agent does after sign-in, and have your rules run in the request path instead of sitting in a policy document.
Think of a hotel key card. Deactivate a guest at the front desk and they can't get a new card. The card in their pocket still opens the door until it expires, unless each lock checks with the desk. Most agent tokens work like that card.
- CISOs who own the incident plan
- Identity and IAM teams
- Platform teams running MCP or A2A
- SOC and detection engineers
- Risk and audit teams
If you haven't read it yet, start with part 1, on owning and governing your AI agents. For giving a single agent its own login and per-task tokens, see our earlier post on agents as privileged users. Everything below assumes each agent already has an identity and a sponsor.
Why does runtime control matter to you?
Picture the call. An agent is changing records it shouldn't, and someone asks you to stop it now. You disable its identity in the identity provider. A while later it's still writing to the CRM, because the token it already holds hasn't expired and the CRM never checks back.
You'll find this gap in the docs. Entra access tokens last an hour by default, and tokens in continuous access evaluation sessions can live much longer, with revocation pushed only to services that support it. Google calls a service account's access token a bearer token that works until it expires, so one of its fixes is to disable the account. OWASP lists kill switches and credential revocation as how you contain a rogue agent. Nobody claims it happens by itself.
-
01 You disable the agent
You flip the agent to disabled in the identity provider. It can't sign in or get new tokens, though anything it already holds still works.
-
02 Refresh tokens get revoked
Revoking refresh tokens stops the agent quietly renewing its access. In Entra's emergency steps that's a separate call from disabling the account.
-
03 Issued tokens keep working
Whatever tokens it already has still work until they expire, unless the app bothers to check back.
-
04 Apps that listen cut it off
Services that take revocation events or introspect tokens reject the agent within minutes. The rest only find out at expiry.
-
05 The gateway shuts the door
Blocking the agent at the MCP or API gateway stops its tool calls straight away, whatever tokens it still holds.
-
06 Quarantine and keep evidence
Keep the agent's identity, logs and traces. Someone will need them to work out what it touched.
For engineers, the weak point is step 3. A self-contained JWT gets checked locally, so the resource server never asks anyone whether it was revoked. RFC 7009 says it plainly: if the authorization server can't revoke access tokens, revoking the refresh tokendefinitionThe longer-lived token an agent trades for new access tokens. Forget to revoke it and the agent quietly keeps renewing itself. won't invalidate them right away, and you have to plan for that. Short lifetimes shrink the window. Introspection or revocation events close it, but only for the apps that use them.
What's out there to help at runtime
Both are OpenID Final Specifications now. Providers finally have a standard way to tell each other a session's been revoked or a credential changed, and CAEP covers robotic users, so agents count.
Binds a token to a key the client holds. A copied DPoP token is useless without the private key, which matters a lot when an agent's memory or logs leak.
Adds authorization_details, so a token can carry something like a transfer of 45 euros to Merchant A instead of a bare payments scope. That's much closer to a task than a scope ever gets.
Short-lived signed tokens that carry the user, the workload and the call context down a chain of services. A replacement token can narrow what's allowed, and the draft says it must never widen it.
Pairs token exchange with a JWT grant so identity survives a hop into another trust domain. It's in the RFC Editor's queue and doesn't have an RFC number yet.
The current revision still requires authorization servers to rotate refresh tokens for public clients, and asks for short-lived access tokens. The spec says nothing about DPoP or sender-constrained tokens, so binding is up to you.
Conventions for invoke_agent and execute_tool spans, with attributes for the agent ID, the tool name and the tool call ID. They're still marked Development, so names can change.
OWASP's rogue-agent entry is practical. Have kill switches and credential revocation ready, hold suspect agents in a sandbox for forensics, and don't let one back into production without fresh attestation and a person's say-so.
Can you actually stop a rogue AI agent?
Usually you can stop it signing in. That part's easy. The hard question is what still works afterwards: tokens it already holds, refresh tokens that can mint new ones, API keys in a config file, a session at an MCP server, and other agents it already handed work to.
Each platform draws the line somewhere different. Entra's guide to disabling agent identities says a disabled agent can't receive tokens or authenticate, and it keeps the identity and its metadata in your tenant. It doesn't say what happens to tokens issued before. Entra's emergency guide for user accounts has two separate steps: disable the account, then revoke its refresh tokens with Revoke-MgUserSignInSession.
AWS does it with a policy. Revoke a role's sessions and IAM attaches AWSRevokeOlderSessions, which denies every action to sessions issued before that moment. It won't work on a service-linked role. Google Cloud rejects a disabled service account's tokens straight away, but they come back to life if you re-enable it before they expire, so Google says to wait at least 60 minutes. We'd wait longer if anyone set an extended token lifetime.
Okta's Universal Logout is the closest thing to a ready-made switch, as long as the app supports it. When an admin clears a user's sessions, or an entity risk policy fires, Okta clears session cookies, refresh tokens and access tokens. Okta has also announced Universal Logout for AI Agents and calls it a kill switch for agent access. We only found that in a press release, so check your own org before you count on it.
| Action | Blocks new tokens | Tokens already issued | Watch out for |
|---|---|---|---|
| Disable an Entra agent identity | Yes | Microsoft's docs don't say | Keep it disabled, not deleted, so the identity and its metadata stay for the investigation |
| Revoke Entra refresh tokens (Revoke-MgUserSignInSession) | Stops silent renewal | Rejected at CAE-capable services. Elsewhere the token runs to expiry | Access tokens last an hour by default, and CAE events can take up to 15 minutes |
| Disable an Entra service principal | Yes, no tokens for that app | CAE for workload identities covers Microsoft Graph only | Single-tenant service principals only. Managed identities aren't covered |
| Okta Universal Logout | Not stated in Okta's docs. It ends sessions | Clears refresh and access tokens in supported apps | Only apps configured for Universal Logout |
| AWS Revoke active sessions | No. Sessions started after the cutoff still work | Denied by a policy on aws:TokenIssueTime | Not available for service-linked roles |
| Disable a Google Cloud service account | Yes | Rejected while it's disabled. They work again if you re-enable it before they expire | Wait at least 60 minutes before re-enabling, longer if tokens have an extended lifetime of up to 12 hours |
| Revoke a refresh token (RFC 7009) | Stops renewal | Only if the server also revokes access tokens, which the RFC says it should | Self-contained JWTs are checked locally and never ask |
| Block the client at the MCP or API gateway | Not applicable | Yes, for every call through that gateway | Anything that reaches the app directly skips it |
Kill switch: the containment steps, in order
- 01Block the agent at the gateway first
Start at the MCP or API gateway and deny the agent's client ID. Nothing else stops tool calls as quickly, whatever tokens are still out there.
- 02Disable the identity and its app
Disable the agent identity, its service principal or app registration, and any workload identity it runs as. Disable, don't delete. You'll want the object and its logs later.
- 03Revoke refresh tokens and end sessions
Revoke refresh tokens at every authorization server the agent uses, and end its sessions there. For user accounts in Entra that's Revoke-MgUserSignInSession. In Okta, Universal Logout clears sessions and tokens in apps set up for it.
- 04Deal with tokens already out there
Where apps take revocation events or introspect, they'll reject the agent. On AWS, revoke the role's active sessions. Everywhere else the token lives until it expires, so note the latest expiry and keep watching until it passes.
- 05Rotate every secret it could read
Rotate API keys, client secrets and certificates the agent held or could fetch from a vault. A copied key outlives every revocation above.
- 06Cut tool and MCP access
Take the agent off MCP server allowlists and tool registries, and revoke OAuth grants it holds in SaaS apps. Check which other agents it handed work to, because they could still be running its tasks.
- 07Quarantine and keep the evidence
Keep the identity disabled and lock the logs and traces down. OWASP suggests parking a suspect agent in a sandbox for forensic review. Don't let it back into production without fresh attestation and a person signing off.
# Entra: turn off the user account first, then kill its refresh tokens Update-MgUser -UserId $AgentUser.Id -AccountEnabled:$false Revoke-MgUserSignInSession -UserId $AgentUser.Id # Entra: the agent's service principal Set-EntraServicePrincipal -ObjectId $sp.ObjectId -AccountEnabled $false # Any OAuth server with an RFC 7009 endpoint POST /revoke token=<refresh_token>&token_type_hint=refresh_token
Run it as a drill before you need it. Pick a test agent, disable it, and write down when each system last accepted a call from it. That's the time-to-revoke measure from part 1, broken out system by system. Wherever the number is longer than you'd like, you've found an app that doesn't check back.
OAuth was built for delegation. Is it still enough when nobody's clicking consent?
OAuth is good at one question: did someone agree to let this client act for them? An agent that runs on its own for hours and picks its own tools stretches that. The core spec gets you a token. Its extensions are what make that token say enough about an agent, and the table below goes through where each one stops.
Scopes are the weak spot. A scope like payments:write says what kind of thing the agent may touch, and nothing about which record, how much or for which task. RFC 9700 asks for tokens cut down to the minimum privilege, restricted to one resource server and to certain resources and actions there. Rich Authorization Requests give you the field to write that down. authorization_details carries a required type plus whatever that type defines, like an amount and a payee, and the authorization server and the API enforce it together.
For chains, token exchange does more than part 1 covered. The act claim records who's acting now. The may_act claim works the other way round: it says up front which party is allowed to act for the subject, so an authorization server has grounds to refuse an exchange for an agent nobody named. Across trust domains, the Identity Chaining draft repeats the same exchange at every boundary.
Then there's theft. A plain bearer token works for whoever holds it, and a commenter on Hacker News pointed out that agents often keep plaintext credentials in memory, where a compromised session can read them. DPoPdefinitionAn OAuth standard (RFC 9449) that ties a token to a key the client holds. Copy the token without the key and it's useless. binds the token to a key, so a stolen copy fails without the private key. RFC 9700 says refresh tokens for public clients must be sender-constrained or rotated, and MCP requires rotation for public clients.
| Standard | Status | What it gives an agent | Where it stops |
|---|---|---|---|
| Token Exchange (RFC 8693): act and may_act | RFC, January 2020 | A new token per hop naming the current actor. may_act says who's allowed to act for the subject | Prior actors are informational only, so authorize on the current actor |
| Resource Indicators (RFC 8707) | RFC, February 2020 | The client names the target, and the token gets restricted to that audience | Each resource still has to check aud and reject tokens meant for someone else |
| Scopes, per the OAuth security BCP (RFC 9700) | Best Current Practice, January 2025 | Least privilege and audience restriction as the baseline | A scope names a kind of access, never one task or one record |
| Rich Authorization Requests (RFC 9396) | RFC, May 2023 | authorization_details with a type, plus amounts, targets and actions | Your authorization server and your API both have to understand each type you define |
| DPoP (RFC 9449) | RFC, September 2023 | Tokens bound to the client's key, so a copied token fails | The agent's private key becomes the thing to protect |
| Transaction Tokens | IETF draft 11, waiting for write-up | User, workload and call context carried down a chain, signed and short-lived | One trust domain only. A replacement can narrow, never widen |
| Identity Chaining | IETF draft 17, in the RFC Editor queue | Token exchange plus a JWT grant at each trust-domain boundary | Not an RFC yet, and each domain still decides what it issues |
| CAEP 1.0 over Shared Signals 1.0 | OpenID Final Specifications, September 2025 | Standard events for session revoked, credential change and risk change between providers | Only helps where the app receives the events and acts on them |
| Token Revocation and Introspection (RFC 7009, RFC 7662) | RFCs, 2013 and 2015 | A revoke endpoint, and an active flag a resource server can ask for | Introspection costs a call per check. JWTs checked locally skip it |
| MCP authorization | Revision 2026-07-28 (latest) | RFC 8707 resource parameter, audience checks, no token passthrough, rotated refresh tokens for public clients | No sender-constrained tokens in the spec |
Does a successful sign-in prove an agent is safe?
No. A sign-in proves the agent held a valid credential at that moment. It tells you nothing about whether the credential was stolen, whether someone hijacked the agent's instructions since, or whether it's now calling tools it never used before.
NIST's zero trust architecture already asks for more. Its tenets say the enterprise monitors the security posture of every asset, and that authentication and authorization run as a constant cycle of reassessing trust, with reauthentication during a session when needed. Agents need the same loop. The signals just look different.
The standards help here. CAEPdefinitionShort for OpenID's Continuous Access Evaluation Profile. Providers send each other events, like a revoked session or a changed credential, so access can change mid-session instead of at expiry. defines events one provider sends another when something changes, like a revoked session, changed token claims, a changed credential or a new risk level, and it's written for human and robotic users alike. Okta's Identity Threat Protection takes these signals from security vendors over the Shared Signals Framework, and its entity risk policy can end sessions through Universal Logout. Entra's continuous access evaluation reacts to a short list of critical events. For workload identities, that list is a service principal disabled, deleted or flagged at high risk.
| Signal | Where it comes from | What it can mean for an agent | Response we'd wire up |
|---|---|---|---|
| Session revoked (CAEP) | Identity provider, or another app over Shared Signals | Someone or something already decided to stop it | Drop the agent's cached tokens and stop its running tasks |
| Credential change (CAEP) | Identity provider or vault | A key or secret was added or rotated | Check a ticket sits behind it. If not, treat it as a compromise |
| Risk level change (CAEP), high service principal risk (Entra) | ID Protection, Okta ITP or a security vendor | A leaked credential or an odd sign-in pattern | Step up, or block until the sponsor confirms |
| Token claims change (CAEP) | Identity provider | Groups or roles behind the token moved | Re-evaluate before the next tool call |
| Burst of calls or fan-out to other agents | Gateway metrics and A2A logs | A loop, a cascade or a hijacked goal | Throttle or pause, as OWASP's cascading-failure entry suggests |
| Authentication failures and authorization denials | A2A server logs, MCP 403 responses | The agent probing for access it shouldn't have | Alert past a threshold you set from your own baseline |
One caveat from Microsoft's docs: CAE only works for some client and resource combinations, and CAE for workload identities only covers Microsoft Graph. A sign-in log full of successes can sit right next to an agent nobody's watching at the API. Part 1 noted that Entra's risky-agent detections run offline, so plan your response times around that.
Short lifetimes are the cheapest form of continuous evaluation. A commenter in a Hacker News thread about JWTs described the usual trade-off: JWTs can't really be revoked, so you set a short expiry on the access token, around five minutes, and a longer one on the refresh token. The agent has to come back to the authorization server often, and every return is a chance to say no.
What's missing from your logs when someone asks what the agent actually did?
Most teams already have the pieces. The identity provider logs the token grant, the gateway logs the tool call, the app logs the record change, and the model platform logs the prompt. What's missing is a key that joins them. When something goes wrong, someone ends up matching timestamps across four consoles and guessing which call belonged to which task.
Part 1's KPI table said which numbers to watch. This section is about the join. Each of the keys below already exists in a standard, so the work is carrying them through every hop and logging them in the same place.
| Key | Where it's defined | What it links | Where to log it |
|---|---|---|---|
| trace-id in the traceparent header | W3C Trace Context (Recommendation) | Every hop of one request, across services | Gateway, MCP server, app and agent runtime |
| jti, client_id, sub and aud | JWT access token profile (RFC 9068) | The exact token used, the agent's client and the user it served | Each resource server, on every call |
| act chain | Token Exchange (RFC 8693) | Which agent acted, after which earlier agents, for which user | Resource servers and the authorization server's exchange log |
| gen_ai.agent.id, gen_ai.tool.call.id, gen_ai.conversation.id | OpenTelemetry GenAI conventions (Development) | The agent, the specific tool call and the conversation it belongs to | Agent runtime traces, in invoke_agent and execute_tool spans |
| contextId and taskId | A2A 1.0.0 | Tasks and messages that belong to one piece of work between agents | Both the A2A client and the server |
| Elevation event with a correlation ID | MCP security best practices | The scope requested, the subset granted and the call behind it | MCP server or authorization server |
| Txn-Token | OAuth Transaction Tokens draft | User, workload and call context, signed, down the chain | Each internal service that receives one |
trace_id: 4bf92f3577b34da6a3ce929d0e0e4736 agent: agent:refund-bot-3 tool_call: call_7Qx execute_tool refunds.create token: jti=9f1c sub=user:rep-221 aud=billing act: { sub: agent:refund-bot-3, act: { sub: agent:triage-1 } } policy: allow rule=refunds.under_limit outcome: 201 Created record=RF-55812
A few gaps show once you lay these side by side. A2A's spec says agents should log security events and keep audit trails for sensitive operations, and it never mentions trace context, so you'll carry traceparent through A2A calls yourself. The OpenTelemetry agent conventions are still marked Development, so pin the version you build against. The NIST NCCoE concept paper is still asking how agents can log their actions and intent in a tamper-proof, verifiable way, and how to bind each action back to a person's authorization. There's no settled answer yet.
Log the outcome too. Most agent logs stop at the tool call, and the call says what the agent asked for. The record ID, the amount and the response code say what actually changed. Without those you can't undo a bad run with any confidence.
Why do orphaned agents and service accounts keep running long after everyone's moved on?
Because a credential doesn't know its project ended. Part 1 dealt with the identity side: give every agent a sponsor and move sponsorship when that person leaves. This section is about what outlives the identity record. Think of API keys in a config file, long-lived refresh tokens, OAuth grants a user approved for an agent in some SaaS app, and a service account on a cluster nobody remembers.
OWASP's NHI top 10 puts improper offboarding first, and it splits the problem in two. Stale or dormant identities get left behind when an app or service goes offline. Orphaned ones keep working after their owner leaves, because nobody was named to take over. Its examples will sound familiar: a decommissioned service's Kubernetes cluster with service accounts still active, and an ex-employee who still gets in through an NHI after their own account was switched off.
NIST SP 800-53 already covers this. AC-2 says to tell account managers when accounts are no longer needed and when users are transferred or terminated. AC-2(3) says to disable accounts that have expired, have no associated user, break policy or sit inactive past a period you set. Agents fit every clause. The trouble is that HR events reach people's accounts, and nothing like them reaches an agent's keys.
A Hacker News commenter put the practical version simply. When keys live wherever the agent runs, it all works until a contractor leaves. That's the moment to design for, because it's the one nobody schedules.
How an agent's credentials outlive its project
- BuildBuilder creates the agent
It gets a client secret or an API key, and someone pastes it into a config file or a pipeline variable.
- Go-liveA user consents in a SaaS app
The agent now holds a refresh token for that app. The grant lives in the SaaS tenant, a long way from your identity team.
- HandoverProject closes, agent keeps running
Nobody turns it off in case something still depends on it. It isn't needed any more, but it's still active.
- Owner leavesBuilder changes teams or leaves
Their account gets disabled. The agent's key, its refresh token and the SaaS grant aren't touched, so now it's orphaned.
- LaterThe key turns up in a leak or an audit
Someone finds it in a repo, a log or an audit finding, and nobody can say what it's for.
- Clean-upDisable, watch, then delete
Disable it in a change window, watch for anything that breaks, and delete it after a waiting period you set.
- App registrations and service principals with secrets or certificates, and an owner who's gone or was never set
- OAuth grants and refresh tokens that someone approved inside a SaaS app. Your identity team usually can't see those
- API keys in config files, CI variables and notebooks, sitting outside any vault
- Service accounts on clusters, VMs and functions that belonged to retired projects
- MCP server and gateway allowlists that still name an agent nobody runs
- Peer agents that still take calls from one you retired. Nobody thinks to tell them
Sweep these on a schedule, and treat every hit the way part 1 treats an unclaimed agent. Then fix the cause. Tie each credential to the agent record when it's issued, give it an expiry, and make retiring the agent revoke everything hanging off it.
Your AI policy says no to something. What actually stops the call when the agent tries it anyway?
A lot of AI governance lives in documents. They say an agent mustn't move money without approval, or mustn't touch customer data outside its task. Then nothing in the request path checks. The rule only gets enforced when someone reads the logs afterwards, if anyone does.
NIST's zero trust model already has the parts you need. A policy engine decides and logs each call. An enforcement point sits in the request and can cut it off. For agents, that enforcement point is usually your API or MCP gateway, and the engine can be something like Open Policy Agent, which keeps its rules as code, apart from the thing enforcing them.
OWASP's agentic top 10 lands in the same place. Its cascading-failure entry wants each high-impact tool call checked against a policy-as-code rule before it runs, and an external policy engine between planning and execution. The privilege-abuse entry wants a central engine re-checking each privileged step. And MCP's tools spec says servers must enforce access controls and rate limits, and that there should always be a person able to deny a tool call.
- The refund limit rule sits in a PDF on the intranet
- The agent's token says refunds:write. The API has no idea there's a limit, so it pays any amount
- Someone spots the breach in a monthly log review, after the money's gone
- Changing the rule means a new document version, then a training session and hope
- Auditors get the policy and a promise that people follow it
- The same rule lives in a policy file in version control, and it has tests
- The gateway won't pass a refund until the policy engine has seen the amount, the agent and the user
- Over the limit, the call waits for a person or gets denied. It never reaches the API
- Changing the rule is a reviewed pull request that goes out with the next deploy
- Auditors get the rule, the test results and a log line for each decision. Much easier than a promise
Before: no gateway in the path
Here the agent talks straight to the MCP server and the API. There's nowhere to block it, and every system logs on its own with no shared key. When you hit stop, you wait for the slowest token to expire.
After: a gateway that can say no
The gateway does the enforcing. Each call gets checked with the policy engine and stamped with a trace ID, and you can block the agent there on the spot. Tokens stay short-lived, bound to the agent and swapped at each hop. Every log ends up in the same place.
Start with the few actions that would hurt most: payments, deletions, permission changes and messages sent outside the company. Write each one as a rule the gateway can check, with the inputs it needs. RAR's authorization_details give you a clean place to carry those inputs inside the token, so the rule and the token describe the same task.
Agents calling agents: where does it break, and what fixes it?
Chains are where the runtime gaps stack up. Every hop is another place a token gets forwarded, widened or trusted too much. Part 1's rule of one token per hop is where you start, and it doesn't cover everything below.
| Risk | How it happens | Control |
|---|---|---|
| Confused deputy | A middle agent uses its own broad rights to do something the original caller couldn't. MCP documents a version of it at proxy servers with static client IDs | Authorize on the user and the current actor at the end of the chain. At proxies, get consent for each client |
| Scope inflation across hops | Each agent asks for a bit more at step-up, and MCP's step-up requests old and new scopes combined. Along a chain it adds up | Exchange for a narrower token at each hop. Transaction Tokens let a replacement narrow, never widen |
| Token passthrough | An agent forwards the token it got instead of getting its own, so the next service can't tell who's calling | Audience checks at every service. MCP forbids passthrough outright |
| Lost chain of custody | The end service only trusts the last caller. Nested act claims are informational only, so they can't drive a decision | Log the full act chain and trace-id at every hop, and use may_act so only named agents act for a user |
| Revocation that stops at the first hop | You stop agent A, but agent B is still working on the task A gave it, with its own token | Track A2A taskId and contextId, so you can find and stop downstream work when you pull the parent |
| Spoofed callbacks | A forged push notification tells an agent a task finished or changed | A2A says clients must validate webhook credentials. Check webhook URLs against SSRF as well |
A2A leaves a lot of this to you. It says credentials should be bound to the agent that sent the request. It doesn't define scope, validity or revocation for a credential an agent gets after hitting the auth-required state. A Hacker News commenter summarizing the OpenID Foundation's paper on agent identity listed revocation propagation as one of its open problems, next to agents impersonating users and recursive delegation.
Standards and spec dates behind runtime control
- Aug 2013RFC 7009 OAuth token revocation
- Jan 2020RFC 8693 Token Exchange (act, may_act)
- Feb 2020RFC 8707 Resource Indicators
- Feb 6, 2020W3C Trace Context becomes a Recommendation
- May 2023RFC 9396 Rich Authorization Requests
- Sep 2023RFC 9449 DPoP
- Jan 2025RFC 9700 OAuth security best practice
Asks for sender-constrained tokens and audience restriction, and says public clients' refresh tokens must be sender-constrained or rotated.
- Sep 2, 2025Shared Signals, CAEP and RISC approved as Final
- Dec 2025OWASP Top 10 for Agentic Applications
ASI10 covers rogue agents. OWASP wants a kill switch, credential revocation and a quarantine ready before you need them.
- Jul 19, 2026OAuth Identity Chaining draft 17
Sent to the IESG and now in the RFC Editor queue.
- Jul 28, 2026MCP specification revision
The current revision still makes authorization servers rotate refresh tokens for public clients. Check that yours does.
- Jul 30, 2026OAuth Transaction Tokens draft 11
What should each team do now?
What to do now, by who you are
- Ask how long it takes to stop your most important agent in every system, measured in a drill, not guessed.
- Write down which agent actions need a rule in the request path. Payments and deletions go on that list first.
- Agree who can pull the kill switch out of hours, and that they won't need a second approval to do it.
- Make agent tokens short-lived. Where your apps allow it, turn on continuous access evaluation or introspection too.
- Set may_act, or whatever your platform calls it. Then only agents you named can act for a user.
- Make retiring an agent revoke its refresh tokens, secrets and SaaS grants in one workflow.
- Put a gateway in front of every agent and MCP call, one that can block a single client straight away.
- Carry traceparent through agent, A2A and MCP calls. Log jti, client_id and the act chain at each API.
- Move high-impact rules into policy as code at the gateway, with tests that run on every change.
- Run a kill-switch drill every quarter and record the last successful call per system.
- Subscribe to CAEP or vendor risk events, and wire each one to an action someone has agreed to.
- Hunt for credentials whose agent record is retired, missing or owned by someone who left.
How do you make the next incident smaller than this one?
We'd do it in this order. The drill comes first because it tells you which of the later steps matter most in your estate. Each step after it closes a gap the drill can measure again.
A runtime control program, in order
- 01Measure your stop time
Run the drill on one agent per platform. Record when each system last accepted a call after you disabled it. That list is your backlog.
- 02Put a gateway in front of every tool
Route agent traffic to MCP servers and APIs through a gateway that can deny a client at once and logs every call. Direct connections are where kill switches fail.
- 03Shorten and bind tokens
Cut agent access token lifetimes and rotate refresh tokens. Where your stack can, bind tokens with DPoP or mutual TLS, as RFC 9700 recommends.
- 04Describe the task in the token
Swap broad scopes for authorization_details on the actions that matter, and set may_act so only the agents you named can act for a user.
- 05Subscribe to trust signals
Receive CAEP or vendor risk events, and turn each one into an action: step up, pause the agent or pull the switch.
- 06Join the telemetry
Carry the trace-id through every hop. Log the token IDs and the act chain next to each tool call, and what it changed.
- 07Enforce policy as code
Move rules from your AI policy into the policy engine one at a time, starting with payments and deletions. Test each rule like code.
- 08Tie credentials to retirement
Issue every credential against an agent record, with an expiry. Retiring the agent revokes all of them.
What if an agent goes rogue before you're ready?
If an agent goes rogue: the first days, in order
Something's acting outside its job: odd writes, a burst of calls, data going where it shouldn't. Stop the calls first, then the credentials, then work out what it did. Keep everything you collect.
- 01Containfirst hour
- Block the agent's client at every gateway. That stops tool calls while you do the slower steps.
- Disable the identity and its app, then revoke refresh tokens and end sessions at each authorization server.
- Check what it handed to other agents. The A2A task and context IDs show you, and those tasks need stopping as well.
- 02Close the windowfirst few hours
- Note when each of the agent's tokens expires. Somebody has to keep checking each system until the last one has run out.
- Revoke AWS role sessions, rotate keys and secrets it could read, and pull its OAuth grants in SaaS apps.
- Confirm the calls really stopped by searching gateway and app logs by client ID and trace-id.
- 03Investigatefirst day
- Go through the act chain on each call. You'll see who it was acting for, and which agents it pulled in.
- Work out how it got the reach it used. A step-up, a new tool, a forwarded token and a stale grant are the usual suspects.
- 04Recoverdays 1 to 3
- Undo the bad changes with each system's owner. The outcome records you logged tell you what to put back.
- Bring the agent back only from a reviewed template with fresh credentials, after attestation and a person's sign-off.
- 05Report and learnfirst two weeks
- Write down how long each system kept accepting calls after you hit stop. Auditors and insurers will ask.
- Turn every gap into something concrete. That could be a gateway rule, a shorter token lifetime or a new signal you listen for.
What could this look like in practice?
Three typical situations
- the setup
- A services firm disables a sales agent in its identity provider after it starts editing the wrong accounts. The CRM checks JWTs locally and doesn't take revocation events.
- what happens
- No new tokens, but the one it already holds still works until expiry. So it carries on editing accounts, and later nobody can say when it actually stopped.
- what to do
- Next time, block the agent's client at the gateway first. Shorten its token lifetime, and put the CRM behind introspection or revocation events for agent clients.
- the setup
- A retailer's triage agent passes work to a returns agent, and that one calls a payments agent. At each hop, the step-up asked for a little more scope.
- what happens
- Three hops in, the token can refund any order. The payments service only sees the agent right before it, and a refund nobody approved goes out.
- what to do
- Exchange for a narrower token at every hop. Then set may_act for the agents allowed to act for a customer, and put a policy rule on refunds at the gateway.
- the setup
- An insurer's data team built an agent to summarize claims for a pilot. The pilot ended and the builder left. The agent's API key still sits in a notebook and a SaaS integration.
- what happens
- An audit finds the key in use from an address nobody recognizes. The identity record shows a disabled builder, and nothing ties the key to anything anyone still owns.
- what to do
- Revoke the key and the SaaS grant now. Then tie every credential to an agent record with an expiry, so retiring the agent revokes them.
We start with the drill. Pick an agent, hit stop and time it, system by system. Then we fix what it turned up. Our AI agent identity and identity threat detection and response pages explain how we work, and AI governance covers the policy side.
We'd usually do the identity work on Microsoft Entra ID, Okta or Ping Identity, with agent secrets in HashiCorp Vault or CyberArk. You can bring in identity engineers for the build, or start with an assessment and see how long your agents take to stop today.
What to take from this
- 01
Disabling an agent stops new tokens and nothing else. Anything it already holds works until expiry, unless the app checks back.
- 02
Block the agent at the gateway first. Nothing else stops its tool calls as fast.
- 03
Drill the kill switch and record, system by system, when the last call got through.
- 04
Bind tokens with DPoP or mutual TLS and rotate refresh tokens, so a copied token is worth less.
- 05
A clean sign-in only proves the credential was valid. Subscribe to CAEP or vendor risk events to learn what changed after.
- 06
Carry the trace-id, the token's jti and the act chain on every hop, so one query rebuilds what an agent did.
- 07
Make retiring an agent revoke its keys, refresh tokens and SaaS grants together.
- 08
Move high-impact rules out of documents and into a policy engine the gateway asks on every call.
- How Cohash delivers Microsoft Entra ID: scope, roles and architecture
- How Cohash delivers Okta: scope, roles and architecture
- How Cohash delivers Ping Identity: scope, roles and architecture
- Hire vetted Microsoft Entra ID engineers
- AI agent identity
- Book a 30-minute working session with a senior engineer
01Can we stop a rogue AI agent instantly?
You can stop its tool calls almost at once if they all go through a gateway you control. Disabling its identity stops new tokens, but tokens it already holds can keep working at apps that don't check back. Drill it so you know the real number for each system.
02Does disabling an agent in Entra or Okta actually kill the tokens it already has?
Disabling stops new ones. In Entra you revoke refresh tokens as a separate step, and services using continuous access evaluation react to that. Okta's Universal Logout clears sessions, refresh tokens and access tokens in apps set up for it. Anywhere else, the access token lasts until it expires.
03Is OAuth enough for autonomous AI agents?
OAuth plus its extensions gets you most of the way. Token exchange with act and may_act handles delegation chains, resource indicators pin the audience, Rich Authorization Requests describe the task and DPoP binds the token to a key. The cross-domain and call-chain pieces are still IETF drafts.
04Is a scope enough, or do agents need task-level authorization?
A scope names a kind of access, like payments:write. Task-level authorization says what this one run may do: which payee, how much, which record. RFC 9396 carries that in authorization_details, and your API and authorization server both enforce it.
05What telemetry should we collect for AI agents?
Enough to follow one action from the token to the outcome. Carry the W3C trace-id on every hop, and log the token's jti, client_id, sub, aud and act chain next to each tool call, plus what changed in the app. Part 1's KPI table covers which numbers to track.
06How do we find orphaned agents and service accounts nobody's claimed?
Look for credentials whose agent record is retired, missing or owned by someone who's left: client secrets, API keys in config files, refresh tokens and SaaS grants. Disable them in a change window, watch who calls, and delete after a waiting period.
07How do you get an AI policy to block a call, not just describe it?
A gateway in the request path asks a policy engine about each call before it goes through. The rule lives as code, with tests. If a call breaks the rule it's held for a person or denied, and the decision gets logged for the auditor.
08What is CAEP, and do we need it?
CAEP is an OpenID standard for sending events like a revoked session or a changed credential between providers, over the Shared Signals Framework. You'll want something like it if your apps should react within minutes when an agent's trust changes, instead of at token expiry.
Three questions, about a minute
Pick an answer and we'll tell you if it's right, and why it is or isn't. The score stays in this browser.
-
Q1You disabled an agent in your identity provider, but its CRM writes keep succeeding. What's the most likely reason?
show the answer
B. Its token hasn't expired yet, and the CRM only checks it locally Disabling blocks new tokens. A self-contained access token keeps working until it expires, unless the app checks with the authorization server or listens for revocation events.
-
Q2What limits a refund agent to one order?
show the answer
D. authorization_details for that order A scope only names a kind of access. Rich Authorization Requests carry the task itself, and both the authorization server and the API enforce it.
-
Q3Triage calls returns, which calls payments. Payments only sees the returns agent. How do you keep the chain visible?
show the answer
A. Exchange tokens per hop with act claims Each hop gets its own token naming the current actor. Nested act claims and a shared trace-id let you rebuild the chain later, while access decisions use the current actor.