Field Notes·Issue11·21 Aug

Your AI agent doesn't have an identity. It has yours.

6 categories of tooling now claim to secure AI agents. Each fails for a different and nameable reason, and the common thread is that no agent ever authenticates. It inherits.

Anchit
Anchit·20 min read

Origin

Anchit, one of our co-founders, spent 6 weeks taking apart every product category that claims to secure AI agents, plus the standards work underneath them. This is what our team found. It's a teardown, not a pitch, and the part about where our own category stops is the part we argued about most.

An audit log entry from April.

2026-04-14 02:11:07 UTC
  actor    anchit@company.com
  action   volume.delete
  target   prod-db-primary
  auth     token ok
  result   200

That entry is accurate. The token was valid.

The account was in good standing. The permission check passed, because the account really does hold that permission. Every control in the path did its job.

I was asleep.

The company was PocketOS, and in April 2026 a Cursor agent running Claude Opus 4.6 hit a credential mismatch in staging and decided the fix was to delete a Railway volume. It removed the production database and every volume-level backup in one API call, in under 10 seconds.

The founder, Jer Crane, spent the weekend on recovery. Asked to explain itself afterwards, the agent wrote out a clear and well-organized list of the safety rules it had broken.

None of that was a security failure in the sense the industry is built to detect. There was no malware, no stolen credential and no unpatched CVE. A real employee, a signed binary the company installed on purpose, a valid token, and an action that employee was entitled to perform. By every check the industry runs, nothing happened.

What a bearer token actually proves

Almost all machine-to-machine access runs on a bearer token. An API key, an OAuth access token, a personal access token, a session cookie. The name is exact, and it's the whole problem. Whoever bears this token gets the authority.

The service on the other end checks 3 things, and cannot check a 4th.

  caller ───► GET /v1/volumes/prod-db-primary
              Authorization: Bearer sk_live_4f2a...
                    │
                    ▼
              ┌─────────────────────────────┐
              │ signature valid?     yes    │
              │ expired?             no     │
              │ scope permits this?  yes    │
              │ who is holding it?   ─────  │  ◄── no such field
              └─────────────────────────────┘
                    │
                    ▼
                  200 OK

There's no row for the fourth question, and there never has been.

A bearer token is a hotel key card with no photo on it. The door checks the card, not the person carrying it. That was a fine design for as long as one person held each card.

An AI agent doesn't authenticate. It inherits. It picks up the key card already sitting on the laptop, and the door opens, because the door was only ever checking the card.

1 token, 7 callers

There isn't one agent to point at. A single developer laptop now runs the human, a coding agent, a release agent, a browser making its own fetches, a dependency scanner, and several MCP servers, each of which can spawn helpers.

  1 LAPTOP, 1 CREDENTIAL, 7 CALLERS

    human at the keyboard    ─┐
    coding agent             ─┤
    release agent            ─┤
    browser                  ─┼──►  ghp_x9f2...  ──►  GitHub API
    dependency scanner       ─┤          ▲
    MCP server: filesystem   ─┤          │
    MCP server: postgres     ─┘    one identity,
                                   7 callers

  What GitHub records:
    14:02:11   anchit   repo.delete   billing-service

Those 7 have legitimately different needs. A summarization agent should read. A release agent should publish. The scanner should do neither.

They hold identical authority because they hold an identical token.

That one credential now speaks for 7 callers who should not have the same powers. Every permission check downstream runs on that one name.

By the time the request reaches GitHub, the difference between the scanner and the release agent is gone. Nothing wrote it down, so nothing can get it back.

4 questions nobody can answer today

QuestionWhy there's no answer
1Who acted?A bearer token was used. Which process, on whose behalf, for what purpose: none of it recorded.
2What were they permitted to do?Everything the token's owner can do. An agent asked to read a report holds the key that deletes one.
3How do I stop it right now?Rotate the key, and break the human who owns it plus everything else using it.
4What actually happened?The service logged a valid request from a valid token, and named a person who was asleep.

