TL;DR: All three are untrusted data crossing into an interpreter in the same channel as code, so the interpreter parses part of the data as instructions. Parameterisation fixes SQL injection structurally: the database parses the statement before the values arrive, so values can never change the statement's shape. The equivalents elsewhere are argument arrays without a shell for commands and rendering data into fixed templates. Prompt injection belongs to the same class but has no parameter mechanism, which is why its defences focus on limiting impact.
How to approach it
Name the common cause in one sentence, then show the structural fix for each interpreter. Explain why parameterisation works at the level of parsing, contrast it with escaping, and finish with the connection to prompt injection.
A strong answer
String-built query
Query text + user value
one string
Parser reads value as code
structure changes
Also shell and templates
Outcome, unsafe: Injection
Same root cause everywhere
Parameterised query
Statement parsed first
placeholders only
Values bound later
never parsed
Structure fixed
Outcome, safe: Structurally safe
Values cannot become code
The common cause. An application builds input for an interpreter (SQL engine, shell, template engine) by combining its own code with data, and the boundary between them is decided by parsing that combined text. Data that contains the interpreter's syntax changes the code.
| Interpreter | Vulnerable pattern | Structural fix |
|---|---|---|
| SQL | f"... WHERE name = '{name}'" | Placeholders: "... WHERE name = ?", values passed separately |
| Shell | os.system(f"convert {path} out.png") | subprocess.run(["convert", path, "out.png"]), no shell |
| Template engine | Template(user_text).render() | Template("Hello {{ name }}").render(name=user_text), sandboxed engine |
Why parameterisation works. With a prepared statement, the database receives the SQL text with placeholders, parses and plans it, and only then binds values into the slots. The parse tree is fixed before any untrusted byte arrives, so a value containing ' OR '1'='1 is compared as a string literal. Escaping instead tries to transform data so it cannot break out of a context; it depends on the exact database, character set and context, and fails in places like numeric fields or identifiers.
Where parameters do not apply. Table and column names, sort directions and other identifiers cannot be placeholders. Map user choices to an allowlist of known identifiers in code.
Second layer. A least-privilege database account and no shell access for the application user limit what a missed injection can do.
The bridge to AI. A language model receives instructions and data as one token sequence with no parameter slot, so data can always act as instructions. That is why prompt injection defences focus on what the model can reach (scoped tools, authorization in code, output handling, egress control) rather than on making text inert. And model output fed into SQL or shells is untrusted input, so it gets the same parameterisation and argument-array treatment.
What interviewers probe next
- "Do ORMs prevent SQL injection?" For their normal query builders, yes; raw query methods and string-built filters reintroduce it.
- "How would you find injection in a codebase?" Search for string-built queries and shell calls, use static analysis rules, and review every sink that takes model or user output.
- "Is stored procedure use a fix?" Only if the procedure itself does not build dynamic SQL from its parameters.
What if?
What if · interview follow-ups
Hold your answer as the constraints change
A search endpoint builds a SQL query by concatenating the user's search term into the WHERE clause, and the same team is adding an LLM feature that summarises results.
Start here
What do SQL, command and template injection have in common?
Where do data and code meet?
Untrusted data crosses into an interpreter in the same channel as code, so the interpreter parses part of the data as instructions. The fix in each case separates the channels so data cannot change the structure of what runs.
Carry it forwardInjection is data parsed as code in a shared channel.
Weak answerTreating each injection type as unrelated.
Constraint changes
Why does parameterisation fix SQL injection structurally?
When does the database parse the statement?
The database parses the statement before the values arrive, so values can never change the statement's shape. Escaping tries to make data safe inside the code channel; parameterisation removes the shared channel.
Carry it forwardParameterisation separates code from data.
Weak answerRelying on escaping or blocklists.
Constraint changes
What are the equivalents for commands and templates?
How do you run a program without a shell?
For commands, argument arrays with no shell, so arguments are never parsed as shell syntax. For templates, render data into fixed templates rather than building templates from input.
Carry it forwardArgument arrays and fixed templates.
Weak answerBuilding shell strings with quoting.
Constraint changes
Where does prompt injection fit?
Is there a way to separate instructions from data in a prompt?
It belongs to the same class: untrusted text and instructions share the model's context. But there is no parameterised query for language models, so the fix moves to containment: limit what the model can do, validate its outputs and enforce authority in code.
Carry it forwardPrompt injection shares the class but lacks a structural fix.
Weak answerClaiming delimiters parameterise prompts.
Constraint changes
What if the LLM output is used to build the SQL query?
Who wrote the query fragment?
Then model output is another untrusted source. Let the model choose from fixed options (fields, operators) and build a parameterised query in code, with the user's permissions applied. Never execute model-written SQL directly.
Carry it forwardModel output feeding interpreters is untrusted input.
Weak answerTrusting SQL the model writes.
Now defend it
How would you fix the endpoint and guard the new feature?
Replace concatenation with a parameterised query; use argument arrays and fixed templates wherever other interpreters appear; treat model output as untrusted input, letting the model pick from fixed options that code turns into parameterised queries; and contain prompt injection by limiting what model output can do.
How it's scored
Weak: Lists the three bugs without a common cause, or recommends escaping as the primary fix.
Hire: Names the shared root cause and gives the structural fix per interpreter, explaining parse-before-bind.
Strong Hire: Covers identifiers and allowlists, least privilege as a second layer, and connects the class to prompt injection and model output correctly.
Common mistakes
- Calling input validation alone a fix for SQL injection.
- Using
shell=Truewith "sanitised" strings. - Assuming ORMs make every query safe.
- Claiming prompt injection can be fixed with escaping.