Defense in Depth

Lesson 1 of 3 in In Production: The Defense Stack Around a Served Model.

This whole domain has been building to one uncomfortable conclusion: the model cannot defend itself. It reads a single token stream with no type system separating instructions from data (the single-channel problem); its refusals are trained dispositions, not enforcement; its filters are probabilistic classifiers bolted on around it. Every mechanism you have met — Jailbreak taxonomies, indirect injection, Training data extraction — exploits some version of that fact.

Production security for LLM systems therefore borrows the oldest idea in the defender’s playbook: defense in depth. You do not look for the one control that works; you stack controls that fail differently, so that what slips past one is caught — or at least witnessed — by another. The stack around a served model has five layers, and the discipline is to be honest about how each one fails.

One boundary note before we build it: this module defends the model call. The moment your model can also act — invoke tools, browse, execute code — the attack surface multiplies, and containment, tool scoping, and the per-cloud agent guardrail catalogs become the story; our sister AI Agent Academy owns that territory. Law and compliance obligations around all of this belong to the AI Governance Academy.

A vertical stack of five defense layers around a served LLM, from bottom to top: provider safety training (a disposition in the weights, steerable by novel jailbreaks), provider content filters (configurable classifiers with false negatives and false positives), your input handling (pattern checks that reduce but never guarantee), your output handling (highlighted — the deterministic layer: escape, validate, least privilege), and monitoring and response (detects what got through, fails when nobody looks).

The defense stack around a served model, bottom-up from the weights to your dashboards. Every layer carries an honest failure note — the design assumption is that each layer leaks, so none is trusted alone. (illustrative — source: OWASP Top 10 for LLM Applications (2025))

Walk the stack from the bottom.

Provider safety training is what you inherit with the model: post-training that makes the model disposed to refuse harmful requests and resist instruction overrides. Techniques like instruction-hierarchy training (Wallace et al., 2024) measurably improve resistance to some override attacks — and the authors do not claim they close the gap. A disposition can be searched around; that is what the Jailbreak literature is.

Provider content filters are the configurable classifiers the platforms wrap around the call — the subject of the next lesson. They are the cheapest layer to turn on and the easiest to overtrust.

Your input handling is where honesty matters most. The instinct from classic security — sanitize the input! — half-applies here. What works: cap lengths, validate formats, strip invisible Unicode and known injection markers, and keep untrusted content (user text, retrieved documents) structurally separated from your instructions in the prompt. What does not exist: an escaping discipline that makes natural language safe, because there is no fixed set of dangerous tokens — any fluent sentence can carry an instruction. Input handling reduces attack volume. It guarantees nothing, and a design that assumes otherwise has already failed.

Your output handling is the layer OWASP names LLM05, Improper Output Handling, and it deserves its emphasis in the stack. The model’s output is a function of everything in its context — including whatever an attacker managed to place there. So treat output as untrusted input to the rest of your system: escape it for wherever it renders (HTML-encode, strip or confirm links in markdown), validate it against a schema before anything executes or acts on it, and least-privilege every consumer — the database user, the downstream API, the browser context. An injection that succeeds against the model but hits hardened output handling becomes a weird answer instead of an exploit.

Monitoring is the admission that some of everything above will fail — lesson three.

The web has run this play before

SQL injection and cross-site scripting were the same disease: untrusted text crossing a trust boundary and being interpreted as code. The cures that actually worked were deterministic and structural — parameterized queries separate code from data by construction; context-aware output encoding makes markup inert no matter what it says. Heuristic input filtering, the 2000s-era WAF approach, helped at the margins and was bypassed forever.

Prompt injection has the same shape with one cruel difference: on the input side there is no parameterized-query equivalent, because the model consumes one undifferentiated token stream — that is the single-channel problem, and it is why “sanitize the prompt” cannot graduate from heuristic to guarantee. The deterministic discipline therefore migrates to the output side, where classical tools still work: encoding, schema validation, and privilege boundaries do not care how clever the attacker’s prose was.

Least privilege deserves the last word. OWASP’s LLM06, Excessive Agency, is what happens when the consumer of model output holds more authority than the workflow needs — the model asks, and the system can. Scope every consumer as if an attacker occasionally authors the model’s output, because at the margin, one sometimes does.

In production

On the managed platforms, the bottom two layers of the stack come from the provider and the top three remain yours. Knowing which is which per cloud is the first architecture decision.

AWS

The safety-training layer arrives with whichever foundation model you select — each provider’s post-training, not Amazon’s. The provider-filter layer is Amazon Bedrock Guardrails: configurable safeguards evaluating inputs and responses, attached at inference by guardrail ID and version, or invoked standalone via the ApplyGuardrail API — which means the same filter layer can also screen text your app handles outside a Bedrock call. Input handling, output handling, and monitoring live in your application code; Guardrails tells you when it intervened, which becomes a monitoring feed.

Azure

Model deployments in Azure AI Foundry carry a built-in content filtering system powered by Azure AI Content Safety that runs both prompts and completions through harm classifiers, with optional Prompt Shields for direct and indirect prompt-injection attempts. The layer boundary is explicit in the API contract: a blocked prompt surfaces as an HTTP 400 error and a filtered completion as a content_filter finish reason — so your output-handling code must treat filter verdicts as a first-class response type, not an exception path. Filter configurations attach per deployment, which makes the filter layer part of your deployment definition.

Google Cloud

Vertex AI wraps model calls in safety filters with two tiers: non-configurable blocks the platform always applies, and configurable content filters with per-category thresholds you set. The API reports why content was blocked through explicit enums (block and finish reasons), giving your app a machine-readable filter signal. Google’s docs are candid that filters act as a barrier rather than changing the model — steering the model itself is done through system instructions for safety, which is the disposition layer’s knob. Escaping, validation, and least privilege remain entirely yours.

Interactive checkpoint quiz (2 questions) — open this page in a browser to take it.