A web server that renders a user's comment without escaping it has a textbook cross-site-scripting bug, and the fix is decades old: never let untrusted input execute as code in a trusted context. An LLM application has the same shape of problem with no equivalent decades-old fix, because the model's entire interface is a context window where every token — the developer's system instructions, the user's message, a retrieved document, a tool's return value — sits in the same undifferentiated stream. The model was trained to follow instructions wherever they appear in that stream, which means text that was never supposed to carry authority can carry it anyway, simply by being phrased like an instruction.
This is the trust boundary this course keeps returning to: the model's own reasoning loop is a trusted execution environment, but a large fraction of what feeds into that loop is untrusted content the model reads rather than the developer's own words. A support agent that retrieves a customer's past ticket to summarize it is reading untrusted text; a research agent that fetches a webpage is reading untrusted text; a coding agent that reads a file from a cloned repository is reading untrusted text. None of that content went through the scrutiny the system prompt did, and all of it lands in the same context the system prompt occupies.
Understanding exactly why this boundary is architectural, not a bug someone forgot to patch, is what makes the defenses in Lessons 3, 4, and 6 make sense rather than feel like arbitrary extra work — they exist because there is no simpler fix available.