SQL injection has been on the OWASP Top 10 for over two decades and still sits in the A03:2021 Injection category - the third-most-impactful class of web vulnerability. The mechanics have not changed since Phrack 54 in 1998. What has changed is the damage.
- Recognise a string-concatenation bug in a SQL query.
- Construct the canonical authentication bypass payload.
- Explain why parameterised queries are the only safe default (CWE-89).
- Map a single SQLi finding to a full-application compromise.
- SQL injection (SQLi)
- A class of bug where attacker-controlled input is concatenated into a SQL string and interpreted as code by the database (CWE-89).
- Tautology
- A WHERE clause that is always true (e.g. 1=1), used to bypass authentication and return rows the attacker should not see.
- Parameterised query
- A SQL statement that separates the code template from the data values, so the database parses code once and binds values as typed data - never as SQL syntax.
The mechanics of a string-concat bug
Most login forms run a query that looks roughly like this: SELECT * FROM users WHERE username = 'alice' AND password = 'hunter2'. If the application builds that string by interpolating values from the form, the user is in control of the query. A password field that contains ' OR '1'='1 turns the WHERE clause into a tautology, and the database returns the first row in the table. With a single short payload, the attacker is logged in as whoever happens to be at the top of the users table - usually the administrator.
The interesting part is the data type. SQL injection is not a buffer overflow, not a deserialization flaw, and not a memory corruption bug. It is a logic bug. The application is asking the database to evaluate a string, and the database is doing exactly what it was told. The fix is to stop sending the database strings and start sending it parameters.
Bypass the login panel
Type anything into the fields and watch the query assemble live in the panel below. Then try the canonical bypass: admin as the username and ' OR '1'='1 as the password. The sandbox fakes the database response - the apostrophe in the password field is what lets the OR clause escape the string literal.
SELECT * FROM users WHERE username = '…' AND password = '…'app.post('/login') handler builds the query by concatenating req.body fields - so the password input is interpreted as SQL.Why it still works in 2026
Heartland Payment Systems lost 130 million credit card numbers in 2008 to a SQLi in a payment-processing web app. It was the largest card heist in history at the time. TalkTalk, a UK telco, was breached in 2015 by a 15-year-old who found a string-concat bug in a customer lookup form - 156,959 records and roughly £77 million in cost. Modern ORMs abstract the concatenation problem away, but ORMs leak. Any time a developer reaches for a raw query, a custom filter, a search field, or a sort column, the temptation to interpolate is right there. Static analysis catches most cases, but the long tail of bespoke queries inside business logic is where the breaches live.
The fix in three lines
The defense is parameterised queries - also called prepared statements. The database parses the SQL template once, then the user input is sent as a typed value, never as SQL syntax. The driver and the database cooperate to ensure the value cannot terminate the string and inject new clauses.
// VULNERABLE - string concatenation
const query = "SELECT * FROM users WHERE username = '" + username + "' AND password = '" + password + "'";
// SAFE - parameterised
const query = 'SELECT * FROM users WHERE username = $1 AND password = $2';
await db.query(query, [username, password]);Whitelist input where possible (usernames, sort columns, enum-like values). Escape as a defense-in-depth measure, but never as the primary defense. And never, ever build SQL with template literals.
What to remember
- SQLi is a logic bug, not a memory bug - the database is doing exactly what it was told.
- A short payload in the wrong field can log an attacker in as anyone.
- Prepared statements with bound parameters are the only safe default. Escaping is a fallback for cases where prepared statements are not available (legacy code, dynamic ORDER BY).
- ORMs help, but raw queries inside business logic remain the most common injection point.
- The vulnerability has been public since 1998 and still appears in production weekly.
Knowledge check
0/3 answered · 0 correct1.What makes a SQL query vulnerable to injection?
2.You are reviewing code: db.query("SELECT * FROM users WHERE id = " + req.query.id). What is the verdict?
3.What is the role of a Web Application Firewall (WAF) in defending against SQLi?