#0304
An orders API lets clients choose how results are sorted by passing a column name as a query parameter. The handler inserts this column name directly into an ORDER BY clause.
Unlike WHERE clause injection, column names cannot be parameterized in most databases — so the fix is an allowlist, not a placeholder.
Without a check, an attacker can inject arbitrary SQL after the column name: created_at; DROP TABLE orders;-- or use a subquery to exfiltrate data.
Column injection is a lesser-known but equally dangerous SQL injection variant. Because developers know they can't parameterize column names, they often skip validation entirely — giving attackers direct control over query structure.
buildSortedQuery to validate column against an allowlist of ["created_at", "total", "status"].'Invalid sort column' if the column is not in the allowlist.{ sql: "SELECT * FROM orders ORDER BY " + column, params: [] } for valid columns.buildSortedQuery('created_at; DROP TABLE orders;--')// → throws Error('Invalid sort column')
buildSortedQuery('total')// → { sql: 'SELECT * FROM orders ORDER BY total', params: [] }
'Invalid sort column' for disallowed column names.created_at, total, status.