SQL Injection: The Complete Practical Guide
SQL Injection in Unexpected Contexts
SQLi beyond the WHERE clause: ORDER BY and identifiers that cannot be parameterized, LIMIT/OFFSET, HTTP headers, JSON bodies, and ORM raw escapes, step by step.
Published
Most tutorials show injection in a WHERE clause, so that is where people look. Real applications put user input into plenty of other parts of a query, and several of them cannot be fixed with a bound parameter at all. These contexts are where injection survives after the easy spots are patched.
Injecting in ORDER BY
You cannot bind an identifier, so a sortable column is frequently concatenated straight in:
?sort=name -> ORDER BY name
?sort=name;... -> the value lands in the ORDER BYThere is no string to close here, so quote-based payloads do not apply. Confirm and exploit with a conditional expression instead:
?sort=(CASE WHEN (1=1) THEN name ELSE email END) (changes the ordering if true)
?sort=(SELECT CASE WHEN (condition) THEN 1 ELSE 1/0 END) (errors or delays on true)You can also probe by column index: ?sort=1 versus ?sort=2 reorders results if the value is used positionally.
LIMIT and OFFSET
Pagination parameters often reach LIMIT n OFFSET m unparameterized. Depending on the DBMS you can append a subquery or, on MySQL, a PROCEDURE ANALYSE-style trick, and time-based conditions work well here because the clause accepts expressions.
Column and table identifiers
Anywhere the app lets you choose a field to display, filter, or group by, the identifier may be concatenated. These must be fixed with an allow-list, never a quote escape, which is exactly why they stay vulnerable.
HTTP headers logged to the database
Applications log request metadata, and that insert is often built by concatenation:
User-Agent: ' OR (SELECT ... )-- -
X-Forwarded-For: ', (SELECT ...))-- -If a User-Agent, X-Forwarded-For, Referer, or cookie is written to an analytics or audit table, the header is your injection point. This frequently becomes second-order injection when an admin later views the logs.
JSON and nested parameters
Modern APIs take JSON. Values deep inside the body still reach queries, so inject into nested fields, array elements, and keys, not just top-level params:
{ "filter": { "status": "active' OR 1=1-- -" } }ORM raw escapes
ORMs are safe until someone reaches for the raw hatch: raw(), whereRaw(), extra(), string interpolation inside a query builder, or a hand-built fragment for something the ORM cannot express. Those fragments concatenate input like any other, so audit every raw call.
Hunt the non-obvious inputs on a free live target, then read WAF and filter evasion for when a filter stands in the way.