SQL injection, also popularly known as SQLi, is a vulnerability that allows an attacker to "inject" or input malicious code that eventually gets run by a database. This vulnerability allows the attacker to access data that they shouldn't, to subvert the application's logic, access data from other database tables and in some cases, SQL injections can be used to escalate an exploit to pivot to the underlying backend system.
An application has a basic structure where the users interact with a frontend, that is, the page you see. The frontend then sends data to the backend. This is the part of the application that carries the business logic and runs stuff. Suppose, you visit an online juice store, Everything you see is the frontend, when you add something to cart and proceed to checkout, the backend handles that. In this case the data that might be sent to the backend is the item(s) you chose(name, price, etc) and maybe your user id so that the system knows who bought what. To store and organize information, the application relies on a database. When you want to log in, the application almost always has to interact with the database.

In SQL injection attacks, the attacker inputs a piece of malicious code that get trusted and run in the database. Suppose you want to login, and you input yourUsername as the username and yourPassword as the password, the backend prepares a query that may look like this:
SELECT * FROM users WHERE username = 'yourUsername' and password = 'yourPassword';
An attacker may input administrator'-- in the username box and an empty password. This results into this query:
SELECT * FROM users WHERE username = 'administrator'--' and password = '';
In this example, anything past the -- is treated as a comment, therefore, the attacker might log in as an administrator, subverting application logic.
Most SQL injection vulnerabilities occur within the WHERE clause of a SELECT query. Although, SQL injection vulnerabilities can occur at any location within the query. Some other common locations where SQL injection arises are:
- In
UPDATEstatements, within the updated values or theWHEREclause. - In
INSERTstatements, within the inserted values. - In
SELECTstatements, within the table or column name. - In
SELECTstatements, within theORDER BYclause.
How to find SQLi vulnerabilities
By now you've noticed that this vulnerability depends on some working knowledge of databases. An attacker will input some code that either triggers a response from the database or an error. To find SQLi vulnerabilities:
- You can pass a
'into the input and watch for database errors - You can pass boolean conditions such as
OR 1=1andOR 1=2and watch the application's responses - You can trigger a time delay payload and watch for any time differences in responses
In some cases, you may not get direct responses, these are called blind sql injection attacks.
Examples and illustrations are covered in future articles
How to prevent SQLi vulnerabilities
Use parameterized queries / prepared statements so that user input is never treated as SQL code. For example (PHP + PDO):
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ? AND active = 1');
$stmt->execute([$email]);Validate and whitelist inputs on the server (check type, length, format, and allowed values). For example (Node.js):
// allowlist for sort column
const allowed = ['name','created_at'];
if (!allowed.includes(sort)) throw Error('invalid sort');Use an ORM or query builder instead of hand-rolled SQL so parameters are handled safely. For Example (Python + SQLAlchemy):
user = session.query(User).filter(User.email == email).first()Never concatenate untrusted values into SQL; if you must insert identifiers (table/column), validate against an allowlist and escape only known-safe values. For example (Go):
cols := map[string]bool{"name":true,"email":true}
if !cols[col] { return errors.New("invalid column") }
query := fmt.Sprintf("SELECT %s FROM users WHERE id = $1", col) // safe because col was validatedApply least-privilege to DB accounts. Use separate users for readonly vs write actions and never run the app as a DB admin. Only give required access.
Use server-side escaping only for non-SQL contexts (e.g. HTML) and rely on parameterization for SQL.
Finally, it is important to maintain security hygiene through pentests and vulnerability assessments