SQL injection (SQLi) is a code injection attack where an attacker inserts malicious SQL statements into input fields that are passed to a database query. If the application concatenates user input directly into SQL queries without sanitization, the attacker can read, modify, or delete database contents, bypass authentication, or execute system commands.
Also see: How to Prevent SQL Injection Attacks, SQL Injection Testing Checklist, OWASP Top 10 Explained 2026, and API Security Best Practices.
SQL injection is classified as A03:2021 — Injection in the OWASP Top 10 and has been one of the most critical web vulnerabilities for over two decades. Despite being well-understood, it remains prevalent because developers continue to build queries with string concatenation.
How SQL Injection Works
Consider a login form that checks credentials against a database:
# Vulnerable code (PHP):
$query = "SELECT * FROM users WHERE username = '$username' AND password = '$password'";
# Normal login: username=john, password=secret123
# Query: SELECT * FROM users WHERE username = 'john' AND password = 'secret123'
# Result: Returns john's record if credentials match ✅
# SQL injection: username=' OR '1'='1' --, password=anything
# Query: SELECT * FROM users WHERE username = '' OR '1'='1' --' AND password = 'anything'
# Result: OR '1'='1' is always true, -- comments out the rest
# The query returns ALL users — authentication bypassed ❌
The attacker's input changes the structure of the SQL query. The database cannot distinguish between the developer's intended SQL and the attacker's injected code.
Types of SQL Injection
1. In-Band SQLi (Classic)
The attacker receives results directly in the application's response. This includes UNION-based attacks that combine data from multiple tables and error-based attacks that extract data from database error messages.
2. Blind SQLi
The application doesn't show query results, but the attacker infers data from the application's behavior:
- Boolean-based: Different responses for true/false conditions
- Time-based: Using
SLEEP()to detect true/false based on response time
3. Out-of-Band SQLi
Data is exfiltrated through a different channel — DNS lookups or HTTP requests to an attacker-controlled server. Used when in-band and blind techniques aren't feasible.
Real-World Impact
- Data theft: Usernames, passwords, credit card numbers, personal records
- Authentication bypass: Log in as any user, including administrators
- Data manipulation: Modify prices, transfer funds, change permissions
- Data destruction:
DROP TABLEdeletes entire tables - Server compromise: Some databases allow OS command execution
Notable SQL injection breaches include the 2017 Equifax breach (147 million records), the 2015 TalkTalk breach (157,000 records, £400,000 fine), and the 2011 Sony PlayStation Network breach (77 million accounts).
How to Prevent SQL Injection
- Parameterized queries (prepared statements): The #1 defense — separates SQL code from data
- ORM usage: Django ORM, Eloquent, Sequelize auto-parameterize queries
- Input validation: Whitelist expected characters and types
- Least privilege: Database user should only have necessary permissions
- WAF: Web Application Firewall as an additional layer
# SECURE — Parameterized query (PHP PDO)
$stmt = $pdo->prepare('SELECT * FROM users WHERE username = ? AND password = ?');
$stmt->execute([$username, $password]);
# SECURE — Parameterized query (Node.js)
const [rows] = await db.execute('SELECT * FROM users WHERE username = ? AND password = ?', [username, password]);
# SECURE — ORM (Django)
user = User.objects.filter(username=username, password=password).first()
For detailed prevention techniques with code examples in PHP, Node.js, Python, Java, and .NET, see our complete SQL injection prevention guide.
Second-order SQL injection
Second-order SQL injection (also called stored SQL injection) is a more sophisticated variant that bypasses first-pass sanitization. The attacker stores a malicious payload in the database through a safe-looking input, which is then used unsafely in a subsequent query.
# Step 1: Attacker registers with this username (appears safe, stored correctly):
username: admin'--
# Step 2: Application later uses the stored username in another query:
# (Assumes data from the database is safe)
$query = "UPDATE users SET email='$email' WHERE username='" . $storedUsername . "'";
# Result: UPDATE users SET email='...' WHERE username='admin'--'
# The -- comments out the rest. The admin user's email is now modified.
# This is second-order injection: the payload survived storage but fires later.
Prevention: data from the database is not automatically safe. Always use parameterized queries even when the values originally came from your own database.
SQL injection beyond SELECT: the full attack surface
Most developers think of SQL injection as a data-reading attack. In reality, the full attack surface extends to every SQL operation the database supports.
- Authentication bypass:
' OR '1'='1' --in login forms bypasses password checking. This works because the query returns a valid user row without needing a correct password. - Data exfiltration via UNION:
UNION SELECT username, password, NULL FROM admin_usersextracts data from tables the application never intended to expose. - File system access: MySQL
LOAD_FILE()can read server files;INTO OUTFILEcan write files. On misconfigured MySQL servers, this can lead to web shell deployment. - OS command execution: Microsoft SQL Server's
xp_cmdshellexecutes OS commands. If an attacker can enable it via SQLi (EXEC sp_configure 'xp_cmdshell',1), full server compromise is possible. - Time-based data extraction: Even when no data is returned,
IF(1=1, SLEEP(5), 0)reveals database structure through response timing — character by character.
Parameterized queries: the correct implementation by language
# PHP (PDO) — correct parameterization
$stmt = $pdo->prepare('SELECT id FROM users WHERE email = :email AND status = :status');
$stmt->execute([':email' => $email, ':status' => 'active']);
# Python (psycopg2) — correct
cursor.execute('SELECT id FROM users WHERE email = %s', (email,))
# Java (PreparedStatement) — correct
PreparedStatement stmt = conn.prepareStatement("SELECT id FROM users WHERE email = ?");
stmt.setString(1, email);
# Go (database/sql) — correct
row := db.QueryRow("SELECT id FROM users WHERE email = $1", email)
# WRONG in all languages: string concatenation
# "SELECT id FROM users WHERE email = '" + email + "'" <-- NEVER do this
Database least-privilege configuration
Even with parameterized queries, defense-in-depth requires that the database user your application connects with has the minimum permissions necessary. If a SQLi vulnerability is exploited, a least-privilege database account limits the damage significantly.
- Grant only required operations: A web application reading and writing user data needs only
SELECT, INSERT, UPDATE, DELETEon the specific tables it uses. Never connect with a database root account. - Separate read/write accounts: Read-only sections of the application (display pages, reports) should use a read-only database account. An SQLi in a read-only endpoint cannot modify or delete data.
- Disable dangerous functions: Disable
LOAD DATA INFILE,INTO OUTFILE(MySQL), andxp_cmdshell(MSSQL) for all application database users. - Restrict network access: The database should only accept connections from the application server IP, not from the public internet. Combined with port restriction (database port blocked externally), this eliminates direct remote database attacks.
Scan Your Website for Vulnerabilities
Free security scan — checks for injection risks, exposed files, misconfigurations, and 40+ issues.
Scan Your Site NowFAQ
What is SQL injection in simple terms?
SQL injection is a hacking technique where an attacker inserts malicious database commands into a website's input fields. If the website doesn't properly validate input, the commands execute on the database, potentially exposing all stored data.
Is SQL injection still common in 2026?
Yes. It's ranked A03:2021 in the OWASP Top 10. It still occurs in legacy applications and websites that use string concatenation for database queries.
What damage can SQL injection cause?
Attackers can read the entire database, bypass authentication, modify or delete data, and in some cases gain full server control.