Your audit log says the service account did it
AI agents act with human credentials and leave a record that cannot answer the only question that matters. Ory Agent Security closes the gap.

AI agents act with human credentials and leave a record that cannot answer the only question that matters. Ory Agent Security closes the gap.

Picture the post-incident review. A production table was truncated at 02:14. You have the audit log, and the audit log is complete. It says svc-ci-bot did it, from a container that no longer exists, using a token that expired eleven hours ago.
Now answer the questions your auditor, your customer, and your board will ask, in that order.
You cannot answer any of them. Not because your logging is bad, but because the thing that acted was not the thing your identity system knows about. An AI coding agent ran a command on behalf of an engineer, using a credential that describes neither of them.
This is the accountability gap, and it is not a future problem. It is in your organization right now, in every terminal where someone typed claude, codex, or gemini this week.
Automation is not new. Your CI system has been running commands with a service account for a decade, and that was fine, because CI was deterministic. A pipeline did what its YAML said. The service account's permissions and the program's behavior were the same statement written twice, so attributing an action to the account was as good as attributing it to a person's decision to merge.
An AI agent breaks that equivalence. It decides what to do next at runtime, from a natural-language instruction, in a loop, with a shell. The same agent, the same credential, and the same repository produce a file edit on Monday and an outbound network call on Tuesday. The credential no longer predicts the behavior, which means the credential no longer explains the behavior either.
Three specific things fail as a result.
Attribution fails. The agent holds a credential that represents a machine, or worse, it borrows a human's. Either way, the record loses the delegation: that a particular person set a particular agent running with a particular instruction. And it loses it permanently — tokens expire, containers are reclaimed, and the link between "Alice asked for a refactor" and "something dropped a table" is gone by the time anyone goes looking.
Authorization is the wrong shape. Access control was designed around resources: this identity may read that bucket. An agent's risk surface is not resources, it is capabilities — may this thing run a shell, fetch a URL, edit a file, invoke that MCP tool. Most organizations grant an agent everything the developer has and hope the prompt is polite, because the alternative is having no controls at all.
Revocation has no target. When one run goes wrong, the only lever available is usually the credential itself, which stops every agent on that credential for everyone. That is a fire alarm, not a control. Nobody pulls it, so nothing gets contained, and the review concludes with a recommendation to be more careful.
The strategic cost of this is not the breach scenario. It is the paralysis. Security teams that cannot describe agent behavior in the terms their controls are written in have exactly two options: ban the tools and watch them get used anyway, or permit them and own the consequences without visibility. Both are bad, and the second is the one most organizations have quietly chosen.
Ory Agent Security is now generally available. It gives an AI agent an identity, puts a permission check in front of every gated tool call, and records the delegation so the chain survives the credentials involved.
The model rests on one distinction that most agent-security proposals miss.
There are two principals in every agent action, not one. There is the human who set it running, and there is the AI process doing the running. Both are real, both are authenticated, and neither substitutes for the other. The human is established by an interactive OAuth 2.0 sign-in with PKCE — the same standard flow you already trust for your applications — and is the subject of the question: May this person use this capability? The agent is established as a distinct OAuth 2.0 client registered to the project, and its bearer authenticates every call the agent makes to Ory. That is what makes the audit record read agent X acting on behalf of user Y rather than a token did something.
Authorization targets identities that already exist. This is the design principle that makes the whole thing operable, and it is worth stating plainly, because getting it wrong is what makes competing approaches unusable:
A grantable identity must outlive the thing it grants for. An admin cannot pre-authorize a session that does not exist yet, so the session cannot be the level grants attach to.
So the things your administrators provision against are durable: the person (in practice, a shared role their identity belongs to) and the installation — this harness, on this host, in this project, which exists from the moment someone installs the plugin until they remove it. Individual runs and individual sub-agent spawns are identified on top of those stable identities rather than by minting new credentials, so nothing accumulates on your project. A laptop running two harnesses, where one of them has spawned two kinds of sub-agent, holds four registered clients — whether it has run three sessions or three thousand.
Blocks can aim at any level. Grants go to durable identities; denials go wherever the situation calls for. Block a capability for an entire installation, for one running session, or for a single class of sub-agent:
block AgentTool:Bash → this install # stop this harness using the shell
block AgentTool:Bash → one running session # stop a runaway run; everyone else keeps working
block AgentTool:WebFetch → all "Explore" sub-agents # a whole class, pre-emptively
A block beats a grant, including a grant inherited through a group. That is enforced in the permission model itself rather than in application logic, so there is no ordering subtlety and no code path that can get it wrong.
A control that breaks developer workflows on day one does not get adopted; it gets disabled, and then you are worse off than before because you also believe you have coverage. Agent Security is built around two decisions that exist specifically to prevent that.
It starts in observe mode. Out of the box, a denied permission is recorded and the tool runs anyway. Nothing breaks on install. What you get immediately is the thing you did not have: a complete record of what would have been blocked. That is your discovery phase, and it produces the actual list of capabilities your engineers use — not the list they said they use, and not the list you guessed. When you promote a project to enforce, you are promoting against evidence.
Two things to know before you promote. Grant your engineers the harness's built-in tool catalog first, or enforce denies everything at once. And a shell command that cannot be resolved statically — a dynamic program name, an unparseable fragment — is denied under enforce rather than allowed, which is the right default and also the most likely source of a surprise. Observe mode surfaces both of these before they can bite.
The posture is set on the project, not the machine. Observe and enforce are properties of the Ory project, read at runtime. There is no local override and no environment variable a developer can flip. Your administrators own the posture; the plugin reads it and obeys it, and a change made in the Console is picked up inside a running session.
There is a third decision that matters more to adoption than either of those, and it is organizational rather than technical. Installing the plugin requires no privilege on your Ory workspace. The plugin holds no administrative credential and has no surface for writing grants, blocks, or posture at all. It needs a project URL and a public OAuth client ID — the same two things a mobile app would need. Everything that governs behavior is configured in the Console by the people who should be configuring it.
That inversion is why this can actually roll out. Developers install a tool; administrators set policy. Neither has to wait for the other, and no one has to hand out workspace access to make the security control work.
Every gated tool call produces a structured trace span. Spans go to a local file, to any OTLP-compatible collector, or both — OpenTelemetry Collector, Jaeger, Grafana Tempo, and the commercial backends all take them without a translation layer. There is no proprietary format to maintain.
What a span carries is the material for the questions you could not answer earlier: which human, which agent, which tool, what the decision was, and — when it was a denial — whether the subject lacked a grant or was explicitly blocked, and which principal the block landed on. Plus the workspace context that makes it correlatable: host, working directory, git branch and commit, plugin version, session. Spans within a session share a trace ID, and if the agent runs inside a larger distributed trace, its activity stitches into that parent trace.
What a span deliberately does not carry is the content. Raw command strings, file contents, request bodies, full URLs, and tool outputs never appear in spans. They are summarized — byte counts, truncated hashes, a file path without its contents, a URL's host without its path or query. Raw shell commands stay inside the agent's process boundary and never reach an exporter, because a command line is one of the likeliest places in a developer workflow for a secret to appear.
This is a boundary worth understanding before your privacy review asks about it. The trail is designed to answer who did what and was it allowed, and designed not to become a secondary repository of your source code and credentials. Both halves of that are intentional.
Not everything is gated, either, and that is also deliberate. An agent's user-interaction primitives — asking the operator a question, updating a plan — are traced and passed straight through. Gating a prompt for human input protects nothing and breaks the tool.
One finding from building this is worth passing on, because it undermines most first-attempt agent controls, including ones you may already have.
Authorizing on tool name alone leaves a hole. If you deny an agent's web-fetch tool but allow its shell, you have denied nothing — bash -c "curl …" reaches the same place. A capability list that gates named tools while leaving a general-purpose shell open is a list of suggestions.
Ory Agent Security parses the shell command and checks each program and built-in it will actually execute as its own permission, following pipelines, conditionals, command substitution, and wrapper commands like sudo and xargs. So curl can be blocked while bash stays available, and a denial names the specific word that caused it. In observe mode, every un-granted word is logged, which means the discovery phase tells you not just which tools your engineers use but which binaries.
The honest boundary of today's model: it checks what runs, not what each program is asked to do with its arguments. Distinguishing a read from a write inside a single invocation is on the roadmap, not in the product. Plan your controls at the level of "may this agent reach a database at all" not "may it reach it read-only".
Ory Agent Security is generally available today, configured from the Ory Console. It works with eleven coding-agent harnesses — Claude Code, Codex, Cursor, Gemini CLI, OpenCode, OpenClaw, Continue, Goose, Cline, Amp, Pi, and Google Antigravity — and with fourteen agent SDK integrations for the agents your own teams are building, across Python and TypeScript. It is one package per harness and one small import per SDK, on a shared core published under Apache 2.0.
Two questions are worth taking to your own organization this week, whatever you do about them.
The first: if an AI agent took a destructive action in your environment tomorrow, what would your audit log say, and could you name the human who set it running? If the honest answer involves a service account, you have the gap.
The second: how many agents are running in your organization right now? Not how many are approved. How many are running. Most teams find that the number they can observe and the number that exists differ by an order of magnitude, and the observable ones are not the interesting ones.
Identity is how every other version of this problem got solved. Human access, service-to-service traffic, third-party integrations — each one became manageable at the point it became an identity with permissions and a record, rather than a credential with a hope. Agents are the same problem arriving faster, and they are the first version of it where the actor decides for itself what to do next.
That is the part that makes identity non-optional rather than merely advisable.
Start here: open Agent Security in the Ory Console, install a plugin, and run a week in observe mode before you decide anything. The evidence it produces is the best argument for whatever you do next.