What Is SQL Injection and How Do I Prevent It?
Key takeaways
- SQL injection is possible wherever a value is concatenated into a query string, so a rule that bans one dangerous keyword does not remove the class of bug.
- Parameterised queries or prepared statements pass the input as data, which is the control that actually closes the hole, and most ORMs do this by default when you use their query builder.
- Stored procedures help because the query structure is fixed in the database, and they make it easier to grant the application account rights on the procedure rather than on the tables.
- Least privilege on the database account limits the damage of any injection, so a read-only reporting account and a separate account for migrations are worth the small effort.
- Second-order injection matters too, where a value is stored safely and later concatenated into another query, so stored data must be treated as untrusted when it is read back.
As of 24 October 2026: the service descriptions, prices and turnaround figures on this page are current.
How does a SQL injection attack actually work?
The attack works because the application builds a query by gluing strings together. A login form that concatenates a username into a query lets the input decide the structure of the statement. A crafted username with a comment marker can truncate the rest of the query and return a row regardless of the password, which is why so many login bypasses look impossible and are not. Other shapes target a union of another table to read data, a stacked statement to modify data, or a boolean test to extract the database one character at a time. A blind injection, where the page shows no data, still leaks the whole database by observing the true or false result.
What is the right way to write safe queries?
Pass values as parameters, always, and let the driver or the query builder handle the escaping. In Python, use a placeholder and a parameter tuple rather than f-strings. In Java, use PreparedStatement with setString and setInt. In PHP, use PDO with bound parameters. In Node, use the driver's parameter syntax. Where you need dynamic query structure, build the query from a fixed set of allow-listed fragments, such as choosing the sort column from a list rather than taking the field name from the request. Use stored procedures for multi-step transactions, and give the application the right to execute the procedure rather than the right to modify the table.
How do I prevent SQL injection beyond the query itself?
Four layers around the fix. Least privilege: the application's database account should not own the tables, should not be able to drop them, and should be separate from the account you use for schema changes. Input validation at the edge: reject values that are not of the expected type and shape. Logging and monitoring: log the SQL that failed, the parameter values and the source, and alert on repeated syntax errors. And a web application firewall as a filter, not a fix. In an Indian context, an injection that reads the customer table is a personal data breach, and the DPDP Act notification duty and the CERT-In reporting clock start at detection.
| Control | Replaces | What it stops |
|---|---|---|
| Parameterised query or prepared statement | String concatenation of values | The injection itself |
| Stored procedure for multi-step logic | Multi-statement strings built in code | Stacked statements and structure changes |
| Allow-list for dynamic fragments | Order-by or column name from the request | Injection through a field name |
| Input validation at the edge | Trusting the request shape | Obviously malformed payloads |
| Least-privilege database account | One powerful application user | Table drops, writes and schema changes |
| Separate account for migrations | Sharing one credential | App compromise reaching the schema |
| Query and error logging | Silent failure | Undetected exploitation attempts |
What are the frequently asked questions?
Get a straight answer on this
Send us the endpoint or query you are unsure about and we will return a fixed-price injection testing plan for your application.
Send us the details See pricing