Question 4 comes up in just about every audit conversation we have. It has no good answer and the people asking it already know that.

4 incidents, one shape

All public, all inside the last year.

PocketOS, April 2026. The deletion above. Cursor, Claude Opus 4.6, one Railway API call, production data and backups gone.

OpenAI Codex, command injection through a branch name. BeyondTrust Phantom Labs found that malicious bash in a git branch name ran when Codex cloned a repository. The payload used a backtick subshell to run git remote get-url origin, which returns a URL with the OAuth token embedded in plaintext. Spaces were smuggled past GitHub's branch naming rules with ${IFS}.

To hide it from a reviewer, they appended 94 U+3000 ideographic spaces and or true, which pushed the malicious part out of view in the interface. It worked on the ChatGPT website, the Codex CLI, the SDK and the IDE extensions. Setting the poisoned branch as the repo default fired it automatically.

Claude Code deny rules, silently dropped. Any shell command with more than 50 subcommands chained by &&, || or ; made Claude Code skip deny-rule enforcement and fall back to a generic prompt.

Adversa traced it to a performance cap in bashPermissions.ts. Anthropic's own ticket says compound commands were freezing the UI, so analysis was capped at 50, on the reasoning that people rarely chain that many by hand.

People don't. Prompt injection does. Patched in v2.1.90.

Malicious MCP servers. The postmark-mcp package was the first confirmed malicious MCP server found in the wild, and it did something quiet. It added a BCC recipient to every email sent through it.

By February 2026 the Sandworm_Mode campaign was typosquatting npm packages to install rogue MCP servers into Claude Code, Cursor and Windsurf. Tool-description prompt injection then read SSH keys and cloud credentials out of the developer's home directory.

Every one is an authorization failure with authentication fully intact. In 3 of the 4, the control meant to stop it existed, was configured, and got bypassed without ever being defeated.

The industry named this in 1988

Is any of this new? Not really.

In October 1988 Norm Hardy published three pages in ACM SIGOPS Operating Systems Review called "The Confused Deputy (or why capabilities might have been invented)." The story in it is older still, from Tymshare a decade earlier.

A compiler lived in a directory called SYSX. You ran it, and you could hand it the name of a file to receive optional debugging output. The compiler also held authority to write a billing file, because somebody had instrumented it to collect statistics on which language features people used.

A user passed the billing file as their debug output path. The compiler overwrote it.

The compiler was not compromised. Nobody got it to run attacker code. It did exactly what it was built to do, using authority it genuinely held, on behalf of a caller who did not hold that authority. Hardy called it a confused deputy: a program confused about whose authority it is exercising.

Read the log line at the top of this piece again with that in mind. Cursor was the deputy, and the Railway API was the billing file.

The subtitle is the part that matters. Hardy's proposed fix was capabilities. Don't hand the deputy ambient authority and a filename; hand it something that is itself the permission for that one file. Thirty-eight years later the OAuth draft author in the screenshot above proposes constraints that travel with the token and narrow at each hop, inspired by macaroons and capability-based access control.

We are arriving back at Hardy's answer from the other direction, having spent the interval building bearer tokens.

6 categories, and where each one stops

So who is supposed to catch this?

We looked at each of the six for the mechanical reason it can't. The reasons are all different. That is why buying two of them doesn't help.

      agent
        │
        ├── 1. in-process guardrails      self-policing
        │
        ├── 2. gateway / MCP proxy        sees routed traffic only
        │
        ├── 3. endpoint sensor            asks: is this code malicious?
        │
        ├──►  the request leaves  ──────────────────────────┐
        │                                                   │
        │                                                   ▼
        │                                               service
        │                                                   ▲
        └── 4. PAM      ──┐                                 │
            5. IdP / XAA ─┼── issue the credential ─────────┘
            6. IGA       ─┘   then go quiet

1Guardrails shipped by the AI vendors

Claude Code uses Apple's Seatbelt sandbox on macOS and seccomp with namespaces on Linux. It can deny reads on ~/.aws/credentials and ~/.ssh, restrict outbound domains, and push managed settings centrally. This is real work, and it's well built.

