#0303
An order management API lets users filter their orders by status. The handler accepts a userId and a status string and builds a SQL query by concatenating both values inline.
An attacker can inject into either parameter: a crafted status of shipped' OR '1'='1 bypasses the user_id filter and returns all users' orders; a malicious userId can delete the entire table.
Using two unparameterized columns doubles the attack surface compared to a single-parameter injection.
Multi-column injections are more dangerous than single-column ones because they offer more injection points. A compromised status filter can silently expose every order in the system.
buildOrderFilter so both userId and status are passed as parameters.{ sql: "SELECT * FROM orders WHERE user_id=$1 AND status=$2", params: [userId, status] }.buildOrderFilter('123', "shipped' OR '1'='1")// FIX → { sql: '...WHERE user_id=$1 AND status=$2', params: ['123', "shipped' OR '1'='1"] }
buildOrderFilter('u42', 'shipped')// → { sql: '...WHERE user_id=$1 AND status=$2', params: ['u42', 'shipped'] }
sql must use $1 and $2 placeholders.params array must be [userId, status] in that order.