The vulnerability is a single line in the application. The database is doing what it is told. The bug lives at the boundary where string values from the network are pasted into a program that the database then runs.
- L1Fundamentals
- L2How databases work
- Identify the exact line of code that turns user input into SQL grammar.
- Explain why a single apostrophe is enough to break a SQL query.
- Distinguish code from data at the SQL boundary.
- Describe what the database is doing when it sees a string with unbalanced quotes.
- Trust boundary
- The line where data crosses from "user-controlled" to "trusted". In SQLi it is the spot where a form value is concatenated into a query string.
- Abstract syntax tree (AST)
- The tree the parser builds from SQL tokens. String concatenation at the application level happens before the parser ever runs - so the AST reflects attacker intent, not developer intent.
- Quoted identifier
- A value the database treats as a literal because it is wrapped in single quotes. Crossing the quote boundary turns a literal into code.
- Tautology
- A WHERE clause that is always true (1=1, "a"="a"). One of the most common SQLi primitives - it converts a filter into a no-op.
The line of code that creates the bug
Almost every SQLi vulnerability comes from one of two patterns:
// Pattern A - string concatenation
const query = "SELECT * FROM users WHERE id = " + userId;
// Pattern B - template literal
const query = `SELECT * FROM users WHERE username = '${username}'`;Both patterns look like programming - and they are. The application is building a program: a SQL query that the database will parse and execute. The user's value is being pasted into that program as if it were trusted source code. It is not. It is data that crossed a trust boundary.
The fix is to stop building programs. Send the database a program template and a list of typed values. The template is the part you wrote; the values are the part the user controls. The driver and the database cooperate to keep them separate.
Break a query with one character
Edit the username or password. Watch the query assemble live. Add a single apostrophe and the database refuses to parse it - the application crashes. Add the canonical bypass (' OR '1'='1' --) and the WHERE clause disappears.
SELECT * FROM users WHERE username = 'alice'' AND password = 'hunter2'Why every modern framework still leaks
The pattern persists because the safe path requires the developer to recognise every entry point as a potential injection site. ORMs default to safe queries, but every ORM ships a raw method (raw(), extra(), whereRaw(), exec()) that the developer reaches for when the ORM cannot express the query. Search fields, sort columns, JSON path filters, and dynamic WHERE clauses are the usual suspects. The static analysis catches most cases, but the long tail of bespoke business logic is where the breaches live.
What "safe" looks like
// SAFE - bound parameter
const query = 'SELECT * FROM users WHERE username = $1 AND password = $2';
const result = await db.query(query, [username, password]);Two changes matter. The query is now a single string literal that contains no user data. The user values travel as a separate array of typed parameters. The driver and the database know that the values are values; the parser will never treat them as code.
What to remember
- The vulnerability is a single line that concatenates user input into a SQL string.
- One apostrophe is enough to break the grammar - that break is the proof the application is parsing attacker input as code.
- The defence is to keep code and data separate on the wire: send a template, then send values.
- ORMs default to safe but leak through raw query methods - every ORM has one.
Knowledge check
0/3 answered · 0 correct1.A developer writes db.query("SELECT * FROM users WHERE id = " + req.query.id). Why is this vulnerable?
2.What does it mean for a value to "cross a trust boundary"?
3.Why does adding a single apostrophe cause a "syntax error" in the application?