When user input is concatenated or interpolated directly into a SQL string, an attacker can supply input that changes the query's meaning, reading or destroying data they were never allowed to touch. The fix is to pass user values as bound parameters so the database treats them as data, never as SQL.
Why it's a problem
A single injectable query can expose your entire database. Input like ' OR '1'='1 turns a login check into one that always passes, and more elaborate payloads can dump other tables, modify records, or drop them. Because the query still works for normal input, the bug often ships unnoticed until someone probes it.
The pattern
// user input becomes part of the SQL text const q = "SELECT * FROM users WHERE email = '" + email + "'"; db.query(q);
The fix
// the value is bound as a parameter, never parsed as SQL
db.query("SELECT * FROM users WHERE email = $1", [email]);
// most ORMs parameterize for you
await prisma.user.findUnique({ where: { email } });Why AI tools write this
Template literals make interpolating a variable into a query string the most natural-looking way to write it, so an assistant building a quick data-access helper will often concatenate the value rather than parameterize it. The result reads cleanly and returns the right rows in testing, which is exactly why the injection risk survives review.
The quick fix
- Use parameterized queries (bound parameters) for every value that comes from a request.
- Prefer an ORM or query builder that parameterizes by default.
- Never build a query by concatenating or interpolating request data into the SQL string.