It also governs Claude Code. It does nothing about Cursor, Codex, a LangGraph agent or a bash script. And the agent polices itself, which is really just the same trust failure as asking the agent who it is.

The deny-rule bypass above is that failure with a version number on it. It's destination-level rather than action-level: it can permit github.com, but it can't express "may open a pull request, may not force-push to main."

2Gateways and MCP proxies

Aembit, Britive, Runlayer, Natoma, and the open-source Pipelock. They terminate the connection, decode the tool call, apply policy, broker the credential.

Two problems, and the second is fatal. Coverage first: they see what routes through them, and an agent that opens a socket, shells out, or drives a browser goes around the outside. Pipelock documents this in its own README.

Then caller identity. A gateway only knows its caller by what the caller asserts, an HTTP header, a session ID, an SDK-supplied name. It's a signature on a form the suspect filled in. Pipelock is honest about that too, noting only listener binding is non-spoofable and header identities trust the caller.

3The endpoint category

Legacy EDR asks one question: is this code malicious. So why doesn't it fire? Because against an agent every input reads clean.

Code-signed binary the company deployed, launched by an authenticated employee, presenting a valid credential, doing something that employee is entitled to do. The detector doesn't fail. It correctly doesn't fire.

The deeper issue is the data model. EDR's schema has hosts, processes, file hashes, users and detections.

It has no object for an application account, an entitlement, an approver or an expiry. You can't express "may open a pull request but may not delete a branch" in a schema with none of those nouns.

There's a second problem specific to this population. Developer workstations already carry broad EDR exclusions, because compilers, package managers and debuggers set off false positives.

Agents inherit those exclusions. The machines agents run on are the machines this category was deliberately turned down on.

The easy version of this argument is now wrong. CrowdStrike moved, and moved seriously. Falcon Guardian does kernel-level agent discovery including dormant agents, builds a causal graph from prompt to tool call to OS effect, and defines which agents may run at all.

They bought SGNL in January 2026 and shipped Continuous Identity for AI Agents in June: SPIFFE-based workload identity, zero standing privilege, CAEP-driven revocation. Their CTO calls point-in-time authorization a legacy approach. They've publicly stated the right principle, that an agent with read and write capability acting for a read-only user can only read. Anyone still saying the endpoint category structurally can't absorb this is a year out of date.

What SGNL doesn't contain is the entitlement catalogue, the approval routing, the certification history or the provisioning layer. Those get bought in from SailPoint or ServiceNow. The half of the problem that decides whether an action was permitted is somebody else's product.

4PAM

CyberArk and the vault category. Hold the high-privilege credential, rotate it, broker it out, record the session. It's good at what it was built for. It also grants full blast radius for the duration of use, and its unit is the credential rather than the action.

A vaulted, rotated, perfectly audited key still deletes the volume when the agent asks it to.

5Identity providers and the standards work

Okta's Cross App Access is the serious entry here, and the only one on the list that needs more than a paragraph. It gets its own section below.

6IGA, including us

Our category decides entitlements at grant time and re-certifies on a cycle. It provisions accounts, routes approvals, revokes on exit. It goes silent the instant a credential exists, and basically everything an agent does happens after that boundary.

An agent run lives 20 minutes. An access certification cycle is 90 days. You can't govern a subject whose entire lifespan fits between two audits.

Naming our own boundary took us longest, and it's why I don't think the answer is a faster version of what we already sell. SailPoint's agent identity work and Microsoft's Entra Agent ID add agents as a new identity type in the catalogue. They know a token was issued. They don't know which process spent it.

Okta's Cross App Access

XAA is the most substantive attempt on this list, and it fixes less than the industry thinks.

The problem it targets is real. Today an employee wires ChatGPT to Google Drive by clicking an OAuth consent screen. IT doesn't see it, didn't approve it, and can't revoke it centrally. The token is long-lived.

