LLM Guardrails and Prompt Injection: Securing and Monitoring AI in Production

Your LLM app passed every eval, so why can one pasted web page make it leak data?

Intro

It Passed Every Eval

Your assistant passed every eval you wrote. Then a customer pastes a web page into the chat, and your assistant quietly starts sending private account details to a stranger. Nothing crashed, and no error was logged. This gap between a working demo and a safe production system is what we close today.

  • Green evals, silent failure
  • No crash, no error

Where We Are

Last time we made serving fast with continuous batching and PagedAttention. Fast is not the same as safe. In this final production lesson we build a threat model, stack defenses in layers, write a small guardrail pipeline in Python, and then learn to watch the system with tracing, metrics, online evals and incident playbooks.

  • Last time: serving with vLLM
  • Today: safe and observable

Instructions and Data Collide

Here is the root problem. A language model reads one stream of tokens. Your instructions, the user's message, a retrieved document and a tool result all arrive as the same kind of text. Classic software separates code from data. A model has no hard wall between them, and almost every attack in this lesson exploits that fact.

  • One text channel for everything
  • Model cannot truly tell them apart

Threat Model

Five Things That Go Wrong

A threat model starts by naming what can go wrong. We will use five buckets: misuse of your product for harmful purposes, leakage of private data, jailbreaks that talk the model out of its policy, prompt injection that hijacks its instructions, and excessive agency, where the model can do more than it should. Each needs a different defense.

  • Misuse and data leakage
  • Jailbreaks and injection
  • Excessive agency

Misuse and Data Leakage

Misuse asks who is using your product and for what. A customer support bot should not write malware or give dangerous instructions. Leakage asks what the model can see. If your prompt, your retrieved documents or your tool results contain secrets or another user's data, then a clever question might surface them. Anything in context should be treated as potentially revealable.

  • Who can use it, for what
  • What can the model see

Jailbreaks, Defensively

A jailbreak is a user trying to pressure the model into ignoring its safety training, through role play, long persuasion or odd framing. We will not write any, because the defensive lesson is simple. Model alignment lowers the odds but is statistical, and new phrasings keep appearing. So you never let the model's good behavior be your only barrier.

  • Pressure on the model's policy
  • Training helps, never guarantees

Excessive Agency

Excessive agency is the quiet multiplier. Think of risk as likelihood times impact. Suppose a chat-only bot has a one percent chance of being tricked, but the worst outcome is an embarrassing sentence, impact one. Give the same bot a refund tool and an email tool, and the impact jumps to ten or a hundred. Same likelihood, far more risk.

  • Risk equals likelihood times impact
  • Tools raise the impact

Prompt Injection

Direct Prompt Injection

Direct prompt injection is when the person typing is the attacker. They write something like: ignore your earlier rules and do something else. It is the easiest to picture and, in many apps, the least dangerous, because the attacker only controls their own session and sees only what they are already allowed to see.

  • The user writes the attack
  • Goal: override instructions

Indirect Prompt Injection

Indirect injection is the serious one. The attacker never talks to your bot. They plant instructions inside a web page, a PDF, an email or a support ticket. Later your retrieval system or a tool fetches that content, the model reads it as context, and the planted text tries to steer the assistant on behalf of the attacker, against an innocent user.

  • Attack hides in retrieved content
  • Victim is a different user

The Three Ingredients

A useful mental model says the dangerous setup needs three ingredients together. First, access to private data. Second, exposure to untrusted content. Third, a channel to communicate outward, such as sending email or loading a URL. Remove any one of the three and the worst attacks lose their power.

  • Private data
  • Untrusted content
  • A way to send data out

Worked Example: Email Assistant

Take an assistant that reads your inbox and can send email. It sees private mail, it reads messages from strangers, and it can send. All three ingredients are present. The fix is not a cleverer prompt. Make sending require your approval, or restrict recipients to a short allowlist. Now stolen data has nowhere to go, even if the model is fooled.

  • Reads inbox, sends mail
  • All three ingredients present
  • Remove one leg

Mistake: Prompt-Only Security

This brings us to the most common mistake: relying on the system prompt alone for security. Writing never reveal secrets or never call this tool unless asked is a polite request to a statistical model. It is not enforcement. Anything that must never happen should be blocked by code outside the model, where a persuasive paragraph cannot argue with it.

  • System prompt is a request
  • Not an enforcement mechanism

Defense in Depth

Swiss Cheese Layers

Since every single defense leaks, we stack them. Imagine each layer catches eighty percent of bad attempts. One layer misses twenty percent. Three independent layers miss point two cubed, which is point zero zero eight, so ninety nine point two percent are caught. Real layers are not fully independent and attackers adapt, so treat this as an optimistic ceiling, not a promise.

  • Every layer has holes
  • Stack independent layers

