Prompt injection mitigations ranked: from filtering to structure

Most prompt injection advice is a list of mitigations with no ordering, as if “add a filter” and “remove the secret from context” were interchangeable. They are not. The mitigations differ by orders of magnitude in how much they depend on the model behaving correctly, and that dependency is the whole game. Here is a practical ranking, weakest to strongest.

Rank 5: output filtering

Filtering the model’s output for secret-shaped strings is the most common mitigation and the weakest. A regex or keyword scan runs after the model has already produced the text, so it only catches values the filter recognizes: an exact key, a base64 encoding, a URL-encoded variant. Anything the attacker transforms beyond your rule set — hex, reversed strings, character-by-character assembly — sails through. Filtering also cannot stop the model from using a secret in a tool call instead of printing it. It is a last line of defense, not a primary control.

Rank 4: input sanitization

Stripping or escaping untrusted content before it enters the prompt sounds reasonable, but content arrives through too many channels: web pages, email, API responses, tool output, file contents. Miss one channel and the boundary is decorative. Sanitization also mutates the data the agent is supposed to work with, which is why teams quietly disable it. It reduces the attack surface, but it is still a model-dependent control: the sanitizer must be correct every time.

Rank 3: system prompts and refusal training

“Never reveal secrets” instructions and fine-tuned refusals feel like progress because they measurably reduce naive injection success in benchmarks. They remain probabilistic defenses against a deterministic attacker. A system prompt is part of the same context the attacker’s text lands in; it can be outweighed, contradicted, or re-ranked. Refusal training improves the baseline, but the attacker only needs one prompt that slips past it. Treat this layer as hardening, never as a guarantee.

Rank 2: tool and permission gating

Restricting which tools the agent may call, and requiring approval for sensitive ones, changes the blast radius. An injected agent that can only read files cannot ship your credentials anywhere. This layer is strong because it constrains actions, not text. Its weakness is granularity: approval prompts get fatigued into auto-accept, and any tool that can read or send data is a potential exfiltration pipe. Gating reduces what an injection can do, but a single over-permissive tool still leaks.

Rank 1: structural separation

The strongest mitigations remove the choice from the model entirely. If the agent’s context never contains the plaintext secret, injection has nothing to exfiltrate — the model cannot be tricked into revealing what it never had. This is structural: credentials are resolved at the process boundary into a subprocess environment, delivered over the wire by a per-host proxy the agent never touches, and scrubbed from agent-visible stdout and stderr. Outbound LLM traffic passes through a DLP layer as a backstop. None of these layers ask the model to behave correctly; they make correct behavior irrelevant.

Choosing by what you can verify

Ranking tells you where to spend effort. Ask which of your mitigations fail closed: if the model is fully compromised, does your control still hold? Output filters, sanitizers, and system prompts all fail open under a sufficiently good injection. Permission gates fail when a tool is over-permissive. Only structure — secrets absent from context, injected at spawn or transport time, filtered at egress — holds regardless of what the model does. A cheap test: run a compromised-agent drill and watch which layer actually stops the leak.

trustless is built around the structural end of this ranking — process-level injection with output sanitization, per-host credential proxying, and a DLP reverse proxy with 40 gitleaks-derived rules and entropy detection. Command details are in the docs.

Which mitigation in your current stack would survive a fully compromised model — and have you actually tested that one?