An agent that promises to stay inside its instructions can still call a tool with the wrong authority. The decisive control is the code that accepts or rejects that call. A secure harness makes prohibited actions fail even when the model asks confidently.
By harness, we mean the runtime around the model: tool adapters, credentials, state, approval handling, execution limits, and event records. Our production-harness article examined those components as operating infrastructure. Read the same architecture as a permission system and the security questions get much more precise. The question stops being "how do we stop the model from doing this" and becomes "which component would have to fail before this could happen at all."

The failures are not happening in the model
OWASP's GenAI Exploit Round-up for Q1 2026, covering January 1 to April 11, documented eight major incidents and reached a conclusion worth reading twice: attackers and system failures are increasingly targeting agent identities, orchestration layers, and supply chains rather than model outputs. The dominant categories were Excessive Agency and Identity and Privilege Abuse (ASI03 in the OWASP Top 10 for Agentic Applications, released December 2025). Overprivileged service accounts. Agents operating outside their intended constraints. Not jailbreaks, and not clever prompting.
The same report makes a second observation that should change how a security team spends its week. Most AI-related security events are not yet mapped to CVE identifiers, because they come from misconfiguration and design flaws rather than discrete code bugs. You cannot patch your way to a safe agent. Most of the time there is nothing to patch.
Where there are CVEs, they point at the same layer. On May 7, 2026, Microsoft published an analysis of two vulnerabilities in its own Semantic Kernel framework. CVE-2026-26030 came from a default filter that passed a model-controlled string into a Python lambda evaluated with eval(), which let an attacker close the quote and append arbitrary logic. CVE-2026-25592 was simpler and more instructive: a DownloadFileAsync function had been marked with the [KernelFunction] attribute by accident, which exposed it to model control and turned prompt injection into arbitrary file write, including into a Windows Startup folder.
Read the second one carefully. Nobody talked a model into doing something it was not equipped to do. The tool surface was wrong. One attribute on one method decided whether the system was exploitable, and that was a harness decision made by an engineer, not a model decision made at inference time.
Replace the model with a plain client that asks for the forbidden action directly, with no prompt and no reasoning. If the action succeeds, the protection was behavioral guidance rather than enforced access control. Every control in this article is written to survive that test.
Start with the action, not the model
Take a supplier-document workflow. The agent reads an approved packet, compares line items against a contract, and drafts a discrepancy report. Reading that packet, writing a draft, changing a supplier record, and emailing the report to a contracting officer are four different privileges with four different blast radii. A broad instruction to "handle supplier review" should not silently grant all four, and a single service account holding all four is the structural vulnerability that OWASP keeps finding at the top of its incident lists.
The unit of security here is the action, not the agent and not the session. Give the runtime an action contract and make every tool call satisfy it before execution:
- Requester. Which authenticated human or system is this work being done on behalf of, and is that identity still valid right now.
- Resource scope. Which specific records, not which table.
- Operation. Read, draft, write, send. Enumerated, not inferred from a tool name.
- Destination. For anything that leaves the system, the exact recipient or endpoint.
- Expiry. When this authority stops being valid, in wall-clock time.
- Approval requirement. Whether a human decision is required, and at which step.
Enforce that contract at the tool boundary, inside the adapter, not in the system prompt and not in a wrapper the model can route around. Then check the target resource again at execution time. A plan that was valid when it was written may now point at a changed record, a closed contract, or a revoked account. The gap between deciding and doing is where long-running agents get expensive.
The five harness layers are access controls
The five layers from the production-harness piece are not five operational conveniences that happen to have security implications. They are five places where authority is either preserved or quietly lost.
| Harness layer | Security control it implements | Failure it prevents |
|---|---|---|
| Permissions | Narrow operations bound to scoped, short-lived credentials | Tool Misuse (ASI02): a permitted tool called with the wrong intent or target |
| Memory | Provenance retained with content: source, owner, age, access scope | Memory and Context Poisoning (ASI06): retrieved text treated as instruction |
| Resumability | Re-authorization on resume, not just state restoration | Identity and Privilege Abuse (ASI03): a checkpoint outliving the permission that created it |
| Observability | Independent record of requested action, decision, target, and observed result | Unfalsifiable incident review: no way to prove what actually executed |
| Cost and execution limits | Hard bounds on retries, tool calls, runtime, and spend | Cascading Failures (ASI08): a loop that converts one bad decision into thousands |
Three of those deserve more than a table row.
Permissions. The useful discipline is to keep a report-reading tool separate from an unrestricted database executor, even when the same engineer builds both and the second one is easier. Every generic tool you expose is a permanent bet that the model will never call it in an unintended combination. Scoped credentials also need to be short-lived, because an agent that runs for six hours with a token minted for the whole window has a six-hour exposure surface regardless of what it is doing in minute four.
Memory. This is the layer teams get wrong most often, because memory feels like storage and behaves like an input channel. Content retrieved from a document, a ticket, a web page, or another agent's output arrives carrying whatever instructions an attacker put there. If your memory layer stores the text and drops the provenance, then by the time that text reaches the model it is indistinguishable from something the user asked for. Keep source, owner, timestamp, and access scope attached to the content, and keep retrieved material in a different structural position than user instructions. A remembered sentence from a supplier PDF does not become an authorized request because it was stored and read back.
Resumability. A checkpoint proves previous progress. It does not prove current permission. When an agent resumes after an hour, a crash, or a queue delay, re-run the authorization check against live state rather than replaying the decision that was captured at suspend time. This is unglamorous and it is the difference between a durable workflow and a durable privilege escalation.
The trifecta is a harness constraint, not a prompt problem
In June 2025 Simon Willison named the lethal trifecta: access to private data, exposure to untrusted content, and the ability to communicate externally. Any agent holding all three can be turned into an exfiltration tool by a single injected instruction, because language models follow instructions found in content and cannot reliably rank them by origin.
The reason to treat this as architecture rather than as a prompt-hardening exercise is that the third leg is almost always optional and almost always left switched on. OWASP's State of Agentic AI Security and Governance report maps prompt injection to six of the ten categories in the agentic Top 10, which is another way of saying that injection is not a category you defend against once. It is an input condition you design around.
In practice that means splitting the workflow so no single execution context holds all three legs. The component that reads untrusted supplier documents does not hold the outbound email credential. The component that can send email receives a structured, validated payload and has no retrieval tool at all. Prompt injection still lands. It just lands somewhere that cannot reach the exit.
Make approval bind to what executes
Human approval is the control most likely to be theater, because it is the one most often implemented against a summary rather than against a payload.
A reviewer needs the destination and the exact consequence. Approving a discrepancy report does not approve an arbitrary future email carrying that report to an arbitrary recipient. Bind the approval token to the action payload and its revision, including recipients and attachments, and invalidate it when either changes. If the executor cannot verify that the payload it is about to run is byte-identical to the one that was approved, it should require a new decision rather than proceed on the strength of the old one.
Render the review page from the stored payload, not from an agent-written description of the payload. Let the model explain its recommendation, and show the underlying facts separately and unmediated. The alternative is that the same component proposing the action also controls the only account of it the reviewer ever sees, which is OWASP's ASI09, Human-Agent Trust Exploitation, arriving through the front door.
Keep the decision state explicit and keep it honest: proposed, approved, submitted, confirmed, rejected, or uncertain. An API returning 200 establishes submission. It does not establish the intended outcome. A system that collapses those two states into "done" will eventually report a delivery that never happened, and the operator will find out from the recipient rather than from the log.
Exercise the boundary before you widen it
Build a small adversarial packet around the workflow you actually run, and run it on every deploy. For the supplier example, four cases cover most of the ground:
- A document in the packet that instructs the agent to forward the records to an external address.
- A supplier identifier outside the authorized scope, referenced in a way that looks routine.
- A recipient changed after approval but before execution.
- A credential that expires mid-run, forcing a resume.
The passing result in each case is a controlled refusal or an escalation, plus a record that says which check fired and why. A silent success is a finding. So is a crash, because a crash that loses the work makes operators route around the control.
Then test a legitimate request, which is the step teams skip. A boundary that blocks everything demos well and cannot be operated. Verify that the approved read and draft still complete, that a denied write does not discard work already done, and that a refusal does not send the agent looking for the same capability under a different tool name. That last behavior is worth watching for specifically: an agent that retries a blocked action through an alternate path is telling you your enumeration of operations has a gap in it.
The defense-program implication
For defense-support workflows, a scoped demonstrator built on public or synthetic records can show the complete permission story before any protected data enters the picture. That demonstrator should make three things legible to a reviewer: where authorization is enforced, what the event record proves, and which dependencies would need separate evaluation in the intended environment.
Be precise about what the demonstration is not. A working demo does not establish an authorization to operate, and it does not establish permission to process a particular dataset. Those decisions belong to the applicable program and system authorities. The engineering contribution is narrower and more useful: a boundary a reviewer can inspect, and a record a reviewer can challenge.
Make authority explicit at the level of the action, enforce it outside the model, and preserve it through memory, approval, and recovery. Then test both the permitted path and the denied path, on every deploy. If a control only works when the model cooperates, it is not a control.
Seven checks before an agent touches production
- Can you name every operation the agent can perform, as an enumerated list, without reading the prompt?
- Does each of those operations carry its own scoped, short-lived credential?
- Does retrieved content reach the model with its provenance attached and in a different structural position than user instructions?
- Does resume re-authorize against live state, or does it replay a stored decision?
- Is any approval bound to the exact payload and revision that will execute?
- Does the event record let someone who was not present reconstruct what was requested, what was decided, and what actually happened?
- Does the plain-client test fail closed on every prohibited action?
A "no" on any of these is not automatically a blocker. It is a decision that should be made deliberately, written down, and owned by a person, rather than discovered during an incident review.
Continue the conversation
Bring Agent9 one workflow, its operating constraints, and the evidence you need before deployment. Discuss the engineering problem.