III.1III · The agent loopconcept
Anatomy of an agent - model, tools, memory, loop
An agent is four moving parts - a model that decides, tools that act, memory that persists, and a loop that repeats - and nearly every agentic security failure is one of those four parts treating attacker-controlled text as if the operator had written it.
Anthropic’s working definition is the one worth adopting: agents are “systems where LLMs dynamically direct their own processes and tool usage,” as distinct from workflows, “systems where LLMs and tools are orchestrated through predefined code paths” (Building effective agents, Anthropic, 19 Dec 2024). The implementation is thinner than the marketing suggests: models using tools based on environmental feedback, in a loop. That thinness is the point. There is no planner module to harden and no orchestration engine to patch. There are four parts, and the security of the system is the security of each part plus the seams between them.
The four parts
| Part | What it is | Where security lives |
|---|---|---|
| Model | A stateless completion endpoint plus the context you assemble (IV.1) | It cannot separate instruction from data: one token stream, no provenance (II.1) |
| Tools | Functions, a shell, HTTP clients, MCP servers, browser and OS control | Where authority is spent. The model’s guess becomes the organization’s action (IV.6) |
| Memory | Scratchpad, history, a vector store, and files the agent writes itself | A memory write is a privileged action. Anything durable is a persistence primitive (III.4) |
| Loop | The harness that re-invokes the model with each result appended | It re-feeds attacker text into the same context that holds your credentials |
A useful sanity check on any agent architecture diagram: if you cannot point at all four, you are looking at a workflow, and a workflow is a much easier thing to secure. Predefined code paths mean the set of actions is enumerable in advance. The moment the model chooses the path, it is not.
One turn, in control flow
The public SDKs converge on the same loop. OpenAI documents it as: call the model for the current agent with the current input; if it returns a final output, the loop ends; if it performs a handoff, swap the agent and re-run; if it produces tool calls, execute them, append the results, and re-run - checking the turn limit each pass and raising MaxTurnsExceeded when it is hit (Running agents, OpenAI Agents SDK). Anthropic’s SDK tool runners take the same shape with a max_iterations cap (Memory tool, fetched 29 Jul 2026).
flowchart TB
U(["User goal"]) --> C["Context assembled:<br/>system prompt · config · memory · history"]
C --> M["Model decides:<br/>answer, or call a tool"]
M -->|"final output"| OUT(["Return to user"])
M -->|"tool_use"| G{"Policy check:<br/>allow · ask · deny"}
G -->|"allowed"| T["Tool executes<br/>with real credentials"]
T --> R["tool_result re-enters<br/>the SAME context"]
R --> M
M -.->|"write"| MEM[("Durable memory")]
MEM -.->|"read at next session start"| C
classDef d fill:#0f1a18,stroke:#5bd1c5,color:#bdeee2;
classDef g fill:#1d1708,stroke:#e4a23f,color:#f0d8a8;
class U,C,M,OUT,T,MEM,G d;
class R g;
The amber box is the whole problem in one node. A tool result is data the agent fetched from somewhere it does not control, and it returns into the same undifferentiated context as your system prompt. The dotted lines are worse: they carry that content across the session boundary.
Read the diagram for one question: at which arrow does content an attacker wrote meet authority you granted? In a chatbot the answer is nowhere, because there is no T node. In an agent the answer is every return trip, until a stop condition fires.
Where attacker-influenced text enters
Every one of these lands in the same context window with the same weight. None is tagged untrusted unless you tag it.
- The user turn. The least interesting, because the person typing is the person accountable.
- The agent’s own configuration. Repository-supplied instruction files, project settings, skills, and hooks are attacker-controlled the moment you clone an untrusted repo. Vendors now treat them that way: Claude Code refuses to honor several sandbox keys from a project’s
.claude/settings.jsonspecifically so that “a checked-out project can’t switch filesystem isolation off” (Configure the sandboxed Bash tool, fetched 29 Jul 2026). - Tool definitions and their metadata. Names, descriptions, and JSON schemas are prose that reaches the model before any tool runs. The MCP specification is explicit that clients “MUST consider tool annotations to be untrusted unless they come from trusted servers” (MCP spec, Tools).
- Tool results. Web pages, files, database rows, API responses (III.3 · Browser & computer-use agents).
- Retrieved documents. RAG output is a tool result pre-selected for relevance to the user’s question, which is a helpful property for an attacker planting content (V.3).
- Durable memory. Anything the agent wrote in a previous session, including things it wrote because it was told to.
- Subagent and peer output. Another model’s completion is untrusted input with trusted-looking provenance (IV.4 · Multi-agent systems, A2A & the seams).
- The environment itself. Filenames, symlink targets, git refs, environment variables, terminal output. The 2026 sandbox escapes in III.2 · Coding agents & Codex security all begin here rather than in prose.
Why the loop is the multiplier
A jailbroken chatbot produces one bad paragraph. A hijacked agent produces a bad action, then reads the result of that action, then decides again with the bad instruction still in its context.
Persistence within the turn. The injected text is not consumed when it is obeyed. It stays in context for every subsequent iteration, so one successful injection steers the remainder of the task after the poisoned result has scrolled past.
Compounding. Anthropic’s postmortem of a production multi-agent system puts it plainly: “Minor changes cascade into large behavioral changes,” and “Without effective mitigations, minor system failures can be catastrophic for agents” (How we built our multi-agent research system, 13 Jun 2025). That is a reliability observation, but the security consequence is identical - the loop has no natural damping.
Speed. The loop runs at machine speed with no human in it by default. The stop condition is therefore a security control, not an ergonomics setting. max_turns and max_iterations are the cheapest bound you can put on a runaway agent, and they belong in the deployment config next to the credentials. See III.5 · Consent & containment for how to size them.
Memory is the part that outlives the incident
Anthropic’s memory tool gives the model file operations - view, create, str_replace, insert, delete, rename - against a /memories directory, and the API injects a system instruction telling Claude to check that directory first and to “ASSUME INTERRUPTION” while recording progress there.
The security-relevant detail is architectural: the memory tool operates client-side. The model only requests operations; your application executes each one. The documentation is blunt about who owns the consequences - “Your application executes every file operation Claude requests, so these safeguards are your responsibility” - and warns that a path such as /memories/../../secrets.env “can reach files outside the /memories directory,” with canonical-path resolution, prefix validation, and rejection of URL-encoded traversal listed as the required mitigations.
One agent, a supervisor, a swarm
The three shapes differ in one way that matters: where the loop’s context is aggregated, and therefore where a poisoned result lands.
| Shape | How control moves | What changes for security |
|---|---|---|
| Single agent | One model, one context, one loop | Smallest surface. Blast radius equals its tool set plus its credentials |
| Supervisor (agents as tools) | A central model calls specialists and keeps ownership of the reply | Its context is a confluence: every worker’s output reaches the most privileged context |
| Handoff / swarm | Control transfers between peers | Authority travels with the task; privilege accumulates along the chain (A2A-4, IV.4) |
The supervisor’s confluence has an upside: it is also a single, natural audit and policy point. The swarm’s does not - there is no one context to inspect, injected instructions ride the handoff payload across a trust boundary, and detection must reconstruct a trajectory across processes rather than read one transcript.
OpenAI’s guidance is to start with one agent and split only when subdivision “materially improve[s] capability isolation, policy isolation, prompt clarity, or trace legibility,” and that on a handoff “A specialist should own the next response rather than merely helping behind the scenes” (Orchestration and handoffs). Two of those four criteria are security properties. Treat multi-agent decomposition as a control decision that happens to also be an architecture decision, and if you cannot say which boundary the split enforces, it is buying complexity and cost - Anthropic measured its multi-agent research system at roughly 15x the token consumption of a chat interaction - without buying containment.