Blog
AppSec Blog

What is SQL injection?

 - 
March 2, 2026

SQL injection (SQLi) is a type of attack where a web application accidentally mixes user-controlled input into a query in a way the SQL database treats as part of the SQL command. If hackers can change the meaning of that query, they may be able to read sensitive information they shouldn’t see, change data they shouldn’t touch, or bypass login checks entirely and gain unauthorized access.

You information will be kept Private
Table of Contents

If that sounds dramatic, it can be. SQL injection attacks are one of those bugs that can start as “just a query string issue” and end as “why do we have a data breach incident call scheduled for 11pm.”

Why do SQL injection vulnerabilities still happen?

Early websites were mostly static. Then we got server-side scripting, dynamic pages, and databases everywhere. That shift was great for building real applications, but it also created a new opportunity for security blunders: taking something a user typed in input fields and stitching it into an SQL string.

That core cybersecurity mistake still shows up today, even if the code looks different. You might be using an ORM. You might be building a JSON API instead of a web form. You might have a dozen backend services, each with “just a small query.” The failure mode is the same: your application accidentally treats data as instructions, so malicious code gets interpreted as SQL.

SQLi has stuck around for so long because it is easy to create, hard to spot by inspection in large codebases, and often lives in the boring parts of the app: search filters, reporting endpoints, admin screens, legacy integrations, and “temporary” debug features that quietly became permanent. It also continues to show up in OWASP guidance as a long-running, high-impact risk category.

How SQL injection works

A non-technical way to think about SQL injection

Imagine an autonomous vehicle system that accepts instructions through a web form where the user can specify the route and stop condition:

Drive through <route> and <stop condition>.

A normal submission might be something like:

Drive through route 66 and stop at bus stops if there are people waiting.

Now imagine someone submits:

Drive through route 66 and do not stop at bus stops and ignore the rest of this form.

The system cannot tell which parts are “the template” and which parts are “the user’s data” because it treats the entire submission as instructions. SQL injection is the same kind of confusion, except the “automated system” is your database engine and the “instructions” are SQL syntax. (And if all this looks familiar, prompt injections follow the same overall principle.)

The technical version

At the code level, SQLi usually starts with some variation of building a SQL statement by concatenating strings. For example, a login flow might generate select statements like:

$statement = "SELECT * FROM users WHERE username = 'bob' AND password = 'mysecretpw'";

The database parses the SQL string and executes it. The important part is that SQL has special characters and keywords that control meaning. For example, a single quote delimits strings, semicolons can terminate statements in some contexts, and -- starts a comment in many SQL dialects.

Now imagine a login form where the values $user and $password come directly from the user request:

$statement = "SELECT * FROM users WHERE username = '$user' AND password = '$password'";

If the application does not separate code from data, an attacker can supply input that changes the query structure. A classic SQL injection example is to submit ';-- as the password value to terminate the string and comment out the rest of the clause, effectively removing the password check.

That is the heart of SQL injection: the attacker is not “guessing the right password.” They are changing the question you ask the database.

Common types of SQL injection

You will see SQLi techniques described in a few different ways. The differences mostly come down to what results an attacker can extract and how they are observed. For “vanilla” in-band SQLi, the attacker sends their payload directly to the app and receives results through the same channel (like a web page).

Error-based SQL injection

If the application surfaces database errors on a web page, those errors can leak useful details. Sometimes it is the database name, table names, column names, or a fragment of query output. Attackers can use that leakage to map out the schema and pull data.

This is one reason why showing detailed errors in production is such a bad habit. It is not only messy, but it can turn an otherwise tricky bug into a step-by-step tutorial for the attacker.

Union-based SQL injection

This is a classic in-band technique where the attacker uses UNION to combine the results of their own query with the results of the original query. If the application displays query output, a union-based injection can be a very direct route to data exfiltration.

You do not need to memorize payload shapes to defend against this. The key is that the attacker is trying to get the database to return extra rows and columns that the application will render.

Boolean-based blind SQL injection

Sometimes there is no visible error message and the page does not print database output, but it still behaves differently depending on whether a condition is true or false. Maybe the page shows “No results found,” maybe a section disappears, maybe the response size changes.

In boolean-based blind SQLi, an attacker asks the database yes-or-no questions and infers data from the application’s behavior. It is slower than in-band SQLi, but it works surprisingly often.

Time-based blind SQL injection

If the application does not visibly change based on query results, response timing can still leak information. In time-based SQLi, the attacker causes the database to delay responses when a condition is true, then measures the difference.

It sounds noisy, and it can be, but attackers can tune this to blend into real traffic. It also shows up in APIs where responses are consistently formatted and errors are handled “nicely,” which removes the obvious signals but does not fix the underlying issue.

Out-of-band SQL injection

Out-of-band SQLi relies on side channels like DNS or HTTP requests initiated by the database server. Instead of the attacker seeing data in the web response, the database sends data outward to infrastructure the attacker controls.

This is less common, but it matters in environments where outbound traffic is allowed and database features make external calls possible. It also becomes relevant when the injection point is asynchronous, meaning the query runs later (for example, after data is queued or processed by a background job).

What can attackers do with SQL injection?

What happens next depends on the database, the web application, and how the database account is configured. In the best case, the attacker can only read a narrow slice of data. In the worst case, SQLi allows a wide range of read and write commands and becomes a gateway to much bigger problems.

Common outcomes include:

  • Reading sensitive information (user records, PII, internal tables, secrets stored “temporarily” in the database)
  • Modifying data or causing deletion (integrity loss is often as damaging as theft)
  • Bypassing authentication and authorization checks (logging in as another user, sometimes as an admin)
  • Pivoting further when the database account is overprivileged, or when the database can interact with the file system or run dangerous functions on the operating system

