SQL injection, commonly shortened to SQLi, is a web application vulnerability that occurs when user-controlled input is allowed to interfere with a database query.
Instead of treating the user's input only as data, a vulnerable application may accidentally allow that input to change the meaning or structure of the SQL command sent to the database.
As a result, an attacker may be able to access information they should not see, alter application behaviour, modify records or, in more serious cases, gain broader database access.
The underlying problem is surprisingly simple:
The application fails to keep SQL instructions separate from user-supplied data.
OWASP explains that SQL injection commonly appears when applications build dynamic database queries using string concatenation together with user input. MITRE classifies the weakness as CWE-89: Improper Neutralization of Special Elements used in an SQL Command.
Therefore, understanding SQL injection is less about memorising attack commands and more about understanding how information moves from a user, through an application, and into a database.
What Is SQL Injection?
SQL injection is a security vulnerability in which externally controlled input can change the intended SQL query executed by an application.
A normal application might receive information such as:
- a username,
- a product category,
- a search term,
- a customer ID,
- a date,
- or a filter.
The application then uses that information to retrieve the appropriate records from a database.
For example, a product page may need to ask a database:
SELECT * FROM products
WHERE category = ?The ? represents a value supplied separately by the application.
In a properly designed query, the database understands that the supplied value is data, not part of the SQL command itself.
However, problems arise when the application directly combines user input with the SQL statement.
In that situation, specially crafted input may interfere with the surrounding query.
PortSwigger describes SQL injection in similar terms: user-controlled data is incorporated into an SQL query in an unsafe manner, allowing the input to interfere with the structure of the query.
How Does SQL Injection Work?
The easiest way to understand SQL injection is to follow the complete request path.
A database-driven web application generally works like this:
User
↓
Web page or API
↓
Application code
↓
SQL query
↓
Database
↓
Result returned to application
↓
Result displayed to user
Normally, each layer has a clear responsibility.
The user provides information.
The application decides what query should be performed.
Finally, the database executes that predefined query.
SQL injection occurs when those boundaries become blurred.
Step 1: The User Sends Input
Imagine an online store with a category filter.
The user selects:
LaptopsThe application receives that value.
At this point, nothing dangerous has happened. User input is a normal part of almost every interactive website.
Step 2: The Application Creates a Database Query
The application needs to retrieve the appropriate products.
Conceptually, the intended query is:
SELECT * FROM products WHERE category = 'Laptops';
The website then displays the matching results.
This is normal application behaviour.
Step 3: The Application Handles the Input Unsafely
The vulnerability appears if the developer builds the query by directly joining SQL code and user input.
Conceptually:
SQL statement + user-controlled textInstead of:
Fixed SQL statement + separate parameterThis difference is critical.
If the input becomes part of the SQL command itself, specially constructed input may alter the query.
OWASP identifies dynamic queries built using string concatenation and user-supplied input as a typical cause of SQL injection vulnerabilities.
Step 4: The Database Receives the Altered Query
The database does not automatically know which text originally came from:
- the developer,
- the web form,
- the URL,
- or an API request.
It simply receives an SQL statement.
Therefore, if the application has already mixed user-controlled input into the SQL structure, the database may interpret part of that input as SQL rather than ordinary data.
This is the key point:
The attacker is not necessarily attacking the database directly. The vulnerable application creates and submits the unintended database query on the attacker's behalf.
That distinction makes SQL injection much easier to understand.
Normal Query vs SQL Injection
| Normal application behaviour | SQL injection vulnerability |
|---|---|
| User input is treated as data | Input can influence SQL structure |
| Query logic remains fixed | Query logic may change |
| Application controls the query | User input influences the query |
| Only authorised data should be returned | Additional data may become accessible |
| Parameters are separated from SQL code | Input is directly concatenated into SQL |
Therefore, the most effective defence is not simply trying to identify every possible malicious word.
Instead, the application should be designed so that user-controlled values cannot become executable SQL syntax in the first place.
Practical Example 1: Product Search
Consider a shopping website.
A customer chooses:
Category: Laptops
The application's intended operation is simple:
Return products where category = LaptopsHowever, suppose the application builds that database request using unsafe string concatenation.
An attacker may submit specially constructed input designed to change the query conditions.
Consequently, instead of returning only laptops, the database might return records that the application did not intend to expose.
PortSwigger describes this type of SQL injection as retrieving hidden data, where injected conditions alter a query so additional database records become visible.
The important point is not the exact attack syntax.
It is the difference in application logic:
Normal behaviour
Input:
LaptopsPurpose:
Show only products in the Laptop category.Vulnerable behaviour
Input:
Specially crafted database-related inputPossible result:
The application's query condition is altered,
causing additional records to be returned.Therefore, even a simple product filter can become a security problem if it handles database input incorrectly.
Practical Example 2: Login System
Now consider a login page.
The user enters:
Username
PasswordThe application should conceptually ask:
Does this username exist
AND
does the supplied password match?The database query logic must remain fixed.
However, if the username or another value is inserted unsafely into the SQL query, specially constructed input might interfere with those conditions.
Instead of the application checking:
Username matches
AND
Password matchesthe query logic might be changed in an unintended way.
PortSwigger refers to this category as subverting application logic.
Again, the important concept is:
SQL injection can transform user input from “information to check” into “input that changes how the check itself works.”
That is why SQL injection can potentially affect authentication as well as ordinary data retrieval.
Where Can SQL Injection Happen?
SQL injection is often associated with login forms.
However, it can occur anywhere user-controlled information reaches a database query.
Possible locations include:
- search fields,
- login forms,
- product filters,
- URL parameters,
- API requests,
- JSON input,
- XML input,
- customer IDs,
- sorting functions,
- reporting tools,
- administrative interfaces.
Moreover, SQL injection is not limited to SELECT statements.
Depending on the vulnerable application, SQL queries may involve operations such as:
- reading data,
- adding data,
- updating data,
- deleting data,
- sorting results,
- selecting columns or tables.
PortSwigger notes that SQL injection can occur in different parts of queries, including SELECT, UPDATE, INSERT and other query structures.
Therefore:
SQL injection is not simply a login-page vulnerability. It is a database-query construction problem.
Types of SQL Injection
Different SQL injection vulnerabilities behave differently.
However, they all share the same underlying issue: untrusted data is allowed to interfere with SQL query structure.
| Type | How it works | What may reveal the vulnerability |
|---|---|---|
| In-band SQL injection | Results return through the normal application response | Database output |
| Error-based SQL injection | Database errors expose useful information | Error messages |
| Union-based SQL injection | Results from additional database queries may be combined | Unexpected records |
| Blind SQL injection | Database output is not shown directly | Changes in application behaviour |
| Time-based blind SQL injection | Response timing is used to infer conditions | Delayed responses |
| Second-order SQL injection | Input is stored first and later reused unsafely | Vulnerability appears at a later stage |
What Is Blind SQL Injection?
Sometimes the application does not display database results or useful error messages.
Nevertheless, a vulnerability may still exist.
The attacker may instead observe differences such as:
- one page response versus another,
- whether content appears,
- whether an error occurs,
- or how long a response takes.
Therefore, the absence of visible database output does not necessarily mean SQL injection is impossible.
What Is Second-Order SQL Injection?
Second-order SQL injection is particularly important because the dangerous input may not cause a problem immediately.
For example:
Step 1: User submits information.
Step 2: Application safely stores it in the database.
Step 3: Another feature later retrieves that information.
Step 4: The application inserts the stored value into another SQL query unsafely.
At that later stage, the stored information may interfere with the new query.
PortSwigger describes this as second-order or stored SQL injection. Importantly, data that was stored safely should not automatically be considered trustworthy when it is later reused.
This leads to a broader security lesson:
Stored data is not automatically safe data.
What Can SQL Injection Do?
The impact depends on the application, database permissions and the specific vulnerability. Nevertheless, SQL injection may potentially affect confidentiality, integrity and access control.
| Possible impact | Practical meaning |
|---|---|
| Read unauthorized data | Customer, account or business information may be exposed |
| Bypass application logic | Restricted functions may become accessible |
| Modify database records | Information may be changed |
| Delete information | Data integrity or availability may be affected |
| Discover database structure | Table or column information may be exposed |
| Escalate privileges | More powerful database permissions may be reached |
| Broader system impact | Serious configurations may expose additional backend functionality |
MITRE lists consequences including unauthorized data access, modification, authentication bypass and other forms of database compromise.
However, it is important not to assume that every SQL injection vulnerability automatically gives an attacker complete control of a server.
The actual impact depends heavily on database configuration, application privileges and surrounding security controls.
Why Input Validation Alone Is Not Enough
A common idea is:
"Just block SQL words."
For example, a developer might try to reject particular keywords or characters.
However, this should not be the primary defence.
There are several reasons.
First, databases differ in syntax.
Second, encoding and application behaviour can change how input is interpreted.
Third, legitimate user data may contain punctuation or characters that simplistic filters reject.
Moreover, SQL input may arrive from multiple locations, including APIs, JSON bodies or stored database values.
Therefore, trying to maintain a blacklist of every possible dangerous input is fragile.
OWASP strongly discourages relying primarily on escaping all user-supplied input and recommends parameterized queries instead.
The stronger principle is:
Do not try to recognise every possible SQL injection attack. Build database queries so that user input cannot change their structure.
How to Prevent SQL Injection
SQL injection is highly preventable when developers follow secure database-access practices.
The most important defences are:
- parameterized queries,
- prepared statements,
- allow-list validation where necessary,
- least-privilege database access.
1. Use Parameterized Queries and Prepared Statements
This is the most important defence.
With a parameterized query, the SQL structure is defined first.
For example:
SELECT * FROM users
WHERE username = ?Then the application supplies the username separately.
Conceptually:
SQL code:
SELECT * FROM users WHERE username = ?
Parameter:
customerNameBecause the database receives the SQL structure separately from the value, the input is treated as data.
OWASP recommends prepared statements with parameterized queries as its first primary defence against SQL injection.
PortSwigger likewise recommends parameterizing variable data because the query structure has already been defined before the value is supplied.
In simple terms:
Unsafe concept
SQL code + user input = one constructed stringSafer concept
Fixed SQL code
+
separately bound user valueTherefore, the database can distinguish:
code
from
data.
2. Avoid Dynamic SQL String Concatenation
Applications should avoid database code that conceptually looks like:
query = SQL text + userInputEven if the developer believes the input is harmless, future changes may expose it to untrusted data.
Instead, query parameters should be used wherever the database interface supports them.
This reduces the chance that a new feature later introduces SQL injection accidentally.
3. Use Allow-List Validation Where Parameters Cannot Be Used
Not every part of an SQL query can always be represented as a standard parameter.
For example, an application may allow users to choose:
- sort by price,
- sort by name,
- sort by date.
Instead of inserting arbitrary user input directly into the SQL query, the application can map a limited set of accepted choices.
Conceptually:
Allowed values:
price
name
dateAnything else is rejected.
This is called allow-list validation.
OWASP recommends allow-list validation for cases where bind variables cannot be used directly.
4. Apply Least Privilege
Even secure applications should assume that vulnerabilities may occur.
Therefore, the database account used by the web application should only have permissions required for its function.
For example, a product catalogue that only needs to read product records may not need permission to:
- delete entire tables,
- create database users,
- modify administrative settings.
The principle is:
Application compromised
↓
Database account accessed
↓
Permissions remain limited
↓
Potential damage is reduced
Least privilege does not fix SQL injection.
However, it can reduce the blast radius if another defence fails.
SQL Injection Prevention Comparison
| Defence | Recommended? | Why |
|---|---|---|
| Parameterized queries | Yes | Separates SQL code from data |
| Prepared statements | Yes | Keeps query structure fixed |
| Allow-list validation | Yes, where needed | Restricts acceptable dynamic values |
| Least privilege | Yes | Limits potential damage |
| Properly designed stored procedures | Can be | Safe when they avoid unsafe dynamic SQL |
| Manual escaping | Not preferred | Fragile and database-specific |
| Blocking SQL keywords | Not enough | Incomplete as a primary defence |
| Web Application Firewall | Additional layer | Does not repair vulnerable application code |
Importantly, stored procedures are not automatically safe.
Both OWASP and MITRE note that stored procedures can still become vulnerable if they construct unsafe dynamic SQL internally.
Can a Web Application Firewall Stop SQL Injection?
A Web Application Firewall, or WAF, may detect and block some suspicious requests.
Therefore, it can provide an additional security layer.
However:
A WAF does not fix vulnerable application code.
Rules may miss unusual attack patterns, while applications may change over time.
Consequently, the primary defence should remain secure query construction.
A better security model is:
Parameterized queries
+
Input validation
+
Least privilege
+
Testing
+
Additional monitoring/WAF where appropriate
rather than:
Vulnerable code
+
WAF
SQL Injection vs XSS
SQL injection and Cross-Site Scripting (XSS) are both injection-related vulnerabilities, but they affect different parts of an application.
| SQL Injection | Cross-Site Scripting |
|---|---|
| Primarily targets database query handling | Primarily affects browser-side content |
| SQL structure is influenced | Script/content is injected into a page |
| Main target is often backend data | Main target is often another user's browser |
| May expose or modify database records | May affect sessions, page behaviour or displayed content |
| Main defence includes parameterized SQL queries | Main defence includes correct output encoding and safe DOM handling |
Therefore:
SQL injection is mainly a server/database query problem, whereas XSS is mainly a browser/content execution problem.
A dedicated XSS guide can explore that distinction in more detail.
How Developers Can Check for SQL Injection Risk
Before deploying a database-driven application, developers should review how user-controlled information reaches the database.
A practical checklist includes:
- Are database values passed through parameterized queries?
- Are any SQL statements built using string concatenation?
- Can URL parameters reach database queries?
- Can API or JSON values reach SQL statements?
- Are dynamic table or column names restricted to an allow-list?
- Are database accounts limited to necessary permissions?
- Are detailed database errors exposed to users?
- Are stored values treated as untrusted when reused?
- Are automated security tests included in development?
- Is the application regularly reviewed for injection vulnerabilities?
This review should cover more than visible website forms.
APIs and internal application functions can expose the same weakness.
Frequently Asked Questions
1. What is SQL injection in simple terms?
SQL injection is a vulnerability where user-controlled input is allowed to change the SQL query an application sends to its database. Instead of being treated only as data, part of the input may be interpreted as SQL code.
2. How does SQL injection work?
SQL injection usually occurs when an application combines user input directly with an SQL query. If the query is constructed unsafely, specially crafted input may change its intended logic.
3. Is SQL injection still possible today?
Yes. Modern programming frameworks provide safer database interfaces, but SQL injection can still occur when developers build database queries using unsafe dynamic strings or otherwise mix code and data. OWASP continues to include SQL injection under the broader Injection category in its current guidance.
4. Can SQL injection happen without a login form?
Yes. SQL injection can potentially appear in:
- search fields,
- URLs,
- APIs,
- filters,
- JSON input,
- reporting tools,
- administrative features,
- or other database-connected functions.
5. What is blind SQL injection?
Blind SQL injection occurs when the application does not directly return database information, but differences in behaviour or response timing can still reveal information about the query result.
6. What is second-order SQL injection?
Second-order SQL injection occurs when user-controlled data is stored first and later used unsafely inside another SQL query. The vulnerability therefore appears at a later stage rather than when the information is initially submitted.
7. What is the best way to prevent SQL injection?
The primary defence is to use parameterized queries or prepared statements, which keep SQL code separate from user-controlled values. OWASP identifies prepared statements with parameterized queries as its first recommended defence.
8. Does input validation prevent SQL injection?
Input validation is useful as an additional defence. However, it should not replace parameterized queries because validating or filtering every possible malicious SQL input is difficult and error-prone.
9. Are stored procedures safe from SQL injection?
They can be safe when implemented correctly. However, stored procedures that build dynamic SQL using untrusted values can still be vulnerable.
Conclusion
SQL injection occurs when an application fails to maintain a clear boundary between:
SQL instructions
and
user-controlled data.
The typical failure path is:
User input
→ Application
→ Unsafe query construction
→ Database executes altered query
→ Unauthorized behaviour or data exposure
Therefore, the strongest prevention strategy is not trying to identify every possible malicious SQL phrase. Instead, applications should be designed so that user-controlled values cannot alter the SQL query structure.
In practice, that means:
- use parameterized queries,
- avoid string concatenation,
- apply allow-list validation where necessary,
- limit database permissions,
- and test database-connected features regularly.
Ultimately, SQL injection demonstrates a broader cybersecurity principle:
Security depends not only on what data enters a system, but also on how each layer interprets and passes that data to the next one.
When applications clearly separate instructions from user input, one of the most well-known web application vulnerabilities becomes far easier to prevent.
References
- OWASP. SQL Injection Prevention Cheat Sheet. https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html
- OWASP. Query Parameterization Cheat Sheet. https://cheatsheetseries.owasp.org/cheatsheets/Query_Parameterization_Cheat_Sheet.html
- MITRE. CWE-89: Improper Neutralization of Special Elements used in an SQL Command. https://cwe.mitre.org/data/definitions/89.html
- PortSwigger Web Security Academy. SQL Injection. https://portswigger.net/web-security/sql-injection
- PortSwigger. SQL Injection Issue Definition. https://portswigger.net/kb/issues/00100200_sql-injection
- PortSwigger. Second-Order SQL Injection. https://portswigger.net/kb/issues/00100210_sql-injection-second-order