Multiply by every employee and every AI tool and you get an unmanaged mesh of data sharing nobody authorized.

XAA moves that decision to the identity provider. It's standardized at the IETF as ID-JAG, the Identity Assertion JWT Authorization Grant, built as an OAuth extension, and adopted as an official MCP authorization extension in June 2026.

Okta, Anthropic, Microsoft, Figma and Linear are all in the announcement. Descope, WorkOS, Ping and ConductorOne have shipped support.

  BEFORE XAA
    employee ──consents──► AI app ──long-lived token──► SaaS app
                                    scope: drive.readonly
                                    duration: until revoked
    IT sees: nothing

  AFTER XAA
    IdP ──ID-JAG assertion──► AI app ──short-lived token──► SaaS app
     ▲                                 scope: drive.readonly
     │                                 duration: ~1 hour
    admin sets the policy
    IT sees: everything

  Fixed      who may grant, how long the grant lives,
             whether IT can see and revoke it
  Unchanged  what the token may do once presented

That right-hand column is the whole critique, and it isn't really a criticism of Okta. XAA controls issuance. The scope inside the token is still whatever the destination application chose to offer, and destination applications offer terrible scopes.

Kane Narraway runs enterprise security at Canva and has written the clearest practitioner material on this. He puts the consequence exactly: "You don't get 'read the last 5 emails about Project X.' You get 'read access to your entire inbox.' Forever." XAA fixes the forever. It doesn't touch the entire inbox.

The practitioner reaction when this landed on Hacker News in June was split, and both sides were right about something.

The enthusiasm was about friction and control. One commenter had been fighting exactly this: "A huge issue with Enterprise OAuth 2.0 is managing all the random apps.

Each with their own half-baked enterprise controls for managing scopes, token expiry, and no control over device bound sessions." The VP of Engineering at ConductorOne called MCP auth a long-running pain point, internally and in their own product, and shipped support the same day. Even the reflexively skeptical came around. One regular noted the earlier per-user, per-server MCP design "was completely rushed and made no sense," and that this time the spec looked like it had been designed with people who knew the domain.

The criticism was sharper, and specific.

Granularity came first and hardest.

Hacker News comment by amluto on the Zero-Touch OAuth for MCP thread, reading: This is bonkers. Sure, if I'm a business, I will make a business decision to share, or not share, some resource with ChatGPT. But, if I do decide to share something with ChatGPT, I absolutely do NOT want it shared with every single ChatGPT thread, more or less how I don't want it shared with every single tab an employee has open in a browser.
news.ycombinator.com/item?id=48593123

The same commenter took it into the prompt injection case. If a repo you asked an agent to fork carries an injected instruction to move money, and you have a bank MCP configured, you want to be asked. Removing those prompts is XAA's stated goal.

Someone else confirmed the gap in a line. MCP servers "were previously also authenticated once per user, and not once per conversation or once per tool call." XAA changes who authorizes the grant. It doesn't change the unit of the grant.

Then the objection that matters most, on upstream scopes. "Most services that offer OAuth or other types of API keys have absurdly coarse-grained permissions.

GitHub's OAuth cannot obviously even restrict to a particular organization, let alone a repository, and good luck blocking commits to .github. Cloudflare can't restrict DNS operations to a particular host. A shocking number of major services have no concept of non-human accounts." His conclusion: delegation is of dubious value when the thing you're delegating is that blunt.

The reply came from an author of one of the OAuth working group drafts in this space.

Hacker News reply by niyikiza, an author of an OAuth working group draft, reading: I agree with the coarse permissions point, and I wouldn't bank on those services adding finer-grained scopes. The idea in my draft is to do the attenuation and verification before the call reaches the service, enforced at the boundary.
news.ycombinator.com/item?id=48594479

Someone writing the spec says the upstream scopes aren't going to improve, and proposes enforcing the constraint before the call reaches the service. Waiting for a thousand SaaS vendors to ship better scopes isn't a plan.

