If your application uses Structured Query Language (SQL) for a relational database and takes any user‑input (directly or indirectly), unsanitized input can be used by an attacker to inject a compromised instruction to your database. This can lead to data theft, data corruption, privilege escalation, or even remote code execution in some cases. These flaws compromise system integrity for your applications. This type of vulnerability is well known but still too often left open to compromise. To prevent SQL injection, treat user input as tainted, not as safe variables to include in your queries. Parameterized queries, object-relational mapping (ORM) libraries and other safe query‑building methods are plentiful. In this article, we’ll explain what SQL injection is and why it still matters. Next, we’ll look at common ways it’s exploited and show code examples to help you identify it in your own code. Finally, we’ll offer recommendations and mitigation strategies you can apply immediately.Documentation Index
Fetch the complete documentation index at: https://docs.semgrep.dev/llms.txt
Use this file to discover all available pages before exploring further.
What is SQL Injection (SQLi)
SQL is used to query relational databases. When building SQL queries, often developers include parts of queries that come from user input. If the input is not safely handled, an attacker can “inject” SQL fragments that alter the structure of the query. Instead of just passing as data, the user input influences the logic (ie. conditions, clauses, or even entirely new statements). There are many reasons this vulnerability still happens.- many frameworks or libraries allow (or even require) some dynamic SQL assembly
- concatenating strings or using template interpolation is convenient
- when optimizing long query performance, safeguards from ORM or other abstractions may be short-circuited
Common SQL Injection Attacks
Let’s walk through some examples for what SQL injection looks like in real-world code. A typical SQLi vulnerability starts when user input is embedded directly into a SQL query string. Consider this Python example:' OR 'a'='a as your query becomes:
Classic Injection via string concatenation
The above example used string interpolation but the same can occur when concatenating strings. Suppose you build a query like this:userInput the attacker can inject their command into the query behavior such as returning the full table results ' OR '1'='1 or executing arbitrary database operations with ; DROP table users; --.
Blind SQL Injection
The previous examples still require knowledge of how the database tables are structured and which database is being used. The attacker might be able to infer details by using boolean conditions, timing (delays), or injecting error codes. A successful or failure in a query can leak information. For example:Second‑order SQL Injection
Another indirect attack vector may be when data is fetched from the database itself and used in a query. If an attacker can enter data into the database, they can insert the malicious string that the source code treats as a trusted source because the data came from inside the database. Suppose user input is sanitized superficially, stored, but later passed through un-sanitized dynamic SQL. An attack happens when that second usage of the payload occurs.Detecting SQL Injection Vulnerabilities in Your Code
Some general guidance on where to focus triage for SQLi:- Places in code where user input (from query params, body, cookies, headers, files, etc.) enters and is used in raw SQL functions, dynamic query builders, or template literals.
- Usage of dangerous “raw query” / “query string” APIs. In many frameworks or ORMs there are methods like query(…), execute(…), or string interpolation.
- Absence of parameter binding, named parameters, or prepared statements.
Example Semgrep Rule: express-sequelize-injection
Consider this JavaScript / TypeScript / Express + Sequelize code:Recommendations and Mitigations
Here are some robust and concrete tips for writing secure database queries.Always use parameterized queries
This is the most reliable way to prevent SQLi. Instead of building the SQL string manually, placeholders are used and the values are passed separately. This separates code from data and let’s the library properly check for and escape any malicious strings. This is a Python example that lets theexecute function santize the query string that was passed with an http request:
%s, ?, :name, etc.) but the concept remains the same.