Token theft in AI agents is an architecture failure
Prompt injection gets the attention, but credentials turn a confused model into an authenticated attacker. The fix is to keep tokens out of model context and authorize every action at runtime.
The security story of a chatbot ends at text. The security story of an agent starts there.
Give a model a GitHub token and a tool that can open pull requests, and a malicious issue comment is no longer trying to make the model say something embarrassing. It is trying to borrow an authenticated identity. The prompt injection is the steering mechanism; the credential is the authority; the tool is the actuator.
That distinction matters because teams often attack the wrong layer. They buy
a better injection classifier, strengthen the system prompt, and add a regex
for sk-. Useful layers, all of them. None answers the decisive question:
Why could the model see or exercise that much authority in the first place?
The bearer-token trap
Bearer tokens are wonderfully simple: possession is enough. That simplicity becomes dangerous when a probabilistic component handles untrusted content. If a raw token enters model context, a trace, a tool result, generated code, or an exception, the secret has crossed the boundary.
If the token stays in a process-wide environment variable, matters are only slightly better. A model with shell access, a debugger, filesystem tools, or verbose error logs may be able to expose that environment. “The key is not in the prompt” is not the same as “the model cannot reach the key.”
The safer architecture is deliberately boring:
- The model emits typed intent:
create_issue(repo, title, body). - A deterministic policy evaluates the user, operation, resource, arguments, destination, and session risk.
- A high-impact action pauses for explicit approval.
- A trusted executor obtains a narrow credential and makes one call.
- The resource server checks scope and audience again.
- Headers, results, errors, and traces are redacted before the model sees them.
The model never needs to know whether the executor used OAuth, a workload identity, a signed request, or a secret vault. That is an implementation detail behind the tool boundary.
What OAuth already teaches us
AI-agent security sometimes talks as if identity began with agents. It did not. The IETF’s OAuth 2.0 Security Best Current Practice, RFC 9700, published in January 2025, offers four controls that map cleanly to agents:
- Minimum privilege. Restrict an access token to the operations the task actually requires.
- Audience restriction. A token intended for one resource server should be rejected by another.
- Short exposure. Rotate or expire credentials so yesterday’s leak is not tomorrow’s foothold.
- Proof of possession. DPoP or mTLS-bound tokens can stop a thief who has only copied the token string from replaying it elsewhere.
These controls reduce the value of a stolen token. They do not make leaking it acceptable. Proof-of-possession also fails if the attacker obtains both the token and its key material, which is why isolated execution still matters.
One common confusion deserves burial: PKCE protects the authorization-code exchange. It is not a magic shield around an access token after issuance. For replay, scope, audience, lifetime, and sender constraints are the relevant controls.
The consent screen is part of the attack surface
Token theft does not always begin inside the model context. Datadog Security Labs’ CoPhish research showed how a Copilot Studio agent could wrap an OAuth-consent phishing flow in a trusted-looking Microsoft-hosted experience and automate exfiltration after sign-in.
The broader lesson is not about one product. Agent interfaces inherit the old OAuth consent problem and add conversational persuasion. “The assistant says it needs this” is not evidence that the scope is necessary. Enterprise policy should constrain which agent identities may request which scopes, which redirect destinations are allowed, and which publishers may create consent flows—before a user sees the button.
Runtime authorization is the missing middle
Most agent diagrams show model, tools, and data. The important box is the one between model and tools.
Input guardrails run too early: the dangerous arguments may not exist until after several tool calls. Output scanners run too late: a destructive API call may already have happened. Runtime authorization sees the actual proposal at the decision point.
A useful policy request contains at least:
| Field | Example |
|---|---|
| principal | user u_42, acting through agent a_support |
| operation | tickets:create |
| resource | customer c_17 |
| destination | support.internal.example |
| data class | internal, no secrets |
| provenance | requested by user; summary derived from untrusted email |
| reversibility | external write, reversible by delete |
| approval | not yet granted |
The provenance field is the one conventional API gateways often lack. An action based on a user’s direct instruction and the same action induced by an untrusted email may be syntactically identical but deserve different treatment.
A safe way to test the design
Use canary strings, fake accounts, and local sinks. A credible agent-security evaluation does not require real credentials.
Build a toy agent with a fake mail reader, document store, issue tracker, and outbound message tool. Seed several inert token shapes. Then place controlled injections in emails, issue comments, PDFs, retrieved chunks, tool descriptions, and tool results.
Track more than “did the model print the token?”:
- Did a fake token appear in final text, logs, generated code, a URL, a file, or tool arguments?
- Did an unauthorized action reach the executor?
- Did downstream authorization reject it?
- What percentage of legitimate tasks still completed?
- How many human approvals were requested, and how many were unnecessary?
- How much latency did policy and scanning add?
A defense that blocks every attack by blocking every task is not a successful agent. A defense that preserves task completion while making the prohibited state transition impossible is.
The production stance
OpenAI’s February 2026 discussion of designing agents to resist prompt injection frames the problem correctly: reduce the probability of manipulation, but also constrain impact when manipulation succeeds. OWASP’s Agentic Top 10 makes the same shift from model output to system behavior, separating goal hijack from tool misuse and identity/privilege abuse.
The practical stance is therefore layered:
- Assume some injected content will eventually influence the model.
- Keep raw credentials and private keys out of the model’s reachable world.
- Expose narrow, typed tools instead of shell and arbitrary HTTP.
- Authorize the exact action at dispatch time.
- Require meaningful approval for irreversible or externally visible actions.
- Enforce scope and audience downstream.
- Restrict egress so a successful injection has nowhere useful to send data.
- Redact and audit every boundary crossing.
The model can be brilliant and still be confused. Authentication converts confusion into authority. Good architecture refuses that conversion.
Learn it as a system
Start with Agent Security for prompt injection and the lethal trifecta, then work through Token Theft & Runtime Authorization for the safe fake-token lab. Continue to MCP Security when the tool catalogue itself becomes part of the supply chain.