LLM Basics
Lesson 6 of 6

Defenses, Part 2: Defense-in-Depth

Every defense in lesson 5 was a text-level defense — a cleverer way of arranging words in the prompt, still relying on the model to behave correctly given those words. Sandwiching failed. Delimiting worked, this time, against this attack. That inconsistency is the whole point: any defense that depends entirely on the model choosing correctly will eventually fail against some attack you haven't tried yet.

The fix isn't a cleverer prompt. It's moving the safety net outside the model entirely — into the system architecture around it.

Three architectural principles, all independent of anything the model "decides":

  • Least privilege — a tool the model can't call is a tool that can never be misused, no matter what any prompt says. An email assistant that literally has no delete_file tool can't be tricked into deleting a file.
  • Human-in-the-loop — for actions that are risky or hard to reverse (sending money, deleting data, sending an email to a new recipient), require explicit human approval before the action executes, regardless of how confident the model is.
  • Defense-in-depth — layer several independent defenses (text-level and architectural) so that one failure doesn't mean total compromise. The point isn't finding one perfect defense; it's making sure no single bypass is catastrophic.

Predict before you look

An agent with send_email and delete_file tools receives an email containing a hidden instruction to misuse both. Before you try it: if the model complies with the injected instruction, does the permission level of each tool actually change what happens?

Notice what the sandbox does not depend on: it never asks whether the model "wants" to comply. Whether the model refuses (as it did in the real transcript this scenario is based on) or complies, the outcome for each tool is fully determined by its permission level. That's the property you actually want — a system whose safety doesn't rest on a language model's judgment holding up perfectly, forever, against attacks nobody has invented yet.

The permission check itself is simple, deterministic code — no model involved at all:

Python

That closes the loop on this course: lesson 1 showed why the attack surface exists at all (one flattened token stream, no hard wall). Lessons 2-4 showed real attacks exploiting that gap in three different shapes (direct, indirect, jailbreak). Lesson 5 showed that text-level defenses help but are inconsistent — genuinely honest data, not a guaranteed win. This lesson is the payoff: the reliable part of the answer isn't a better prompt, it's an architecture that doesn't need the model to be perfect.

An agent has a `send_payment` tool with no spending limit, no approval step, and a system prompt that says "never send payments without explicit user confirmation." What's the missing layer of defense?