SecurityIdentity

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.

Aditya, Cohash Security Practice October 2026 33 min read 12 chapters 3-question check
part 6 of 6 · Identity security, from the ground up
01 Gatewayblock calls stop 02 Identityoff no new tokens 03 Tokensrevoked refresh and… 04 Keysrotated copies go dead 05 Quarantine evidence kept

the 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.

in plain wordsPractice: runtime control for AI agents

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 it like this

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.

who should care
  • 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.

chapter 01

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.

1 hourdefault lifetime of a Microsoft Entra access token
28 hoursupper limit Entra gives tokens in continuous access evaluation sessions
15 minlatency Microsoft says CAE critical events might take to propagate
60 mindefault upper limit on a Google Cloud service account access token
how it worksWhat happens when you hit stopEach step closes one door. The risky one is step 3, where tokens the agent already holds keep working at apps that never check back.
  1. 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.

  2. 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.

  3. 03 Issued tokens keep working

    Whatever tokens it already has still work until they expire, unless the app bothers to check back.

  4. 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.

  5. 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.

  6. 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

newCAEP 1.0 and Shared Signals 1.0

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.

newDPoP (RFC 9449)

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.

newRich Authorization Requests (RFC 9396)

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.

enhancedOAuth Transaction Tokens, draft 11

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.

newOAuth Identity Chaining, draft 17

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.

enhancedMCP authorization, 2026-07-28 revision

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.

newOpenTelemetry GenAI agent spans

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.

newOWASP rogue-agent containment

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.

chapter 02

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.

tableWhat each stop really stops. Vendor rows follow each vendor's docs; the last row is our own practice
ActionBlocks new tokensTokens already issuedWatch out for
Disable an Entra agent identityYesMicrosoft's docs don't sayKeep it disabled, not deleted, so the identity and its metadata stay for the investigation
Revoke Entra refresh tokens (Revoke-MgUserSignInSession)Stops silent renewalRejected at CAE-capable services. Elsewhere the token runs to expiryAccess tokens last an hour by default, and CAE events can take up to 15 minutes
Disable an Entra service principalYes, no tokens for that appCAE for workload identities covers Microsoft Graph onlySingle-tenant service principals only. Managed identities aren't covered
Okta Universal LogoutNot stated in Okta's docs. It ends sessionsClears refresh and access tokens in supported appsOnly apps configured for Universal Logout
AWS Revoke active sessionsNo. Sessions started after the cutoff still workDenied by a policy on aws:TokenIssueTimeNot available for service-linked roles
Disable a Google Cloud service accountYesRejected while it's disabled. They work again if you re-enable it before they expireWait 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 renewalOnly if the server also revokes access tokens, which the RFC says it shouldSelf-contained JWTs are checked locally and never ask
Block the client at the MCP or API gatewayNot applicableYes, for every call through that gatewayAnything that reaches the app directly skips it

Kill switch: the containment steps, in order

  1. 01
    Block 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.

  2. 02
    Disable 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.

  3. 03
    Revoke 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.

  4. 04
    Deal 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.

  5. 05
    Rotate 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.

  6. 06
    Cut 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.

  7. 07
    Quarantine 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.

kill-switch-runbook (example output)example output
# 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.

chapter 03

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.

tableEach OAuth extension, what it adds once nobody's around to click consent, and how finished it is
StandardStatusWhat it gives an agentWhere it stops
Token Exchange (RFC 8693): act and may_actRFC, January 2020A new token per hop naming the current actor. may_act says who's allowed to act for the subjectPrior actors are informational only, so authorize on the current actor
Resource Indicators (RFC 8707)RFC, February 2020The client names the target, and the token gets restricted to that audienceEach 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 2025Least privilege and audience restriction as the baselineA scope names a kind of access, never one task or one record
Rich Authorization Requests (RFC 9396)RFC, May 2023authorization_details with a type, plus amounts, targets and actionsYour authorization server and your API both have to understand each type you define
DPoP (RFC 9449)RFC, September 2023Tokens bound to the client's key, so a copied token failsThe agent's private key becomes the thing to protect
Transaction TokensIETF draft 11, waiting for write-upUser, workload and call context carried down a chain, signed and short-livedOne trust domain only. A replacement can narrow, never widen
Identity ChainingIETF draft 17, in the RFC Editor queueToken exchange plus a JWT grant at each trust-domain boundaryNot an RFC yet, and each domain still decides what it issues
CAEP 1.0 over Shared Signals 1.0OpenID Final Specifications, September 2025Standard events for session revoked, credential change and risk change between providersOnly helps where the app receives the events and acts on them
Token Revocation and Introspection (RFC 7009, RFC 7662)RFCs, 2013 and 2015A revoke endpoint, and an active flag a resource server can ask forIntrospection costs a call per check. JWTs checked locally skip it
MCP authorizationRevision 2026-07-28 (latest)RFC 8707 resource parameter, audience checks, no token passthrough, rotated refresh tokens for public clientsNo sender-constrained tokens in the spec
chapter 04

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.

