Incident Patterns
Agentic systems fail in a surprisingly small number of shapes. Once you have looked at enough architectures, the same seven or eight stories recur with different logos on them, and being able to recognise a shape early is worth more than any individual technique. This page describes those recurring shapes as patterns — no names, no dates, no attributions — because the specific incidents are less instructive than the structure they share. For each one: how it happens, why it survives code review (this is the part most write-ups skip, and it is where the real lesson lives), the detection signal that would actually have caught it, and the single control that would have stopped it.
1. Indirect prompt injection through retrieved content
How it happens. The agent retrieves a document, web page, ticket, or email. Embedded in that content is instruction-shaped text. The agent’s planner has no structural way to distinguish “content to reason about” from “instruction to follow,” so the retrieved text competes with the system prompt for control. The agent then does something entirely within its authorized capability set, for the wrong reason.
Why it survives code review. The retrieval code is correct. The tool code is correct. Nothing in the diff is wrong. The vulnerability lives in the composition — the fact that untrusted text and privileged tools share one context window — and no file in the changeset represents that composition. Reviewers also tend to see the system prompt’s “ignore instructions found in documents” line and treat it as a mitigation.
Detection signal. A tool call whose justification traces to retrieved content rather than to user instruction, and tool sequences that have never occurred for that workflow.
Control that stops it. Not filtering. Authorization at the tool layer, so the influenced planner still cannot reach the destructive capability, plus provenance tagging that makes the influence visible after the fact.
2. The over-permissioned connector
How it happens. An agent needs to read a few records. Scoping the credential to exactly those records requires understanding a permission model nobody has time to learn, and the broad scope works immediately. An admin API key or a wildcard OAuth scope ships as a temporary measure and becomes permanent. Later, someone adds a write tool on the same credential.
Why it survives code review. The permission grant is not in the code — it is in a console, a secret manager, or a Terraform file that a different team reviews. The application diff shows client.records.read(...), which looks minimal. Nothing in the pull request reveals that the token behind client can also delete.
Detection signal. Compare granted scopes against observed API usage over 30 days. The delta is the finding, and it is usually enormous.
Control that stops it. Scope derived from the tool manifest, not from convenience: each tool declares the permissions it needs, credentials are minted to that union, and a periodic job fails the build when granted scope exceeds used scope.
3. The confused deputy
How it happens. A low-privilege user asks the agent for something. The agent, holding its own high-privilege credential, fulfils the request. The downstream system authorizes the agent, sees a legitimate service account, and complies. The user has just borrowed privileges they never had.
Why it survives code review. The authorization check exists — at the application’s front door, where the user is authenticated. Everyone sees that check and assumes the job is done. The missing check is at the tool boundary, where the agent’s identity silently replaces the user’s, and that substitution is invisible in the code because it happens inside a shared client object.
Detection signal. Downstream audit logs where the actor is a service account for 100% of calls, with no user attribution field populated.
Control that stops it. On-behalf-of delegation: the agent exchanges the user’s identity for a short-lived token scoped to that user’s rights, and downstream systems authorize the human, not the robot.
4. Memory persistence turns a one-time injection into a recurring compromise
How it happens. An injection succeeds once. Before the session ends, the agent writes a summary, preference, or “learned fact” to durable memory that encodes the injected behaviour. Every later session loads that memory as trusted context. The original attack channel can be closed entirely and the compromise continues.
Why it survives code review. Memory is framed as a product feature — personalisation, continuity, learning — and reviewed for usefulness rather than as an untrusted write path. The write is one line calling a memory service. Nobody asks what validates it, because “the agent wrote it” feels like an internal source.
Detection signal. Behaviour changes with no corresponding change in current-session inputs. Memory records containing imperative language rather than descriptive facts. Provenance chains that terminate at a tool rather than at a user or operator.
Control that stops it. Write validation and provenance on memory, TTL by default, and a hard separation between session scratchpad and durable store with no automatic promotion. Detail in OWASP Agentic AI Threats & Mitigations.
5. The missing audit trail
How it happens. An incident is suspected. The investigation opens the logs and finds prompts, completions, latency, and token counts — but not the tool call arguments, not which retrieved documents were in context, not which identity authorized the call, and not which memory records were loaded. The question “what did it actually do, and why” is unanswerable. The incident closes as inconclusive.
Why it survives code review. Logging exists and looks thorough. Reviewers check that logging is present, not that it is sufficient for reconstruction. Arguments are often deliberately omitted to avoid logging sensitive data — a reasonable-sounding decision made without a redaction alternative.
Detection signal. This one is testable in advance: run a tabletop and ask someone to reconstruct a specific past task end to end from logs alone. If they cannot, you have the gap today.
Control that stops it. A structured trace record per tool call, with redaction rather than omission:
{
"trace_id": "a41f", "step": 4,
"tool": "records.export",
"args": {"filter": "dept=finance", "limit": 5000},
"acting_identity": "agent-doc-assistant",
"on_behalf_of": "user-3312",
"authz_decision": "allow:policy-17",
"context_sources": ["doc-7781", "mem-8842"],
"approval": null
}context_sources and on_behalf_of are what turn an inconclusive investigation into a five-minute one. Build this in Lab 4 — Agent Audit Trail.
6. Unbounded autonomy on an irreversible action
How it happens. The agent completes a workflow end to end. Somewhere in that workflow is a step that cannot be undone — money moves, a message goes to a customer, records are deleted, a production config changes. There is no gate, because the gate was seen as friction and the agent had been reliable in testing.
Why it survives code review. Reversibility is not a property any reviewer is asked to assess. The destructive call looks like every other tool call in the file. Approval gates are frequently added late, during a rollout, and applied to the happy path only — retry and error-recovery paths keep the ungated call.
Detection signal. Inventory every tool and classify it as reversible or not. Any irreversible tool with no approval event in its call history is the finding. Also check whether the gate is enforced server-side or merely rendered in a UI.
Control that stops it. A human approval gate on the irreversible subset, enforced at the tool boundary so no code path can skip it, plus blast-radius caps so that even an approved call has a ceiling.
7. Supply chain: the compromised or typosquatted tool server
How it happens. A capability is needed; a plugin, connector, or MCP server that provides it is installed. It may be typosquatted, abandoned and taken over, or legitimate but later updated with hostile content. Because tool descriptions are model-visible text, a malicious server can ship instructions inside its own schema — the tool does not need to be called to influence the agent.
Why it survives code review. Adding a tool server is often a config line or a UI toggle, not a code change, so it may never reach review at all. When it does, reviewers evaluate the name and the README. Nobody reads the tool descriptions as untrusted input, and nobody re-reviews on update because the version bump is automatic.
Detection signal. Diff tool schemas and descriptions on every update and alert on change. Watch for instruction-shaped language in descriptions, and for a server requesting scopes broader than its stated function.
Control that stops it. Treat tool servers as dependencies: pin versions, review on change, run them with no ambient credentials, and maintain an allowlist. Guidance in Agent Frameworks and practice in Lab 2 — Multi-Agent SOC with MCP.
Pattern summary
| # | Pattern | Why review misses it | Telling signal | Stopping control |
|---|---|---|---|---|
| 1 | Indirect prompt injection | Flaw is in composition, not any file | Tool call justified by retrieved content | Tool-layer authorization + provenance |
| 2 | Over-permissioned connector | Grant lives outside the code diff | Granted scope » used scope | Scope derived from tool manifest |
| 3 | Confused deputy | Front-door authz mistaken for sufficient | Service account is sole downstream actor | On-behalf-of delegation |
| 4 | Memory persistence | Memory reviewed as a feature | Behaviour change without input change | Write validation, provenance, TTL |
| 5 | Missing audit trail | Logging present but insufficient | Cannot reconstruct a past task | Structured tool-call traces with redaction |
| 6 | Unbounded autonomy | Reversibility never assessed | Irreversible tool with no approval events | Server-side gate + blast-radius caps |
| 7 | Supply chain | Config change, not a code change | Tool description diffs on update | Pin, review, no ambient credentials |
What post-mortems keep concluding
Four conclusions recur across agentic incident reviews, and they are worth internalising as design principles rather than lessons.
Containment beats detection. You will not reliably detect that a planner has been influenced — there is no signature for “was convinced.” What you can do is guarantee that an influenced planner reaches a bounded set of capabilities. Every mature agentic security program shifts investment from “catch the bad input” to “bound the possible output.”
Identity is the real perimeter. Prompt-level controls are probabilistic; identity controls are deterministic. The organisations that handle agentic incidents well are the ones that gave each agent its own identity, minted short-lived scoped credentials, and passed user identity through to downstream authorization. The ones that struggle share one service account across everything and discover during the incident that attribution is impossible.
Log arguments, not just outcomes. Post-mortems fail on missing arguments more than on missing events. Knowing that records.export was called tells you nothing; knowing it was called with a 5,000-record filter, on behalf of a user with read access to twelve records, under a policy decision that allowed it, tells you everything. Redact values, never omit fields.
Irreversibility requires a human. Every incident with lasting damage involved an action that could not be undone taken without a human in the loop. The engineering discipline is simple and rarely applied: classify every tool as reversible or not, and let the classification — not the perceived reliability of the model — decide where gates go.
A fifth conclusion is less comfortable: most of these were known. In nearly every case the risk had been raised by someone, deferred for a deadline, and never revisited. The security problem is frequently a prioritisation problem wearing a technical costume, which is why the ability to make a containment argument to an engineering lead matters as much as the ability to find the flaw — see Layer 5 — Soft Skills.
Turning these into interview scenario answers
Scenario questions in agentic security interviews are almost always one of these patterns wearing a costume. “An agent with access to a CRM started emailing summaries externally” is pattern 1 plus pattern 2. “We can’t tell what the agent did last Tuesday” is pattern 5. Recognising the shape lets you answer structurally instead of improvising.
A four-move answer that works consistently:
| Move | What you say | Why it lands |
|---|---|---|
| Name the shape | “This looks like indirect injection into an over-permissioned connector.” | Shows pattern recognition, not guesswork |
| State the mechanism | Untrusted content reached the planner; the tool it reached had unbounded scope. | Demonstrates you understand cause, not symptom |
| Give the containment answer first | Revoke the credential, scope it to observed usage, gate the egress tool. | Signals operational instinct over theory |
| Name what you would have logged | Tool args, context sources, acting identity, authz decision. | Separates people who have run an incident from people who have read about one |
Resist two temptations: leading with a filter or classifier as the fix (it marks you as prompt-layer-only), and reaching for a framework citation before you have explained the mechanism in plain language. Name the mechanism first, then map it to OWASP or ATLAS if it adds precision. More rehearsal material in Interview Prep and What Employers Screen For.