Prompt injection is SQL injection, minus the happy ending
In the early 2000s, every web application had SQL injection. Everyone knew it was a problem. Nobody had solved it structurally. It took years — and a lot of breaches — before parameterized queries, ORMs, and safe framework defaults made the whole class mostly disappear.
That is exactly where we are with prompt injection today: the “everyone knows, nobody’s fixed it” stage.
One root cause, four decades of bugs
SQLi, XSS, command injection, buffer overflows — different bugs, one root cause. Somewhere, attacker data got interpreted as instructions. The entire arc of application security is us slowly forcing the two apart: parameterized queries, prepared statements, output encoding, argument arrays instead of shell strings.
Keep code and data in separate lanes. That single idea beat SQL injection.
An LLM’s core design does the opposite. Instructions and data arrive in the same channel, as the same tokens, and the model decides — probabilistically — which is which. There is no type system for “this is a command” versus “this is content to process.”
That’s why prompt injection has no clean fix. It isn’t a bug sitting on top of the architecture. It is the architecture.
Worse than SQLi in one important way
Parameterized queries worked because the boundary was enforced by the database, not guessed by it. You could prove a query was safe, ship the fix, and move on. Deterministic problem, deterministic answer.
With an LLM, the same input can be safe today and exploited tomorrow — and the model providers themselves will tell you, honestly, that they can’t guarantee otherwise. There is no version bump on the other side of which you are safe.
So the question changes
If you can’t make the model reliably reject malicious instructions, “how do I write a safer system prompt” stops being the interesting question. The interesting questions are one layer down:
- What sees the resulting action when the model is tricked?
- What stops it?
- What records it?
That’s a different engineering problem, and it’s the one we chronically under-invest in. The honest engineering move is to assume the boundary will fail, and put your controls around the action the agent takes, not just the input it reads.
The parameterized-query moment is coming
Here’s the part that keeps me optimistic. SQL injection went from “every app has it” to “rare misconfiguration” within a decade — not because developers got smarter, but because we built infrastructure that made the safe path the default path.
The same moment is coming for agents. Maybe it arrives at the model layer, as some enforced separation between instruction and content channels. Maybe it arrives in the system around the model, as an action boundary that treats every agent decision as untrusted until checked. Either way, the controls we can build today — visibility, authorization, and an audit trail around what agents actually do — are the prepared statements of this era, waiting to be standardized.
We’ve solved this shape of problem before. That’s not a reason for comfort. It’s a reason to build.