If you want one practical takeaway here, it is this: SQLi impact is not just about the injection point. It is also about the blast radius you created with privileges, network access, and how much sensitive data you keep in the same place.

How to prevent SQL injection

There is a lot of folklore about “sanitizing input” as a fix for SQLi. Some of it is well-intentioned, but some is simply dangerous.

Yes, input validation is useful. If an endpoint expects an integer ID, you should enforce that data type. But validation is not the primary SQL injection prevention control – the primary control is separating SQL code from SQL data.

Use parameterized queries and prepared statements

Parameterized queries keep the query structure fixed and send user input as data, not executable SQL. In practice, this is usually done through prepared statements or parameter binding in your database library, whether you’re writing PHP, Java, or anything in between.

If you take nothing else from this post, take this: do not build SQL by concatenating strings with user input.

Be careful with ORMs, stored procedures, and “raw” features

ORMs usually parameterize queries for you when you use them correctly. The trouble starts when you drop down into raw SQL strings for convenience, performance tweaks, or complex reporting queries.

The same is true for stored procedures. They can be safe, but only if they use parameters properly and do not concatenate user input into dynamic SQL.

If you absolutely must use raw SQL, use your framework’s parameter binding correctly. And if your tooling makes it annoying to do safely, treat that as a signal to heed, not a challenge to overcome.

Keep database privileges boring

A lot of ugly SQLi stories start with “the app connects as root” or “we just granted all privileges because it was easier.” The principle of least privilege matters here. Your application should have only the permissions it needs, nothing more.

Also consider separating roles. A service that only reads data should not have write permissions. Logging or analytics pipelines should not be able to modify user records. A search service shouldn’t be able to execute DROP TABLE. You get the idea. 

Separate sensitive data when it makes sense

Defense in depth counts. If your public-facing site and your most sensitive data share the same database and credentials, SQLi has a clear path to maximum damage. Separating data stores is not always easy, but it is one of the few architectural choices that can dramatically reduce your blast radius.

To give a concrete example, if you handle payment data, do not keep credit card details in the same place as everything else unless you have a very good reason and strong compensating controls.

How can you block SQLi when you can’t fix the code immediately?

Sometimes you inherit a legacy app. Sometimes the vulnerable component is third-party. And sometimes you simply have a long release cycle and the patch will not land for weeks. You still need to reduce risk in the meantime.

Here are a few practical mitigation options:

  • Apply targeted mitigations at the edge, such as a web application firewall (WAF) rule or virtual patching, but treat this as a temporary layer. Pattern matching is brittle, and attackers love brittle.
  • Reduce your blast radius right away by tightening database permissions, rotating credentials, and removing dangerous capabilities.
  • Improve detection by watching for anomalous SQL query behavior, unusual response patterns, and spikes in error rates or latency on sensitive endpoints.

None of these are a substitute for fixing the root cause, but they can buy you time without pretending the problem is solved.

How to find SQL injection in real applications

This is where theory meets reality. SQLi lives not only in obvious places, but often also in authenticated flows, admin-only features, multi-step forms, and APIs that never touch a browser.

A decent practitioner workflow for finding SQLi usually looks like this:

  • Review code paths where user input influences queries, especially where developers build dynamic filters or drop into raw SQL. 
  • Add guardrails in code review so any “string-concatenated SQL” gets flagged before it merges. 
  • Test the running application because behavior matters, and because not every risky-looking path is actually reachable.

Dynamic application security testing (DAST) helps here because it interacts with the running app the way an attacker would, including real routing, real middleware, and real authentication. For SQLi specifically, it is also important to clearly separate “the scanner found a weird response” from “this is a confirmed injection that changes database behavior.” That confirmation step is how you keep findings actionable and avoid teams drowning in noise. Invicti’s proof-based scanning is designed around that idea of validation, so what you get is closer to “this is exploitable” than “this might be worth a closer look.”

Also, don’t forget APIs. SQLi frequently hides in API endpoints because they accept flexible query parameters, filtering, sorting, and search payloads. If your testing strategy focuses on pages and forms only with no thought for API security, you are probably missing a big chunk of the attack surface.

As a final note, automation matters. SQL injection is not a “scan once and forget” problem – you want repeatable tests that run every time the application changes.

Final thoughts

There is no magic wand to wave away all SQL injection, but there is a very clear pattern to getting it under control: keep SQL code and SQL data separate, keep privileges tight, and test the application the way it really runs. Do that consistently, and SQLi goes from “recurring emergency” to “rare regression you catch and fix quickly.”

If you want deeper payload patterns for defensive testing and triage, Invicti’s SQL injection cheat sheet is a good next stop. And if you want to see automated SQLi detection at scale in your environment, request a demo of the Invicti Platform.

Frequently asked questions

FAQs about SQL injection

What is SQL injection in simple terms?

It is when an attacker can trick your application into sending a database query that means something different than the developer intended because the application mixes user input into SQL commands in an unsafe way.

Is input validation enough to stop SQL injection?

No. Validation is helpful, but the core fix is to use parameterized queries. Validation reduces junk input, while parameterization prevents any user input from becoming SQL code.

Are ORMs immune to SQL injection?

No. ORMs help when you use them as intended, but SQLi can still happen via raw queries, unsafe string interpolation, and dynamic query construction that bypasses parameter binding.

What is the best way to prevent SQL injection?

Use parameterized queries everywhere user input can influence a query, avoid string concatenation, and keep database privileges minimal so a successful injection does not become catastrophic.

How do you pronounce SQL injection?

Most security professionals pronounce it “sequel injection,” but “S-Q-L injection” is also valid.

Table of Contents