Skip to content

SQL injection

CWE-89OWASP A03:2021Updated August 29, 20265 min read

SQL injection is a vulnerability that lets an attacker smuggle their own database commands in through an input field, because the application never separates input from the query. It can be used to log in without a password, read sensitive data, or alter records. The structural fix is parameterised queries (prepared statements).

SQL injection has been one of the most common and most damaging web vulnerabilities for over twenty years. The attack itself is surprisingly simple, but its consequences range from a leaked customer database to a fully compromised server. Here is what it actually is, how an attack unfolds, and what to do about it.

What is SQL injection?

SQL injection is a vulnerability that lets an attacker sneak their own SQL code into one of your application’s database queries. It happens the moment user input (a search term, a login name, a URL parameter) is pasted straight into a query without the application keeping data and commands apart.

An everyday comparison: you dictate an order to a waiter and say, “one coffee, and also ignore every order from table four.” An alert waiter writes that whole sentence down as your order. A naive waiter carries out the second half as an instruction. A database that does not separate data from commands is that naive waiter: anything that comes in can become a command.

The word “injection” captures exactly that confusion: the attacker injects their own instructions into a sentence the developers meant as harmless data. The flaw is therefore not in SQL itself, but in how the application assembles the query. Any place where input shapes a query, a filter, or a sort order is a potential entry point.

How does a SQL injection attack work?

The heart of the problem is that the query is assembled as text by gluing user input together. Take a classic login form that drops the submitted email and password straight into the query.

Vulnerable:

// User input is pasted directly into the query
const email = req.body.email;
const password = req.body.password;

const query =
  "SELECT * FROM users WHERE email = '" + email + "' AND password = '" + password + "'";

const rows = await db.query(query);
if (rows.length > 0) {
  // access granted
}

If an ordinary user enters their email address, this works fine. But an attacker does not type an address into the email field: they type ' OR '1'='1' --. The query the database ends up seeing becomes:

SELECT * FROM users WHERE email = '' OR '1'='1' --' AND password = '...'

The injected OR '1'='1' is always true, and the double hyphen -- turns the rest of the line into a comment, so the password check disappears entirely. The database returns every row and the attacker is logged in, usually as the first user in the table, which is often an administrator.

The fix is to never treat input as code. With a prepared statement (a parameterised query) you send the query and the values to the database separately. The ? placeholders are filled with data that is never interpreted as SQL.

Safe:

// Query and values travel to the database separately
const email = req.body.email;
const password = req.body.password;

const query =
  "SELECT * FROM users WHERE email = ? AND password = ?";

const rows = await db.query(query, [email, password]);
if (rows.length > 0) {
  // access granted
}

Now ' OR '1'='1' -- is just an email address that does not exist, and the login attempt fails as it should. The database knows exactly which part is command and which part is data, the very separation that makes the attack impossible.

Cleaning input yourself with search-and-replace or a blocklist of words is not reliable protection. Attackers have endless variations (different encodings, mixed case, comment tricks). Rely on parameterised queries, not on filtering.

What is the impact of SQL injection?

The severity depends on what the query is allowed to do and how the database is set up, but the reach is wide. In the mildest case an attacker reads data that was never meant for them: customer records, password hashes, order history. With a crafted query they can also change or delete records, alter prices, or grant themselves admin rights.

It often does not stop there. Through the authentication bypass from the example, an attacker logs in without any valid credentials. In certain configurations the impact reaches the underlying system: reading server files, writing a web shell, or running operating-system commands. That turns a SQL injection from a “data leak” into a “full takeover,” with all the legal and reputational fallout that follows.

A further risk is that a successful SQL injection rarely leaves an obvious trail: the query arrives through a legitimate input field and looks like ordinary traffic in the logs. Attackers use that stealth to siphon data over long periods. Because the vulnerability ranges from simply viewing data to executing code on the server, its severity runs from high to critical.

How do you detect SQL injection?

A first signal is a classic one: enter a single quote (') into an input field and see whether the application returns a database error. A visible SQL error message betrays that your input is reaching the query. Modern cases are subtler: with blind SQL injection there is no error message, and a tester measures behaviour instead: a query that deliberately delays the response, or a condition that just barely changes the result or not.

Automated scanners and tools such as sqlmap find many of these cases, but they miss the vulnerabilities that sit behind authentication, inside complex workflows, or in second-order input. A thorough penetration test therefore combines automation with manual investigation. This is exactly the kind of weak spot AssistSec pinpoints and reliably reproduces during a security assessment, so you know which queries can actually be abused.

How do you prevent SQL injection?

  • Always use parameterised queries or prepared statements. This is the single most important measure and fixes the problem at its root.
  • Lean on a mature ORM or query builder and avoid assembling raw SQL by hand. If you do add loose fragments, parameterise those too.
  • Apply the principle of least privilege. Let the application connect as a database user that can only do what it needs, no DROP, no access to system tables.
  • Validate input by type and format as an extra layer: if you expect a number, accept only a number. This complements parameterisation, it does not replace it.
  • Never show raw database errors to the user; log them internally. Error messages are a gift to an attacker.
  • Deploy a web application firewall as an extra layer, but do not rely on it as your only defence.
  • Have the code tested regularly. A focused penetration test and code review catch the cases that scanners skip.

Sources

Frequently asked questions

Is SQL injection still dangerous in 2026?

Yes. SQL injection has been in the OWASP Top 10 for years and still shows up in new applications, especially where developers build queries by hand instead of using prepared statements or an ORM.

What is the difference between SQL injection and XSS?

SQL injection targets the database behind the application; cross-site scripting runs in another visitor's browser. Both come from the same root cause: input that is not cleanly separated from code.

Does an ORM protect against SQL injection?

Mostly, as long as you use its standard methods. The moment you add raw SQL or loose fragments to an ORM query, the vulnerability can come back.

Does a web application firewall stop SQL injection?

A WAF blocks known attack patterns and is useful as an extra layer, but it is not a replacement for parameterised queries. Attackers routinely bypass filters; the real fix lives in the code.

Related articles

Press / to search · Esc