$ x0hashbrown 
notes & writeups on offensive security, CTFs and breaking things safely

SQL injection, from first principles

web2026-09-01

SQL injection has been on the OWASP Top 10 for two decades, and it keeps showing up for one simple reason: it happens whenever untrusted input gets concatenated into a query instead of being kept separate from it. The payload trivia is downstream of that one idea.

The core problem

A query built like this treats user input as part of the program rather than as data:

query = "SELECT * FROM users WHERE username = '" + input + "'"

If input can contain a quote character, it can close the string literal early and inject its own SQL. Everything else โ€” UNION-based extraction, boolean/time-based blind techniques, second-order injection โ€” is just different ways of exploiting that same trust boundary failure.

Why it's still common

  • ORMs make it easy to fall back to raw string queries "just this once".
  • Legacy code paths that predate an org's secure coding standards.
  • Search/filter/sort parameters that feel like "just a string", not user-controlled SQL.

The fix, in order of preference

  1. Parameterized queries / prepared statements โ€” the interpreter keeps code and data separate; this closes the class of bug entirely.
  2. ORM query builders used as intended, without dropping to raw SQL string interpolation.
  3. Strict allow-listing for the rare cases where identifiers (table/column names) must be dynamic, since those can't be parameterized.
  4. Least-privilege DB accounts and input validation as defense in depth โ€” not a substitute for the above.
Test only systems you own or are explicitly authorized to test โ€” e.g. your own lab, or a program with written scope.
← back to posts