SQL injection is one of the oldest vulnerabilities in web applications. The first publications date back to the late 1990s, and yet injection still ranks high in the OWASP Top 10:2025. In our web application pentests we still encounter SQL injection with some regularity, especially in custom-built applications, legacy code and in places where developers bypass the framework with hand-written queries. In this article we explain what SQL injection is, which variants we encounter in practice, how a pentester looks for it and, most importantly, how you prevent it structurally.
## What is SQL injection?
SQL injection arises when user input is insufficiently separated from the database query into which that input ends up. An application that pastes a search term directly into a SQL string gives the attacker the ability to manipulate that string. Instead of only supplying data, the attacker also supplies extra SQL code that the database then executes as part of the query. The consequences can range from reading data the user is not entitled to, to modifying or deleting data and, in the worst case, taking over the underlying server.
The core of the problem is the blending of code and data. The database cannot tell which part of the query was intended by the developer and which part was entered by a user. As long as that separation is not technically enforced, the door stays ajar.
## The variants we encounter in practice
SQL injection is not a single technique but a family. Broadly, we distinguish three main forms.
With classic, in-band injection the attacker sees the result directly in the application. This is the most visible form: the attacker alters the query and the outcome appears on screen, for example through a UNION construction that pulls extra columns from other tables.
With blind SQL injection the attacker does not see the data directly, but infers it from the behavior of the application. With boolean-based blind injection the application responds noticeably differently to a true condition than to a false one, allowing you to reconstruct data bit by bit. With time-based blind injection the attacker forces the database to wait, for example with a sleep function, and measures whether a condition was true by the response time. Blind variants are slower to exploit but at least as dangerous.
With out-of-band injection the attacker uses a second channel, for example a DNS or HTTP request that the database sends outward, to exfiltrate data. This variant is useful when the application itself gives no usable feedback.
In addition, we regularly see second-order injection: input that looks harmless at the moment of storage, but is later reused in another query and then turns out to be malicious after all. This form in particular is often missed by automated scanners, because the vulnerability only manifests in a second action.
## How a pentester looks for it
An automated vulnerability scan finds some of the simple cases, but the interesting findings almost always come from manual testing. Our approach starts with mapping all input points: not only the obvious search fields and forms, but also URL parameters, HTTP headers, cookies and hidden fields. Anywhere input can eventually end up in a query is a potential injection point.
We then test those points in a targeted way. We send input that would break the syntax of a query and watch for anomalies: a database error, a changed response, a difference in response time or an unexpected redirect. A single quote that produces a 500 error is a classic first signal. From that point we refine: confirm that we actually influence the query, determine which database type sits underneath, and estimate how far the vulnerability reaches.
We use tools such as sqlmap to speed up confirmation and exploitation, but always under manual control and within the agreed scope. The value of a pentest lies not in running a tool, but in assessing the context: is this input point reachable without authentication, what data is at stake, and what is the real impact for this organization? That translation from technical finding to business risk is where an automated scan stops and the auditor begins.
## Why parameterized queries are the solution
There are all kinds of stopgap measures against SQL injection, but only one addresses the problem at its root: parameterized queries, also called prepared statements. With this approach you send the query and the user input to the database as two separate things. The structure of the query is fixed, and the input is treated purely as data, never as executable code. That removes the blending of code and data that makes the vulnerability possible.
This is fundamentally different from escaping or filtering input. Escaping tries to render dangerous characters harmless, but is error-prone: one forgotten case, one different character set, or one place where the developer bypasses the rule, and the gap is back. Parameterized queries move the responsibility to the database driver, which enforces the separation structurally. Virtually every modern framework and ORM supports this by default; the risk arises precisely where developers bypass that abstraction with manually assembled queries.
A fair nuance: parameterization works for the values in a query, but not for structural parts such as table or column names. Anyone who wants to make those dynamic must work with a strict allowlist of permitted values instead of processing user input directly into the query structure.
## Defense in layers
Parameterized queries are the foundation, but a robust defense consists of multiple layers. Input validation based on expected format, type and length catches some of the junk early and is good hygiene, even though it is no replacement for parameterization. The principle of least privilege limits the damage: if the application account only has the database rights it truly needs, a successful injection can reach less far. Careful error handling prevents database errors with table names and query structure from leaking to the user, which would give an attacker valuable information. And a Web Application Firewall can block known attack patterns, although that is an additional barrier and never the structural solution; a WAF can be bypassed and must never be the reason not to fix the code.
## From finding to remediation
If a pentest finds a SQL injection, the remediation is usually clear: replace the vulnerable query with a parameterized variant and check whether the same construction occurs elsewhere in the code. That second step is often forgotten. SQL injection is rarely an isolated case; if a developer assembles queries manually in one place, they probably do so more often. We therefore always advise, after a finding, to search the codebase for the same pattern and to roll out the fix broadly.
After remediation comes a retest. A finding is only closed once it is demonstrable that the injection point is no longer exploitable and that the fix introduces no new problems. That verification step makes the difference between a ticked-off report and genuinely reduced risk.
Do you want certainty that your web application is resistant to SQL injection and other injection vulnerabilities? Secure Audit performs web application pentests in which we test manually and in a targeted way, translate the impact to your context and give concrete remediation advice, including a retest. Get in touch for a no-obligation conversation.
Frequently asked questions
Is SQL injection not a solved problem by now?+
No. The solution is technically known and simple, but in practice we still encounter injection regularly, especially in custom and legacy applications and where developers bypass the framework with hand-written queries. That is why injection is still in the OWASP Top 10.
What is the difference between a vulnerability scan and a pentest for SQL injection?+
A scanner finds some of the simple, directly visible cases. Blind, second-order and context-dependent injections are often missed. A pentester tests manually, confirms the vulnerability and assesses the real impact for your organization.
Does a Web Application Firewall protect against SQL injection?+
A WAF can block known attack patterns and raises the barrier, but it can be bypassed and does not fix the underlying flaw. See a WAF as an extra layer, never as a replacement for parameterized queries in the code.
What exactly are parameterized queries?+
With parameterized queries, also called prepared statements, you send the query structure and the user input to the database separately. The input is treated purely as data and never as code, which removes the blending that makes SQL injection possible.
Does an ORM automatically protect against SQL injection?+
Largely yes, because most ORMs use parameterized queries by default. The risk arises when developers bypass that abstraction with raw, manually assembled queries or dynamic query strings. That is precisely where extra vigilance is needed.
Need help with security?
How secure is your IT environment really? We test it with vulnerability scans and pentests, and guide the implementation of ISO 27001 and IEC 62443.
Explore SecurityAbout the author
Partner | IT Auditor