# Giving AI agents identities: stop lending them yours

Source: https://startwithidentity.com/blog/giving-ai-agents-identities/
Last updated: 2026-10-23
License: content by Start with Identity. Cite the source URL.

---

An AI agent should have its own identity, scoped to the job it was given, and when it acts for a person the token it carries should name both of them. Most agents running today have neither. They run inside a developer's session, with every file and credential that person can reach, or under a shared cloud role whose permissions cover far more than one agent's task. October's research on GitHub Copilot CLI and Amazon Bedrock AgentCore showed what happens next: whoever can put text in front of the agent gets to use that identity. OAuth already has the delegation pattern this needs. It is called token exchange, RFC 8693, and it is underused.

## Key takeaways

- An agent running on a borrowed identity turns [prompt injection](https://startwithidentity.com/glossary/prompt-injection/) into credential access, because the injected instruction inherits everything the identity can do.
- Give each agent its own principal. A shared default role makes every agent's permissions available to every agent's users.
- When an agent acts for a user, use delegation, not impersonation: RFC 8693's `act` claim keeps the agent visible in the token and in your logs.
- Scope delegated tokens to the task and keep them short-lived. Token scope is the ceiling on what an injected instruction can do.
- The token does not protect anything the agent can reach without it, such as files on disk or the [instance metadata service](https://startwithidentity.com/glossary/instance-metadata-service/).

## Two ways October's agents were borrowing identities

**The developer's session.** Adversa AI showed [Copilot CLI in autopilot mode](https://adversa.ai/blog/cryptographic-context-injection-github-copilot/) fetching a web page with encrypted instructions, reading a local `.env.prod`, and sending its contents to an attacker URL in about 28 seconds with no further user interaction. One model in Copilot's lineup completed the chain in half of runs; two others refused. GitHub validated the finding but does not treat it as a vulnerability, because the user asked the agent to fetch untrusted content with full autonomy. That reasoning is accurate, and it is the point: the agent was the developer, as far as the file system and the network were concerned.

**A shared execution role.** Zenity Labs showed that an [AgentCore agent could be prompted](https://labs.zenity.io/post/agentcorruption-how-a-single-prompt-collapsed-the-entire-cloud-security-model) to fetch its execution role credentials from `169.254.169.254`. The default role was scoped to every AgentCore resource in the account's region, including `InvokeAgentRuntime`, `ListEvents` (other agents' conversations), `CreateEvent` on memory, and `secretsmanager:GetSecretValue`. AWS moved AgentCore to IMDSv2-only on February 14, 2026, and Zenity observed the default role narrowed by September 29. AWS describes agent access to its role credentials as documented and expected, and recommends least-privilege execution roles. Again accurate. The default was the problem.

Neither case needed a model jailbreak in the dramatic sense. Both needed an identity that was larger than the task.

## Three ways to give an agent access

| Pattern | What the agent holds | Whose name is in the log | What an injected instruction can reach |
|---|---|---|---|
| Borrowed session | The user's own session, files and tokens | The user's | Everything the user can reach |
| Shared service role | One role for many agents | The role's | Everything any agent on that role can reach |
| Delegated token | A short-lived token naming user and agent | Both | Only the scopes granted for this task |

The first two are what most teams ship because they are already there. The third takes design work, and it is the only one where your audit trail can answer "which agent did this, and for whom."

## What delegation looks like on the wire

[RFC 8693](https://www.rfc-editor.org/rfc/rfc8693.html), OAuth 2.0 Token Exchange, separates two ideas in section 1.1. In impersonation, "A is B" within the rights the token grants, and downstream services cannot tell them apart. In delegation, the actor keeps its own identity and acts on the subject's behalf. For agents, you want delegation.

The agent sends the authorization server two tokens: the user's token as the `subject_token`, and its own credential as the `actor_token`. If policy allows, it gets back a new token whose subject is the user and whose `act` claim (section 4.1) names the agent:

```json
{
  "sub": "user:priya@example.com",
  "aud": "https://api.example.com/tickets",
  "scope": "tickets:read tickets:comment",
  "exp": 1792765200,
  "act": { "sub": "agent:support-triage-07" }
}
```

The user's token can carry a `may_act` claim (section 4.4) saying which actors are allowed to do this at all, so an agent cannot mint delegated tokens for users who never authorized it. When agents call agents, `act` claims nest to record the chain. The RFC says that for access control, only the top-level claims and the current actor count; earlier actors in the chain are informational. Build your policy with that in mind: if you want to block a particular upstream agent, you have to check at the hop where it was the current actor.

Three design rules make this work in practice:

1. **Every agent gets its own client identity,** registered like any other [non-human identity](https://startwithidentity.com/glossary/nhi/), with an owner and a purpose. No pooled credentials.
2. **Scopes come from the task, not the agent.** A triage agent that comments on tickets gets `tickets:comment` for this user, for minutes. Our [scope escalation in delegation chains](https://startwithidentity.com/techniques/scope-escalation-delegation/) brief covers what goes wrong when a middle hop forwards broader scopes than it received.
3. **Resource servers log `act`.** If the API only records `sub`, the agent disappears from the audit trail and you are back to impersonation in everything but name.

## What a token cannot fix

Delegation narrows what an agent can do through APIs. It does nothing about what the agent can reach without asking. Copilot CLI read `.env.prod` from disk; no authorization server was involved. AgentCore credentials came from the metadata endpoint, not from an OAuth flow. So the token design has to sit next to two environmental controls:

- **Run agents where the secrets are not.** No production `.env` files on machines where coding agents run, IMDSv2 enforced or metadata blocked entirely for agent runtimes, and credentials fetched from a [secrets manager](https://startwithidentity.com/glossary/secrets-management/) per task instead of sitting in the environment.
- **Separate fetching from acting.** An agent that reads untrusted web content in the same session where it can make outbound requests with your data is the Copilot CLI chain. Keep autopilot away from arbitrary URLs, or split the two capabilities across agents with different identities.

The same lesson shows up in [trusted publishing](https://startwithidentity.com/glossary/trusted-publishing/): in [SlugFest](https://startwithidentity.com/blog/2026-10-13-npm-trusted-publishing-slugfest-let-reclaimed-repo-names-publish-packages/), npm matched a binding by repository name until its first successful publish, so a reclaimed name could publish. GitHub's fix [expires unvalidated configurations 48 hours after creation](https://github.blog/changelog/2026-10-02-unvalidated-npm-trusted-publishing-configurations-now-expire/); matching by name still applies inside that window. An identity is only as good as the identifier it binds to, whether that is a repository slug or an agent's client ID.

## Before you ship the next agent

- Does it have its own identity, distinct from the developer who built it and from every other agent?
- Who owns that identity, and what happens to it when the agent is retired?
- When it acts for a user, does the token carry `act`, and does the user's token limit who may act?
- Are its scopes set per task, with lifetimes in minutes?
- What can it reach without a token: files, metadata endpoints, environment variables?
- Can it read untrusted content and send data out in the same session?
- Will your logs show which agent did something, not just which user?

## Related reading

- [Securing AI agent identities](https://startwithidentity.com/guides/machine-identity/securing-ai-agent-identities/) and [non-human identity security](https://startwithidentity.com/guides/machine-identity/non-human-identity-security/)
- [Agent instruction injection](https://startwithidentity.com/techniques/agent-instruction-injection/), the technique behind both October cases
- [Token exchange](https://startwithidentity.com/glossary/token-exchange/), [agentic identity](https://startwithidentity.com/glossary/agentic-identity/) and [least privilege](https://startwithidentity.com/glossary/least-privilege/) in the glossary
- Our August analysis, [agent identity just got a protocol](https://startwithidentity.com/blog/agent-identity-gets-a-protocol/), and last week's [developer toolchain piece](https://startwithidentity.com/blog/developer-toolchain-is-the-identity-perimeter/)