tableWhat to watch for after sign-in, and what we'd do when each one fires
SignalWhere it comes fromWhat it can mean for an agentResponse we'd wire up
Session revoked (CAEP)Identity provider, or another app over Shared SignalsSomeone or something already decided to stop itDrop the agent's cached tokens and stop its running tasks
Credential change (CAEP)Identity provider or vaultA key or secret was added or rotatedCheck 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 vendorA leaked credential or an odd sign-in patternStep up, or block until the sponsor confirms
Token claims change (CAEP)Identity providerGroups or roles behind the token movedRe-evaluate before the next tool call
Burst of calls or fan-out to other agentsGateway metrics and A2A logsA loop, a cascade or a hijacked goalThrottle or pause, as OWASP's cascading-failure entry suggests
Authentication failures and authorization denialsA2A server logs, MCP 403 responsesThe agent probing for access it shouldn't haveAlert 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.

chapter 05

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.

tableJoin keys. With these, the token, the tool call and what changed land in one record
KeyWhere it's definedWhat it linksWhere to log it
trace-id in the traceparent headerW3C Trace Context (Recommendation)Every hop of one request, across servicesGateway, MCP server, app and agent runtime
jti, client_id, sub and audJWT access token profile (RFC 9068)The exact token used, the agent's client and the user it servedEach resource server, on every call
act chainToken Exchange (RFC 8693)Which agent acted, after which earlier agents, for which userResource servers and the authorization server's exchange log
gen_ai.agent.id, gen_ai.tool.call.id, gen_ai.conversation.idOpenTelemetry GenAI conventions (Development)The agent, the specific tool call and the conversation it belongs toAgent runtime traces, in invoke_agent and execute_tool spans
contextId and taskIdA2A 1.0.0Tasks and messages that belong to one piece of work between agentsBoth the A2A client and the server
Elevation event with a correlation IDMCP security best practicesThe scope requested, the subset granted and the call behind itMCP server or authorization server
Txn-TokenOAuth Transaction Tokens draftUser, workload and call context, signed, down the chainEach internal service that receives one
correlated-agent-event (example output)example output
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.

chapter 06

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

  1. Build
    Builder creates the agent

    It gets a client secret or an API key, and someone pastes it into a config file or a pipeline variable.

  2. Go-live
    A 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.

  3. Handover
    Project 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.

  4. Owner leaves
    Builder 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.

  5. Later
    The 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.

  6. Clean-up
    Disable, 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.

chapter 07

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.

side by sideSame refund limit. Left, it's written down and hoped for. Right, the gateway checks it on every call
Policy in a document
  • 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
Policy as code at the gateway
  • 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

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.

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. 01 · AGENT 02 · IDENTITY 03 · TOOLS AND APPS gets token calls tool forwards token Agent runtime broad scope, bearer token Identity provider logs token grants MCP server own log Payments API trusts any valid token © Cohash · cohash.com
01 · AGENT02 · IDENTITY03 · TOOLS AND APPS Agent runtime: broad scope, bearer token Agent runtime broad scope, bearer token Identity provider: logs token grants Identity provider logs token grants MCP server: own log MCP server own log Payments API: trusts any valid token Payments API trusts any validtoken gets token calls tool © Cohash · cohash.com
after

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.

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. 01 · AGENT 02 · CONTROL 03 · TOOLS AND APPS 04 · EVIDENCE exchanges token every call allow or deny? allowed call own token decisions outcomes grants Agent runtime DPoP-bound, short-livedtoken Authorization server token exchange, act chain Gateway (PEP) blocks, stamps traceparent Policy engine rules as code, logsdecisions MCP server checks audience Payments API logs outcome with trace-id SIEM or data lake joined on trace-id © Cohash · cohash.com
01 · AGENT02 · CONTROL03 · TOOLS AND APPS04 · EVIDENCE Agent runtime: DPoP-bound, short-lived token Agent runtime DPoP-bound, short-lived token Authorization server: token exchange, act chain Authorizati…server token exchange,act chain Gateway (PEP): blocks, stamps traceparent Gateway(PEP) blocks, stampstraceparent Policy engine: rules as code, logs decisions Policyengine rules as code,logs decisions MCP server: checks audience MCP server checks audience Payments API: logs outcome with trace-id Payments API logs outcome withtrace-id SIEM or data lake: joined on trace-id SIEM or data lake joined on trace-id exchanges token every call allowed call decisions outcomes grants © Cohash · cohash.com

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.

chapter 08

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.