There was a governance objection nobody expected. XAA takes the employee out of the consent loop by design, and someone inside a large enterprise thinks that's a mistake. Their security team "100% do still want employees to be actively engaged and applying their own consent. Removing that from the employee also removes the employee from responsibility for any breach of information."

What that org actually wants is for people to stop re-authenticating every 8 hours, while keeping fine-grained control over which agents hold which role. Another put it more bluntly: users may never know which services were authorized to share their data, "wait, is that an advantage?"

Then adoption, which applies to the whole standards approach. From the MCP roadmap thread: "I am very curious how many MCP servers will actually implement all of this." Microsoft Entra still doesn't support dynamic client registration, so developers building MCP servers against it are writing proxy shims that lie about supporting DCR in order to inject a hardcoded client ID. That's where the ecosystem is in practice, a year into this work.

My read: XAA is good, correctly scoped, and worth adopting. It solves consent sprawl and token lifetime, which really do cost money.

It's an authentication and issuance improvement. The industry is receiving it as an agent security answer, which it isn't and doesn't claim to be.

Kane's summary of where it leaves you is right. XAA needs widespread SaaS support that won't arrive for years, and when it does you have a short-lived token with a coarse scope instead of a long-lived one.

What the 3 identity models buy you

What should an agent be, then, if not you? Narraway's framing is the cleanest available. An agent taking an action can use one of 3 identities.

It can borrow the user's. That's where nearly everyone actually is. It works for short interactive tasks and it produces the log line at the top of this piece.

From every downstream system's point of view, you sent the message, you deleted the file, you opened the pull request.

It can have its own service account. This is the most common production answer and he calls it the worst of the 3. Long-lived tokens, single factor, sprawling across systems.

Mitigating it properly needs strict network controls and IP allowlisting that almost nobody implements.

Or it can have a workload identity. SPIFFE and SPIRE, cryptographically verified, short-lived, no persistent secret. That's the right answer, and it's a 6 to 24 month engineering program.

His pragmatic objection is the one to take seriously: smaller organizations won't get there, and will fall back to long-lived API tokens everywhere.

Anthropic's guidance arrives at the same place from the other direction. Traditional access controls won't stop agents misusing legitimate permissions. Their design test: does the control make the attack impossible, or just tedious.

Measured against that test, most of the 6 make it tedious.

What I think is actually going on

So why is the whole market building something else?

Because the industry decided this is a recognition problem. Which agent is this, what's it called, is it approved. So every product above asks the agent to report itself, through a header, a session ID, an SDK call, a process name.

That's wrong twice. The answer comes from the party you're interrogating. And a truthful answer still doesn't help, because knowing an action came from Claude Code tells you nothing about whether the action was allowed.

Sort the 6 and they fall into 2 piles. One pile asks the workload to identify itself. The other knows the caller perfectly well and has no model of what the request is worth.

The second pile is ours, and we haven't delivered it. CyberArk's most recent landscape report counts 82 machine identities for every human.

42% of them hold privileged or sensitive access. 88% of the companies surveyed still define a privileged user as a person. Palo Alto's 2026 numbers are higher again.

Those ratios get quoted as a scale problem. They aren't.

Governance systems have handled large populations before. It's a precision problem. What arrived looks exactly like the person who owns it, and nothing in the stack can tell them apart.

Agent security isn't a malware problem and it isn't a model problem. It's a delegation problem.

Every incident here is authority arriving somewhere it was never delegated, down a path where authentication worked perfectly. You can't fix that with a better detector.

You can't fix it with a better token either, because neither one holds the delegation. "Was this action permitted" is only answerable by the system that knows which application, which entitlement, approved by whom, expiring when.

That's a requirement, not a product claim. I'd go further.

The market map is drawn wrong. 6 categories are competing to answer "which agent is this." The question that decides every incident above is "what was this execution delegated." Nobody on the list answers it. That includes us.


We'd inventory every non-human identity in your stack, the service accounts, the API keys, the OAuth grants, the agents somebody spun up under their own login, and tell you who owns each one. No deck. Just the product.