Input Filters and Moderation

The first layer inspects input. Cheap rules catch obvious things like enormous inputs, known bad patterns or disallowed file types. A moderation model, which is a small classifier or a dedicated safety model, scores nuanced categories. Both add latency and can block good users, so tune thresholds with real examples and run cheap checks before expensive ones.

  • Cheap rules first
  • Moderation model for nuance
  • Adds latency and cost

Output Checks and Schemas

The second layer inspects what the model produced, before anything acts on it. If you asked for structured output, as in our earlier schema lesson, validate it strictly: valid JSON, expected fields, allowed values, sensible ranges. A refund amount of negative five hundred or an unknown action name is rejected in code. Output filters can also scan text for leaked secrets or disallowed content.

  • Validate before acting
  • Schema must parse and fit
  • Fail closed on doubt

PII Redaction

Personally identifiable information deserves its own layer. Redact emails, phone numbers and identifiers before they reach third-party services, before they enter logs, and before they appear in outputs that should not contain them. Pattern matching is quick but imperfect, so pair it with access controls, and never assume a regex found everything.

  • Mask emails, phones, IDs
  • Before logs, prompts, outputs

Privilege Separation

Privilege separation is architecture, not filtering. Use one quarantined model call to read untrusted content, and give it no tools and no secrets. It can only return a constrained result, like a short summary or a label from a fixed list. A separate privileged component holds the tools and never sees the raw untrusted text. A hijacked reader has nothing to steal and nothing to press.

  • Quarantined model reads untrusted text
  • Privileged model holds tools

Allowlisted Tools, Least Privilege

Apply least privilege to tools. Expose only the tools the task needs, from an explicit allowlist. Give each a credential scoped to the minimum: read-only database access instead of admin, one folder instead of the whole drive. Validate every argument in code, because the model chooses the arguments and an attacker may be influencing that choice.

  • Only named tools
  • Scoped credentials
  • Validate every argument

Sandboxing Code Execution

If the model can run code, assume the code is hostile. Run it in a sandbox: a container or lightweight virtual machine with no access to your secrets, no network unless required, limited memory and disk, and a hard time limit. Throw the environment away afterwards. The sandbox turns a possible disaster into a failed job.

  • Isolated container or VM
  • No network, limited disk, time limit

Human in the Loop

For actions that are hard to undo, such as payments, deletions or outbound messages, put a human in the loop. Show the exact action and arguments, not a friendly summary. Keep approvals rare. If people click approve a hundred times a day they stop reading, so reserve the gate for the actions where a mistake really hurts.

  • Approve irreversible actions
  • Show exact action, not summary
  • Beware approval fatigue

No Defense Is Complete

Be honest about the limits. No filter, model or prompt gives complete protection against injection today. The practical goal is to assume some attacks will succeed, then limit what a successful one can do, detect it quickly, and recover. Test regularly with your own red team exercises and keep a growing regression set of failures you have seen.

  • Assume some attacks succeed
  • Limit blast radius
  • Red-team and re-test

Python Guardrail Pipeline

The Pipeline Shape

Now let us write it in plain Python, independent of any provider. The pipeline is four steps. Check the input. Call the model. Validate the output against a schema and an allowlist. Redact personal data from whatever goes back to the user. Each step is a small function that returns either a clean value or a rejection with a reason.

  • Check input
  • Call model
  • Validate output
  • Redact PII

The Input Check

The input check does two cheap things. It rejects messages longer than a limit, say four thousand characters, because huge inputs hide payloads and burn money. It also checks a short list of suspicious phrases using lowercase matching. Return a pair: a boolean and a reason. A blocklist is easy to evade, so treat it as a speed bump that feeds your logs, never as the defense.

  • Length limit
  • Simple blocklist
  • Return ok and reason

PII Regex Walkthrough

For redaction we use re dot sub with two patterns. One matches an email: word characters, an at sign, a domain, a dot, a suffix. Another matches phone numbers made of seven to fifteen digits with optional spaces or dashes. The text contact jane at example dot com or 555 0100 becomes contact EMAIL or PHONE. Regex misses unusual formats and sometimes hits harmless numbers, so measure both errors.

  • Email pattern
  • Phone pattern
  • Replace with tags

The Output Validator

The output validator parses the model's reply with json dot loads inside a try block. Then it checks that the action is in an allowlist, such as answer, refund or escalate, and that fields like amount lie between zero and one hundred. Anything else returns a rejection. A reply of refund with amount negative five hundred never reaches your payment system.

  • Parse JSON strictly
  • Check action allowlist
  • Check value ranges