tableHow agent-to-agent chains go wrong, and the fix we'd put on each
RiskHow it happensControl
Confused deputyA 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 IDsAuthorize on the user and the current actor at the end of the chain. At proxies, get consent for each client
Scope inflation across hopsEach 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 upExchange for a narrower token at each hop. Transaction Tokens let a replacement narrow, never widen
Token passthroughAn agent forwards the token it got instead of getting its own, so the next service can't tell who's callingAudience checks at every service. MCP forbids passthrough outright
Lost chain of custodyThe end service only trusts the last caller. Nested act claims are informational only, so they can't drive a decisionLog 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 hopYou stop agent A, but agent B is still working on the task A gave it, with its own tokenTrack A2A taskId and contextId, so you can find and stop downstream work when you pull the parent
Spoofed callbacksA forged push notification tells an agent a task finished or changedA2A 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

  1. Aug 2013
    RFC 7009 OAuth token revocation
  2. Jan 2020
    RFC 8693 Token Exchange (act, may_act)
  3. Feb 2020
    RFC 8707 Resource Indicators
  4. Feb 6, 2020
    W3C Trace Context becomes a Recommendation
  5. May 2023
    RFC 9396 Rich Authorization Requests
  6. Sep 2023
    RFC 9449 DPoP
  7. Jan 2025
    RFC 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.

  8. Sep 2, 2025
    Shared Signals, CAEP and RISC approved as Final
  9. Dec 2025
    OWASP Top 10 for Agentic Applications

    ASI10 covers rogue agents. OWASP wants a kill switch, credential revocation and a quarantine ready before you need them.

  10. Jul 19, 2026
    OAuth Identity Chaining draft 17

    Sent to the IESG and now in the RFC Editor queue.

  11. Jul 28, 2026
    MCP specification revision

    The current revision still makes authorization servers rotate refresh tokens for public clients. Check that yours does.

  12. Jul 30, 2026
    OAuth Transaction Tokens draft 11
chapter 09

What should each team do now?

What to do now, by who you are

Business leadersthis month
  • 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.
Identity teamthis quarter
  • 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.
Platform and app teamsthis quarter
  • 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.
Security operationsongoing
  • 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.
chapter 10

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

  1. 01
    Measure 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.

  2. 02
    Put 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.

  3. 03
    Shorten 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.

  4. 04
    Describe 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.

  5. 05
    Subscribe 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.

  6. 06
    Join 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.

  7. 07
    Enforce 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.

  8. 08
    Tie credentials to retirement

    Issue every credential against an agent record, with an expiry. Retiring the agent revokes all of them.

chapter 11

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.

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
chapter 12

What could this look like in practice?

Three typical situations

01 Agentdisabled 02 Old tokenvalid 03 CRM acceptsit 04 Gateway block calls stop now
scenario 01High risk
Disabled, but still writing to the CRM
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.
01 Triage agent 02 Returns agent asks for more 03 Paymentsagent oversized token 04 Policy check over the limit
scenario 02High risk
Three agents, three step-ups, one oversized token
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.
01 Pilot ends 02 Builderleaves 03 Key stillvalid 04 Expiry onrecord revoked at retire
scenario 03Medium risk
The key from a pilot that ended
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.

key takeaways

What to take from this

  1. 01

    Disabling an agent stops new tokens and nothing else. Anything it already holds works until expiry, unless the app checks back.

  2. 02

    Block the agent at the gateway first. Nothing else stops its tool calls as fast.

  3. 03

    Drill the kill switch and record, system by system, when the last call got through.

  4. 04

    Bind tokens with DPoP or mutual TLS and rotate refresh tokens, so a copied token is worth less.

  5. 05

    A clean sign-in only proves the credential was valid. Subscribe to CAEP or vendor risk events to learn what changed after.

  6. 06

    Carry the trace-id, the token's jti and the act chain on every hop, so one query rebuilds what an agent did.

  7. 07

    Make retiring an agent revoke its keys, refresh tokens and SaaS grants together.

  8. 08

    Move high-impact rules out of documents and into a policy engine the gateway asks on every call.

fact-checked October 2026 against vendor and official documentation · where to go next
  1. How Cohash delivers Microsoft Entra ID: scope, roles and architecture
  2. How Cohash delivers Okta: scope, roles and architecture
  3. How Cohash delivers Ping Identity: scope, roles and architecture
  4. Hire vetted Microsoft Entra ID engineers
  5. AI agent identity
  6. 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.

next step

Tell us what you're running. We'll tell you what we'd do first.

A 30-minute working session with a senior engineer. No slides.

useful to bring
  • The platform and the version you're on
  • Where you need to get to, and by when
  • What's custom: rules, plugins, integrations
  • Any audit finding or deadline driving it