A chatbot that says something wrong is a content problem. An agent that acts on something wrong is a security problem, because it holds credentials, calls tools, and decides on its own what to do with text a stranger wrote. Nothing about that is unfamiliar to anyone who has secured a service account. What is new is that the thing holding the credential now reasons, and can be talked into changing its mind.
Most published advice about securing AI systems is really about the model's output: filters, refusals, red-team prompts. Useful for a chat product, and mostly beside the point for a fleet of agents doing work. An agent's damage does not arrive as a sentence. It arrives as a tool call: a write to a system of record, a transfer, a shell command, a request to an internal service with a credential attached.
That is good news, because a tool call is a boundary an engineer can defend the ordinary way. It can be identified, authorised, budgeted, rate-limited, journalled and rehearsed. The security question for an agent fleet is not what the model might say. It is which calls the agent can make, on whose authority, and what stops the one it should not have made.
Which puts most of this guide on familiar ground: identity, least privilege, blast radius, separation of duties, evidence. The controls are old. Only the actor is new.
Each of these is defensive: it describes what to detect and refuse on your own estate. Under each, the control that answers it.
An agent reads a page, a ticket or a document that contains instructions aimed at it, and the model treats them as a task. The prompt filter is the weak place to catch this; the tool boundary is the strong one.
An agent's own grants look modest, and its delegation chain reaches an identity that can do anything. Nobody drew that chain, so nobody saw it. This is OWASP's LLM06 in one sentence.
Tools arrive faster than registries. An agent ends up calling a server that no inventory lists, and a tool whose description silently changed after you approved it, which is the supply-chain gap a re-fetch-on-connect model opens.
A token handed to the model is a token in the trace, in the logs, in the memory store, and in whatever the model repeats next. Rotation does not help if the leak is structural.
No single blocked action is interesting. Twenty of them from one agent inside a day is a pattern, and it is invisible if each is only ever handled where it happened.
From the outside, an agent being driven by someone else and an agent stuck retrying are the same shape: sustained, fast, expensive. Waiting to tell them apart before reacting is how both get expensive.
A privileged agent with no attestation and no named owner is not a governance gap, it is an unrotatable credential with a personality. It is also the most common finding on a first scan.
A defence that was disabled in a config change six weeks ago behaves identically to one that is holding, right up until the day it matters.
One identifier, one owner, one runtime, one attestation method, and a delegation chain that is recorded rather than implied. Everything else in this guide depends on being able to name the actor. An agent that acts under a shared key is an incident you cannot investigate.
A system prompt asking the model not to do something is a request. A policy point that refuses the call is a control. Keep the list of forbidden actions short, explicit and enforced per call: shell execution, writes to systems of record, anything moving money. The model never gets a vote.
Not on everything, or people will click through it in a week. On the small set where a mistake is expensive and slow to reverse. The workable shape is a hold the agent can be told to wait for, with the grant proven by a signed token bound to that exact agent, run and tool set, so approving one action never quietly approves the next.
It is. Tools are added by the person who needed one, on the afternoon they needed it. The realistic control is not a stricter process, it is detection: notice the server nobody registered, notice the tool description that changed, notice the agent that can now reach both.
Every guardrail here is a claim, and a claim nobody tests decays. Fire the drills at a real gateway with a fake provider behind it: the meter that trips is real, the invoice is not. A defence that stopped working should fail a pull request, not an incident review.
Every decision, refusal, kill and approval journalled when it happens, each record carrying the hash of the one before it, so the chain is verifiable by somebody who does not trust you. Security work that cannot be shown is security work that will be repeated under worse conditions.
Everything here is defensive: it inspects, detects and refuses on your own estate. Nothing in the stack crafts adversarial prompts, manipulates another system's outputs, or attacks anything, and the drills are rehearsals fired at your own gateway with a fake provider behind it. Where we describe an attack, it is to say what to detect and what to stop, which is the only reason to name it.
Security, cost and control are one conversation held in three rooms. If you came here first, the other two are worth twenty minutes: AI agent governance and the runtime controls, and FinOps for AI, on spend that creates itself. The newest surface has its own guide: MCP security. All of the tools are Apache-2.0 and run on infrastructure you own, and one command starts the live services locally.
The actor reasons and can be talked into changing its mind, but the damage still arrives as a tool call: a write, a transfer, a shell command, a request carrying a credential. That makes the tool boundary the place to defend, with the same discipline as any service account: identity, least privilege, blast radius, evidence.
Not with a better prompt. Taint-track what came from outside the trust boundary and refuse the actions it reaches, at the policy point, per call. A system prompt asking the model not to do something is a request; a decision point that denies the call is a control.
OWASP's LLM06: an agent that reaches admin-equivalent power through its delegation chain rather than through its own grants. Its own permissions look modest, and two hops away it can do anything. Finding it needs the chain drawn as a graph, because no permission list on a single identity will show it.
Correlate rather than count. A single blocked action is noise; a stream of blocked actions from one identity inside a day is a pattern, and severity should rise with repetition and with the privilege of the identity doing it.
Rehearse them in CI against a real gateway with a fake provider behind it, so the meter that trips is real and the invoice is not. And refuse to count an unconfigured feature as a pass: a guardrail that is switched off looks exactly like one that is broken.