SQL injection (SQLi) is a web vulnerability in which an attacker inserts fragments of SQL code inside the data sent to an application, so that the database engine interprets them as part of the query rather than as plain values. When the application builds its queries by directly concatenating user input, those fragments alter the original logic: they allow reading tables that should not be accessible, bypassing authentication, modifying records or, in the worst case, executing commands on the server's operating system. It is one of the oldest and best documented web security vulnerabilities, and it still shows up in real applications in 2026.
The essentials. SQL injection arises from mixing code and data in the same string. The definitive defense is not filtering dangerous characters, but separating code and data through parameterized queries (prepared statements). The remaining layers (input validation, least privilege on the database, WAF) reinforce that separation, but do not replace it.
How SQL injection works: query interpolation
The root of the problem is dynamic query building. An application takes a value sent by the user (a name, an identifier, a search term) and inserts it into a SQL string before sending it to the engine. If that insertion is done by string concatenation, the engine cannot distinguish between what the programmer wrote and what the user supplied: everything arrives as a single statement.
Consider a login form that builds its query like this:
// Vulnerable: direct concatenation of user input
$user = $_GET['user'];
$sql = "SELECT id, email FROM users WHERE name = '$user'";
$result = mysqli_query($conn, $sql);
If the user sends admin, the resulting query is harmless. But if the user sends ' OR '1'='1' -- , the final string becomes:
SELECT id, email FROM users WHERE name = '' OR '1'='1' -- '
The condition '1'='1' is always true and the -- comments out the rest of the line, so the query returns every row in the table. On a poorly designed login, this is equivalent to signing in with no credentials. The same technique, with more elaborate payloads, allows extracting data from other tables, chaining subqueries or forcing errors that reveal the internal structure.
The correct fix separates code from data with parameters. The engine receives the query template and the values through separate channels, so the value can never change the structure of the statement:
// Safe: parameterized query with PDO
$stmt = $pdo->prepare('SELECT id, email FROM users WHERE name = ?');
$stmt->execute([$_GET['user']]);
$rows = $stmt->fetchAll();
Here the ? is a placeholder. Even if the user sends ' OR '1'='1, the engine treats it as a text literal and looks for a user whose name is exactly that string. Injection is no longer possible by design.
Types of SQL injection
Injections are classified by how the attacker retrieves the information. This taxonomy matches the one used by OWASP and by tools such as sqlmap.
In-band: union-based and error-based
In in-band injection, the attacker receives the results through the same channel as the request, directly in the application's response.
The union-based variant leverages the UNION operator to append a second query to the original one, whose results are displayed alongside the legitimate ones. First the number of columns is determined (for example with ORDER BY 3-- - or by testing UNION SELECT NULL,NULL,NULL) and then data is extracted: ' UNION SELECT username, password FROM users-- -.
The error-based variant forces the engine to produce an error whose message contains data from the database itself. Functions such as EXTRACTVALUE() or UPDATEXML() in MySQL, or type conversion in SQL Server, cause the injected fragment to appear inside the error text if the application shows it to the user.
Blind: boolean-based and time-based
In blind SQL injection the application returns neither the data nor the errors, but its behaviour changes depending on the query. The attacker infers the information question by question.
The boolean-based variant sends true or false conditions and observes the difference in the response (a page that loads or not, text that appears or disappears). With many requests a value is reconstructed character by character.
The time-based variant introduces a conditional delay and measures the response time. Each engine has its own function:
- MySQL:
' OR SLEEP(5)-- - - PostgreSQL:
'; SELECT pg_sleep(5)-- - - SQL Server:
'; WAITFOR DELAY '0:0:5'-- - - Oracle:
' AND 1=(SELECT COUNT(*) FROM all_users WHERE ROWNUM=1 AND dbms_pipe.receive_message(('a'),5)=1)-- -
If the response takes five seconds, the condition was true. It is slow but reliable, and it works even when the application shows no visible difference.
Out-of-band
When neither the response nor the timing is useful, out-of-band injection (OAST) exfiltrates data through a secondary channel, typically DNS or HTTP. The engine is forced to make an outbound request to a domain controlled by the auditor (xp_dirtree and UNC paths in SQL Server, UTL_HTTP or UTL_INADDR in Oracle, LOAD_FILE with UNC paths in MySQL). It is the preferred technique when the application is completely silent but the server has network egress.
Second-order injection
In second-order injection, the malicious value is stored first without causing harm and executed later, when another part of the application retrieves it and concatenates it into a different query. It is hard to detect with automated scanners because the entry point and the execution point are separated in time and in code.
Detection: sqlmap and manual payloads
The reference tool for automating exploitation is sqlmap, open source. It detects the injection type, identifies the engine and automates extraction:
# Enumerate databases from a GET parameter
sqlmap -u "https://target.tld/item?id=1" --batch --dbs
# Dump a specific table
sqlmap -u "https://target.tld/item?id=1" -D appdb -T users --dump
sqlmap accepts requests captured with Burp (-r request.txt), handles session cookies and tunes its techniques by level and risk. Even so, no serious audit relies on the tool alone: manual confirmation with payloads such as ', '', ' OR '1'='1, 1-1, 1 AND 1=2 or the time-based delays remains essential to understand the context, avoid false positives and find points the automator misses, such as HTTP headers, JSON fields or second-order injections. In a web audit the usual flow combines crawling and interception with Burp Suite, manual validation of each parameter and occasional use of sqlmap to speed up exploitation once the vulnerable point is confirmed.
Prevention: parameterized queries and defense in depth
Parameterized queries (prepared statements)
This is the only defense that addresses the root cause. By sending the template and the values separately, the value can never alter the structure of the statement. It is available in every language: PDO and mysqli in PHP, PreparedStatement in Java, cursor.execute(sql, params) in Python, parameterized queries in .NET, pg and mysql2 in Node.js. The rule is simple: no user data should ever be concatenated inside a SQL string.
An important caveat: parameters only work for values, not for identifiers (table or column names) or dynamic clauses such as ORDER BY. When those elements depend on user input, the correct protection is an allowlist that maps the input to a closed set of permitted values.
ORMs and their limits
ORMs (Hibernate, Entity Framework, Django ORM, Sequelize, Eloquent) parameterize by default and remove most of the risk. But they are not immune: as soon as you use raw queries (raw, extra, HQL with concatenation, native expressions), the ORM stops protecting you and the developer is again responsible for parameterizing. A misused ORM is as vulnerable as the mysqli_query at the start.
Input validation and least privilege
Input validation with allowlists (types, lengths, expected formats) reduces the attack surface, but it is a complementary layer, not a defense on its own: there will always be payloads that pass a filter. More effective is applying the principle of least privilege on the database: the account the application uses should not be able to run DROP, nor hold the FILE privilege (which enables LOAD_FILE and INTO OUTFILE), nor access more schemas than necessary. That way, even if an injection exists, the impact is contained. Segmenting accounts by function and revoking permissions on information_schema when they are not needed greatly limits what an attacker can extract.
WAF as defense in depth
A WAF (Web Application Firewall) detects and blocks known injection patterns and adds a useful layer against automated scanning and mass exploitation. But it is a safety net, not a solution: evasion techniques (encoding, inline comments, mixed casing, engine-specific alternative syntax) can bypass poorly tuned rules. A WAF buys time and filters noise, but the code still has to be parameterized.
Real cases and public CVEs
SQL injection is not a historical problem. In 2023, CVE-2023-34362 in MOVEit Transfer, a SQL injection in the file transfer web application, was exploited at scale by the Cl0p ransomware group to steal data from thousands of organizations. It is one of the highest impact incidents of the decade, and its initial vector was precisely a SQLi. Years earlier, the Heartland Payment Systems breach and several of the intrusions attributed to Albert Gonzalez also started with SQL injection against exposed applications.
In the public catalogue, SQL injection maps to CWE-89. Searches in the NVD for SQL injection return a steady stream of entries in CMS platforms, plugins, admin panels, network devices and unpatched enterprise software. The pattern repeats: a concatenated parameter, a database account with too many privileges and no parameterized queries.
Fit with the OWASP Top 10
SQL injection is classified within A03:2021 Injection of the OWASP Top 10, a category that in the 2021 edition merged classic injection with cross-site scripting. Its testing methodology is described in the OWASP Web Security Testing Guide (WSTG-INPV-05). Although the category's relative position dropped compared to earlier editions thanks to the adoption of frameworks that parameterize by default, it remains one of the most critical vulnerability classes for its direct impact on the confidentiality and integrity of data. You can see the full context in our analysis of the OWASP Top 10 2025 and in the review of the 5 most common web vulnerabilities, where injection sits alongside related vectors such as XSS and CSRF.
Frequently asked questions
Is SQL injection still dangerous in 2026?
Yes. Despite being more than two decades old, it still appears in audits and in real incidents. Cases like MOVEit (CVE-2023-34362) show that a single injection point can cause a mass breach. The risk persists in legacy code, raw queries inside ORMs, third party plugins and endpoints added without review.
Does an ORM protect me from SQL injection?
Partially. ORMs parameterize by default and remove most of the risk, but they stop protecting you as soon as you use raw queries or build fragments by concatenating user input. The responsibility to parameterize returns to the developer in those cases.
What is the difference between classic and blind SQL injection?
In classic (in-band) injection the data comes back in the response or in an error message. In blind injection the application shows neither data nor errors, but its behaviour or its response time changes depending on the query, which allows the information to be inferred question by question with the boolean-based and time-based variants.
Is a WAF enough to stop SQL injection?
No. A WAF is defense in depth: it blocks known patterns and slows automated exploitation, but evasion techniques can bypass poorly tuned rules. The real fix is parameterizing the queries in the code. The WAF complements, it does not replace.
How do I check whether my application is vulnerable?
Combine code review (looking for input concatenation in queries) with dynamic testing: manual payloads on every parameter, header and JSON field, plus occasional automation with sqlmap. The most reliable option is a professional web application audit that covers the points scanners miss, such as second-order injections.
Related resources
- Web application penetration testing
- OWASP Top 10 2025: business vulnerabilities
- The 5 most common web vulnerabilities
- What is XSS (cross-site scripting)
- What is CSRF (cross-site request forgery)
- What is SSRF (server-side request forgery)
- What is a WAF and what it is for
Auditing SQL injection with Secra
Secra performs web application audits aligned with the OWASP Top 10 and the OWASP Web Security Testing Guide. We test every parameter, header and field of the application for in-band, blind and out-of-band SQL injection, confirm findings manually, verify query parameterization and review the privileges of the database accounts to contain the impact.
We deliver prioritised findings, reproducible proofs of concept and hardening recommendations specific to your architecture, along with regression cases to integrate into CI so the vulnerability does not reappear. If you need a professional review, explore our web and mobile audit service or write to us through /en/contact/ to plan an audit adapted to the scope of your platform.
About the author
Secra Solutions team
Ethical hackers with OSCP, OSEP, OSWE, CRTO, CRTL and CARTE certifications, 7+ years of experience in offensive cybersecurity, and authors of CVE-2025-40652 and CVE-2023-3512.

