SQL Injection (ORDER BY)

The sneaky vulnerability that bypasses prepared statements.

The idea

We all know that Prepared Statements (Parameterization) stop SQL injection in `WHERE` clauses (e.g. `WHERE username = ?`). However, you cannot parameterize table names, column names, or the ORDER BY direction (ASC/DESC) in most SQL dialects. If you allow users to sort a data table by passing a column name in the URL (`?sort=price`), and you concatenate that directly into the `ORDER BY` clause, you are vulnerable to SQL Injection, even if you use an ORM.

Step 1: User clicks "Sort by Price". The URL is ?sort=price

How it works (Strict Whitelisting)

Because `ORDER BY` cannot be parameterized, the only defense is to strictly whitelist the allowed column names in your application code before injecting them into the query.

# VULNERABLE: Direct concatenation of column name
sort_col = request.args.get('sort') # E.g., 'price'
# DANGER: Attackers can inject '?sort=(CASE WHEN ...)'
query = f"SELECT * FROM products ORDER BY {sort_col}"

# SECURE: Strict Whitelisting
sort_col = request.args.get('sort')
ALLOWED_COLUMNS = ['price', 'name', 'date_added']

if sort_col not in ALLOWED_COLUMNS:
    sort_col = 'date_added' # Safe fallback

query = f"SELECT * FROM products ORDER BY {sort_col}"

Watch out for

Worked example

A data-table in an admin panel shows a list of users. Clicking a column header changes the URL to `/users?sort=email`. An attacker changes the URL to `/users?sort=extractvalue(1,concat(0x7e,(SELECT version())))`. Because the backend concatenates this into the `ORDER BY` clause, MySQL attempts to extract XML using the database version number. It crashes and returns an error: `XPATH syntax error: '~8.0.21'`. The attacker has successfully extracted the database version directly into the error log.

Check yourself

Why can't you just use a Prepared Statement (e.g. `ORDER BY ?`) to fix this vulnerability?

Incorrect. It's a limitation of the SQL protocol itself, not just ORMs.
Correct! The database engine compiles the query structure first. It can't compile a query if it doesn't know which column it's supposed to sort by.