Fail Closed

Wire the steps together with a clear failure policy. When a check fails, fail closed: return a safe fallback message, or hand off to a human, instead of passing the raw output along. Log the reason every time. Failing open feels friendly during a demo and becomes the incident report later.

  • On doubt, refuse or escalate
  • Never pass raw output through

Monitoring

Why Monitor

Guardrails reduce risk, but you still need to see what is happening. Language model failures are usually silent: the service returns a confident, well-formed, wrong answer with a healthy status code. Prompts change, documents change, models get updated, and users surprise you. So we log structured traces of every request, including inputs, outputs, tool calls, timings, token counts and guardrail decisions.

  • Outputs are nondeterministic
  • Failures are silent
  • Prompts and data change

A Tracing Decorator

Here is a tracing decorator. It wraps your pipeline function, records the start time, calls the function, and catches any exception so it can log the error and re-raise. In a finally block it appends one JSON object per line to a file: request id, duration in milliseconds, status, token counts and the guardrail outcome. JSON lines files are easy to append to and trivial to analyse.

  • Wrap any function
  • Time it, catch errors
  • Append one JSON line

Dashboard Stats by Hand

Reading the file back gives a dashboard. Say we logged one thousand requests, and thirty were refusals. Refusal rate is thirty over one thousand, three percent. If each request used eight hundred tokens at a hypothetical price of two dollars per million, total tokens are eight hundred thousand and cost is one dollar sixty. Sort the latencies and read the median and the ninety fifth percentile, because averages hide slow tails.

  • 1000 requests, 30 refusals
  • Refusal rate 3 percent
  • Cost from token counts

Metrics and Feedback Signals

Four core numbers to chart over time are latency, cost per request, error rate and refusal rate. A rising refusal rate can mean an overactive filter, and a falling one can mean a guardrail broke. Add user feedback signals too: thumbs up and down, regenerate clicks, copy actions, follow-up complaints and human edits. They are noisy, but they point you toward the traces worth reading.

  • Latency, cost, error, refusal
  • Thumbs, regenerate, edits

Drift

Drift is when the world moves under a system that has not changed. Users start asking about a new product. The document corpus is updated and retrieval shifts. The provider updates a model version behind the same name. Track input length, topic mix, retrieval scores and output style over time, and alert when a distribution moves away from its baseline.

  • Inputs change
  • Corpus changes
  • Model versions change

Online Evals with an LLM Judge

You cannot read every trace, so sample. With one hundred thousand requests a day, sampling two percent gives two thousand to score. A judge model rates each on a rubric: grounded in sources, policy violations, helpfulness. Judges have biases, such as favoring long answers, so periodically compare their scores with human labels on a small set and fix the rubric when they disagree.

  • Sample 2 percent of traffic
  • Judge scores quality and safety
  • Calibrate against humans

Releases and Incidents

A/B Tests and Canaries

Ship changes to prompts, models and guardrails gradually. A canary release sends five percent of traffic to the new version while watching refusal rate, errors, cost and judge scores. Noise matters: with one thousand requests and a three percent rate, the standard error is the square root of point zero three times point nine seven over one thousand, about half a percent. So a move from three to four percent is within noise.

  • Send 5 percent to the new version
  • Compare guard metrics
  • Roll back automatically

Incident Playbook

Write the incident playbook before you need it. Step one, contain: a kill switch that disables a tool or the whole feature, and a fast rollback. Step two, investigate with the traces: who, which input, which content, which tool call. Step three, fix the root cause, rotate any exposed credentials, notify whoever you must, and add the case to your regression set so it never returns quietly.

  • Contain, investigate, fix
  • Kill switch and rollback
  • Add a regression test

Recap

Common Mistakes

Let us collect the mistakes. Trusting the system prompt as your only security. Giving agents broad tools and credentials. Treating retrieved or tool content as trusted instructions. Logging raw personal data into your traces. Shipping without a kill switch. And never turning past incidents into tests. Each one is cheap to avoid and expensive to learn from the hard way.

  • Prompt-only security
  • Too much agency
  • Logging raw secrets
  • No regression set

Recap and What Is Next

To recap: models cannot separate instructions from data, so assume injection will happen. Limit agency, separate privileges, validate in code, redact personal data, and keep humans on irreversible actions. Then trace everything, watch latency, cost, errors, refusals and drift, sample with a judge, release gradually, and keep a playbook. That closes the production section. Next we start the capstones, beginning with a document question answering bot.

  • Threat model, layers, traces
  • Next: capstone document Q&A bot