Skip to content

Taxonomy

Unvalidated input reaching a sink

Caller-controlled data arrives somewhere that interprets it.

What it looks like

  • A path, query fragment, template or command assembled from an argument.
  • A validation step moved, weakened, or applied to the wrong variable.
  • A value checked in one branch and used in another.

Why it survives review

The well-behaved input a reviewer imagines produces exactly the right result, and the call site reads as ordinary string handling. Whether it is safe depends entirely on what the sink does with it, and the sink is usually in another file.

How to see it

  1. Trace backwards from anything that interprets a string — a query, a path, a redirect, a template — to where the value came from.
  2. Check the validation applies to the value that actually reaches the sink, not to a copy made before it was transformed.
  3. Allow-lists survive review better than deny-lists because they are correct; a deny-list is a list of the attacks somebody thought of.

A minimal pair

Correct

const safe = ALLOWED.has(column) ? column : 'id';
return `ORDER BY ${safe}`;

Defective

return `ORDER BY ${column}`;

A column name of id; DROP TABLE users -- is now part of the query.

Practise it

2 diffs in the corpus carry this class. They are not listed, because knowing which diff contains what would make finding it a comprehension question about this page.

Go to the exercises