SQL Injection Prevention

SQL injection (SQLi) happens when untrusted input is interpreted as part of an SQL query instead of as data. It remains one of the most damaging web vulnerabilities — a single unparameterized query can lead to data exfiltration, data corruption, or full system compromise.

The fix is well understood and cheap: treat user input as data, never as SQL. Almost every real-world SQLi bug traces back to building a query with string concatenation.

TL;DR

Quick Example

The single most important habit — pass values as parameters, not as part of the SQL string:

How Injection Happens

When input is concatenated into a query, an attacker can change its meaning:

If email is x' OR '1'='1, the database sees:

The database can't tell your intent from the attacker's — the boundary between code and data was lost the moment you concatenated.

Common SQLi Types

The Real Fix: Parameterization

Use placeholders and bind values as parameters. The syntax differs by stack, but the principle is identical:

With an ORM or query builder, keep every value a bound parameter — never interpolate user input into a raw fragment.

The Parts You Can't Parameterize

Parameters bind values, not identifiers. Column names, table names, and sort direction can't be parameters — and that's where teams who "always parameterize" still get burned:

Defense in Depth

Parameterization is the fix; these limit the damage if something slips through.

Least privilege

Observability

See Logging for structured logging patterns.

Common Mistakes

Concatenating input into SQL

Trusting a "we use an ORM" assumption

FAQ

Does using an ORM make me safe from SQL injection?

Mostly, for normal CRUD — but not automatically. The moment you drop to raw SQL or interpolate a value into a query fragment, you can reintroduce SQLi. Keep all values as bound parameters.

Isn't escaping input enough?

No. Hand-rolled escaping is fragile and easy to get wrong across encodings and database quirks. Parameterized queries remove the need to escape because input never enters the SQL grammar.

How do I parameterize a dynamic column name or sort order?

You can't — identifiers aren't parameters. Map user input through an allowlist of known-safe column names and reject anything else.

What about search with LIKE?

Still parameterize: bind the whole pattern (e.g. %term%) as a value. Build the wildcards in application code, not by concatenating into the SQL.

Related Topics

References