- SQL injection lets attackers insert malicious SQL code into input fields to manipulate database queries, extract data, bypass authentication, or destroy records.
- The primary fix is parameterised queries (prepared statements). This is non-negotiable. No other control replaces it.
- Input validation, stored procedures with fixed logic, and least-privilege database accounts are layered defences that reduce attack surface.
- WAFs detect and block known SQLi patterns but are not a substitute for fixing the underlying vulnerability in code.
- SQL injection remains in the OWASP Top 10. It caused the 2012 LinkedIn breach (117 million credentials), the 2015 TalkTalk breach, and the 2021 Twitch source code leak.
- As a developer, run your own SQLi tests using OWASP ZAP or Burp Suite Community before your application goes to production.
SQL injection is 25 years old. It was first documented in 1998. It remains in the OWASP Top 10 in 2026 as one of the most exploited web application vulnerabilities in existence.
That longevity is not because it is complicated. It is because developers continue to build database queries using string concatenation, treating user input as trusted code. This checklist explains why that happens, what SQL injection looks like in practice, and the exact steps to prevent it in your application.
What is SQL injection?
A web application takes user input, such as a username or search query, and builds a database query using that input. If the application constructs the query by concatenating the user’s input directly into the SQL string, an attacker can supply input that changes the structure of the query itself.
Consider a login form that queries the database like this:
SELECT * FROM users WHERE username = '[username]' AND password = '[password]'
A normal user enters their username and password. The query works as intended. An attacker enters this as the username:
admin' --
The resulting query becomes:
SELECT * FROM users WHERE username = 'admin' --' AND password = ''
The double dash comments out the rest of the query. The password check never executes. The attacker logs in as admin without knowing the password.
SQL injection types: what attackers can do
| Type | Example attack input | What the attacker achieves |
|---|---|---|
| Classic in-band SQLi | ' OR '1'='1 | Bypasses login by making the WHERE clause always true |
| UNION-based SQLi | ' UNION SELECT username, password FROM users-- | Appends a second query to extract data from another table |
| Error-based SQLi | ' AND 1=CONVERT(int, (SELECT TOP 1 name FROM sysobjects))-- | Forces database error messages that reveal schema information |
| Blind Boolean SQLi | ' AND 1=1-- (true) vs ' AND 1=2-- (false) | Infers data by observing true/false differences in application response |
| Blind time-based SQLi | '; IF (1=1) WAITFOR DELAY '0:0:5'-- | Infers data by causing deliberate time delays in database response |
| Second-order SQLi | Malicious input stored, then later used in a query unsanitised | Exploits data that was safely stored but unsafely retrieved later |
Second-order SQL injection defeats input sanitisation at the point of entry. Data that was safely stored is later retrieved and used in an unsafe query. Developers who test only at input fields miss this entirely.
The prevention checklist
1 Parameterised queries (prepared statements): non-negotiable
This is the primary fix. A parameterised query separates the SQL structure from the data. The database compiles the query structure first, then binds user-supplied values as parameters. User input cannot change the query structure because it is never interpreted as SQL code.
Python with SQLite:
cursor.execute(
'SELECT * FROM users WHERE username = ? AND password = ?',
(username, password)
)
Java with JDBC:
PreparedStatement stmt = conn.prepareStatement(
"SELECT * FROM users WHERE username = ? AND password = ?"
);
stmt.setString(1, username);
stmt.setString(2, password);
PHP with PDO:
$stmt = $pdo->prepare(
'SELECT * FROM users WHERE username = :username AND password = :password'
);
$stmt->execute(['username' => $username, 'password' => $password]);
Many developers believe they can sanitise their way out of SQL injection by escaping characters. Escaping is fragile. Encoding mismatches, multi-byte character sets, and second-order injection all break it. Parameterised queries are structurally safe. Escaping is not.
2 Stored procedures with fixed logic
A stored procedure is a predefined SQL routine in the database. If the procedure accepts parameters and does not concatenate them into dynamic SQL internally, it provides the same structural separation as a parameterised query.
Stored procedures are not automatically safe. A stored procedure that builds dynamic SQL internally using EXEC or sp_executesql with concatenated input is just as vulnerable as inline string building. Stored procedure usage must be combined with parameterisation of the inputs.
3 Input validation: reduce the attack surface
Validate inputs against what you expect. A field that should accept a user ID should only accept integers. A field that should accept a username should only accept alphanumeric characters within a defined length. Reject anything that does not match the expected pattern before it reaches the database layer.
Input validation is a reduction of attack surface, not a prevention of SQL injection on its own. Attackers who understand encoding, multi-byte characters, and application logic can bypass client-side and many server-side validation patterns. It slows attackers down. It does not stop them without parameterised queries underneath.
4 Least-privilege database accounts
The database account your application uses to connect should have only the permissions required for its function. A read-only application needs only SELECT. An application that writes orders needs INSERT on the orders table, nothing else.
An application running as a database administrator account multiplies the damage of any SQL injection vulnerability. The attacker can read, write, delete, and in many database configurations execute system commands. Least privilege limits what an attacker can do even when injection succeeds.
- Revoke
DROP,TRUNCATE, andALTERfrom application accounts. - Use separate accounts for read and write operations where practical.
- Never use the database root or
saaccount in application connection strings.
5 Web Application Firewall (WAF): detection, not substitution
A WAF inspects incoming HTTP requests and blocks or flags patterns that match known SQL injection signatures. It adds a layer of detection that can catch automated scanning and some manual injection attempts. It is not a substitute for parameterised queries.
Skilled attackers encode payloads, use time-based blind injection, or chain application logic in ways that WAF signature rules do not detect. If your application is vulnerable, a WAF provides a speed bump. It does not fix the code.
6 Error handling: do not expose database structure
Verbose error messages that include SQL syntax, table names, column names, or stack traces give attackers the information they need to refine their injection attempts. Error-based SQL injection specifically exploits this by causing deliberate errors to extract schema information.
In production, show generic error messages to users and log detailed errors to a secure, access-controlled system. Never expose raw database errors in HTTP responses.
7 Test your own code before someone else does
Run SQL injection tests on your application before it reaches production. OWASP ZAP (free, open-source) and Burp Suite Community Edition (free) both automate SQLi testing against running applications. sqlmap is the most widely used command-line SQL injection testing tool.
Manual testing with the input patterns in the table above on every user-input field in your application takes two to three hours. Automated scanning with ZAP takes 15 minutes to set up. Both are faster and cheaper than discovering a vulnerability in production.
SQL injection in the real world: why this still matters
- 2012 LinkedIn breach: 117 million user credentials exposed. SQL injection was among the attack vectors used to access the database.
- 2015 TalkTalk breach: 157,000 customer records stolen. A 15-year-old used SQL injection against an unpatched legacy database. Total cost to TalkTalk: £77 million.
- 2021 Twitch source code leak: SQL injection contributed to the access chain that exposed Twitch’s source code and creator payout data.
These are not obscure targets or unusual attack sophistication. They are organisations with security teams, compliance requirements, and significant engineering resources. SQL injection succeeded because parameterised queries were not used consistently across all database-touching code.
SQL injection as a cybersecurity career skill
Understanding SQL injection from both sides, how to find it and how to prevent it, is a core competency for both AppSec engineers and penetration testers. AppSec engineers integrate prevention into development pipelines. Penetration testers use SQLi testing to prove real-world risk to clients. Both roles appear in the top-paid cybersecurity specialisations.
Explore the Metana Cybersecurity Bootcamp
Metana’s Cybersecurity Bootcamp covers ethical hacking methodology, web application security, and vulnerability assessment. No prior background required. Job guaranteed or tuition back within 180 days.
Explore at metana.io/cybersecurity-bootcamp →FAQ
What is SQL injection?
SQL injection is a web application vulnerability where an attacker inserts malicious SQL code into an input field. If the application constructs database queries by concatenating user input directly into SQL strings, the attacker’s code executes as part of the query, potentially bypassing authentication, extracting data, modifying records, or deleting the entire database.
What is the best way to prevent SQL injection?
Parameterised queries, also called prepared statements, are the primary and most reliable prevention. They separate SQL structure from user data, so input is always treated as a value and never as executable code. No amount of input sanitisation or escaping is as structurally reliable as parameterisation.
Can a WAF prevent SQL injection?
A WAF can detect and block many SQL injection patterns, especially automated attacks. It is not a substitute for fixing the underlying vulnerability. Skilled attackers encode payloads or use blind injection techniques that bypass WAF signature rules. A WAF adds detection capability. Parameterised queries fix the root cause.
What is a SQL injection example?
A login form that builds its query as SELECT * FROM users WHERE username = '[input]' AND password = '[input]' is vulnerable. An attacker who enters admin' -- as the username causes the query to become SELECT * FROM users WHERE username = 'admin' --' AND password = ''. The password check is commented out and the attacker logs in as admin without the correct password.
How do I test my application for SQL injection?
OWASP ZAP and Burp Suite Community Edition both automate SQL injection testing against running web applications for free. sqlmap is the most widely used command-line tool for SQL injection detection and exploitation in authorised testing. Manual testing involves entering known SQL injection patterns (single quotes, OR 1=1, comment sequences) into every user-input field and observing application responses.


