July 29, 2026

SQL Injection: How It Works and How Parameterized Queries Stop It

SQL injection happens when user input gets concatenated directly into a query string instead of passed as a separate parameter, letting an attacker's input be interpreted as SQL syntax rather than plain data. The fix is structural, not cosmetic: parameterized queries (prepared statements), which every mainstream database library supports and which make injection close to impossible by design.

SQL Formatter showing a properly indented query with WHERE clause conditions on separate lines, illustrating the kind of formatting that makes a raw concatenated variable easy to spot in review

This isn't a theoretical risk

SQL injection has been on the OWASP Top 10 list of web application security risks for two decades running, and it's still a live threat, not a solved problem from an earlier era of the web. A single hacking campaign in late 2023, for example, used SQL injection to pull over two million user records from more than 65 different websites. It's a mechanism attackers actively scan for by default, not an edge case developers rarely encounter.

The mechanism: data that gets interpreted as code

The vulnerability exists whenever user input is inserted directly into a SQL query string instead of being passed as a separate, clearly-marked value. Consider a login query built like this:

// VULNERABLE
const query = `SELECT * FROM users WHERE username = '${input}'`;

If a user types a normal username, this works fine. But if they type ' OR '1'='1 as the username, the query becomes SELECT * FROM users WHERE username = '' OR '1'='1' — a condition that's always true, potentially returning every row in the table, including data the attacker was never meant to see. More sophisticated payloads can modify data, drop tables, or exfiltrate an entire database, depending on what the application does with the query results and what permissions the database connection has.

The fix: parameterized queries

The actual solution isn't "sanitize your input more carefully" — it's structural: separate the query's logic from its data entirely, using parameterized queries (also called prepared statements). The database driver sends the SQL structure and the user's value as two distinct things, so the value can never be interpreted as part of the query syntax, no matter what characters it contains.

// SAFE
const query = 'SELECT * FROM users WHERE username = ?';
db.execute(query, [input]);

Every mainstream database library supports this pattern. There is essentially no legitimate reason to build a query by concatenating raw user input into a string in a modern codebase — if you find code doing that, it's worth treating as a bug to fix immediately, not a style preference.

Why formatting matters here too

This is one place where a formatter earns its keep beyond readability: dense, unformatted SQL with string concatenation buried mid-line is exactly the kind of code where an injection vulnerability hides in plain sight during review. Formatted, properly indented SQL makes it much easier to spot a raw ${variable} sitting inside a query string instead of a bound parameter.

Want to try this yourself?

Open SQL Formatter