SQL Injection
How unsafe queries expose your database and how to write safe ones
Overview
SQL injection occurs when user input is concatenated directly into a database query, letting attackers change the query's meaning to read, modify, or delete data. It is one of the oldest and most damaging web vulnerabilities. The reliable fix is to use parameterized queries so input is always treated as data, never as code.
Syntax / Usage
Never build SQL by string concatenation. Use parameterized queries (prepared statements) where the driver safely binds values.
// VULNERABLE: input becomes part of the SQL
const email = req.body.email;
db.query("SELECT * FROM users WHERE email = '" + email + "'");
// email = "' OR '1'='1" -> returns every user
// SAFE: parameter is bound, never interpreted as SQL
db.query("SELECT * FROM users WHERE email = $1", [email]);
Examples
Parameterize every value, including those in INSERT and UPDATE:
db.query(
"INSERT INTO posts (title, body, author_id) VALUES ($1, $2, $3)",
[title, body, authorId]
);
When using an ORM or query builder, let it handle escaping:
// Prisma binds parameters for you
await prisma.user.findUnique({ where: { email } });
Common Mistakes
- Concatenating or interpolating user input into query strings
- Believing input validation alone prevents injection (it does not)
- Using dynamic column or table names from user input without an allowlist
- Running the app with an over-privileged database account
- Exposing raw database errors that reveal schema details to attackers
See Also
web-security-fundamentals web-security-owasp-top-ten web-security-authentication