In Production · AI · Backend · Frontend
Prompt injection is our generation’s XSS
XSS and XSRF are the same flaw: a system that cannot tell data from instructions, or that acts with authority nobody asked for. LLMs inherited both.
Picture a web app that keeps a JWT in localStorage, valid for two hours. One of its pages has an input, and whatever you type is shown to everyone who visits later. An attacker types a script into it. From then on every visitor’s browser runs that script and hands over the token, and the attacker can use their accounts for up to two hours.
The fix is almost boring: write the text with textContent instead of innerHTML, or sanitize it before it reaches the DOM. The browser has a reliable way to say “this is text, not code”, and the hole closes.
Its cousin, XSRF, is about a different mistake. Cookies go along with any request to a site, even when another site triggers it, and even through an invisible iframe that makes you click something you never saw. The browser acts with an authority the user did not grant in that click.
Now look at an LLM assistant. It reads text from outside, tickets, emails, documents, web pages, and it usually has tools: send an email, query data, create records. Data and instructions travel in the same channel, and authority rides along without anyone asking. It is the old mix, both flaws at once.
Loading interactive figure…
Static version: with no defenses, the ticket text becomes an instruction and the assistant tries to call send_email; with the tool off the allowlist, the call is blocked.
With no defenses, the ticket becomes an order. Fencing the untrusted text helps until the attacker closes the fence themselves; try the third preset. What actually holds is taking the tool away from the task. Summarizing does not need send_email, and any side effect waits for a person to confirm it.
Nothing to escape with
XSS got solved because the browser can draw a hard line around text. A model cannot. You can ask, fence, repeat and warn, and there is still no guaranteed escape. So the defense has to move away from the input and onto privilege. What the model is allowed to do matters more than what it read.
In my XSS demo a stolen token lasted two hours. For an agent with tools, the window is a single call. I treat everything a model reads as untrusted, including our own documents. I give each task the fewest tools it needs. And model output is rendered as text, never piped into innerHTML, SQL or a shell.