Prompt Injection Is a Code Review Problem, Not Just a Model Problem

Editorial illustration: untrusted content belongs outside the instruction boundary.

Most teams shipping an LLM agent today have a SQL injection checklist for their API layer and nothing equivalent for the prompt layer. That gap is the whole problem: prompt injection isn’t a model weakness you patch by swapping providers, it’s an input-validation defect in your code, and it shows up in predictable places if you know where to look.

Where it actually lives

Prompt injection findings in a real review cluster around three spots:

  1. Untrusted content concatenated into the system or tool-result context. A support ticket body, a scraped web page, or a file the agent just read: anything an attacker can influence that lands in the context window without being clearly delimited from instructions.
  2. Tool definitions with no permission boundary. If the model can call a tool that deletes data, sends email, or hits an internal API, the question isn’t “would the model choose to do that”? It’s “what happens when injected text tells it to.“
  3. Multi-agent handoffs. An orchestrator that passes a sub-agent’s raw output to another sub-agent (or back to a tool) without re-validating it is a confused-deputy chain, not a single trust boundary.

A minimal review pattern

Example: unsafe Python-style context assembly

This is simplified Python-style application code, not a snippet from a specific AI SDK. It represents the kind of helper function an LLM agent might use to combine a user request and documents retrieved from a knowledge base before sending them to a model. The highlighted problem is that the retrieved documents are treated as trusted instructions.

def build_context(user_input: str, retrieved_docs: list[str]) -> str:
    # BAD: retrieved_docs are concatenated as if they were trusted
    return f"{SYSTEM_PROMPT}\n\n{user_input}\n\n" + "\n".join(retrieved_docs)

The fix isn’t a smarter prompt. It’s the same boundary discipline as any other injection class: label untrusted spans explicitly, strip or refuse content that mimics instruction syntax, and scope tool permissions so that even a fully “successful” injection can’t reach anything destructive.

What to bring to the next review

If your team already runs security review on pull requests, the checklist to add is short: where does untrusted text enter the context, what can the model call as a result, and what’s the blast radius if it calls the wrong thing on purpose. That’s the same question application security has asked for twenty years, but it has a new place to be asked.