Safeguard
Developer Tools•

Can you parameterize ORDER BY and table names in SQL?

Placeholders only bind values, not identifiers or sort direction. Use a code side allowlist or a typed switch to keep dynamic ORDER BY safe from injection.

Safeguard Security Team
3 min read

No. Bind variables carry values, not identifiers, so you cannot parameterize a table name, a column name or a sort direction. For those, map user input to a fixed list in your own code and reject anything else. The user never supplies SQL text, only a choice from your list.

Why placeholders do not work here

A prepared statement fixes the structure of the query before any data arrives. Column and table names are part of that structure. The database has to know them to plan the query, so a placeholder in that position is not allowed.

That leaves developers with a tempting shortcut: concatenate the user's sort field into the string. This is where many SQL injection bugs live in code that otherwise uses parameters properly.

What OWASP recommends

The SQL injection cheat sheet gives three rules for these cases.

  1. Prefer values from code. Table and column names ideally should not come from user input at all. The cheat sheet calls user driven table names "a symptom of poor design" and suggests a rewrite where possible.
  2. Map choices with an allowlist. If user input must select a name, match each accepted value to a known name in a switch statement, and reject everything else.
  3. Convert direction to a typed value. For sort order, turn the input into a boolean and use it to choose the fixed keyword ASC or DESC. Input converted to a number, date, boolean or enum before it is concatenated is considered safe to append.

A safe pattern

SORTABLE = {"name": "customer_name", "created": "created_at"}

def build_order(field, descending):
    column = SORTABLE.get(field)
    if column is None:
        raise ValueError("unsupported sort field")
    direction = "DESC" if descending is True else "ASC"
    return " ORDER BY " + column + " " + direction

The user's string is only a dictionary key. The text that reaches the SQL comes from your constants.

Common mistakes

  • Blocklisting quotes or semicolons. OWASP's validation guidance says not to try to recognize every malicious string, and escaping is labelled strongly discouraged.
  • Trusting the framework by default. Many query builders accept raw fragments for ordering. Check that the fragment comes from your allowlist.
  • Validating the format only. A value that looks like a valid column name might still reference a column the user should not sort by, such as a hidden or sensitive field.

Pair it with least privilege

Even with the allowlist, run the application with a database account that has only the rights it needs. OWASP advises separate accounts per application, no admin rights, and views that expose only the necessary columns.

Test it

  1. Send an unknown sort field and confirm a clean rejection.
  2. Send a field name with punctuation and confirm the same.
  3. Send an unexpected direction value and confirm it falls back to a default or fails.
  4. Review logs for queries built from non allowlisted text.

Quick check

Can I just escape the column name?

OWASP states it cannot guarantee escaping prevents all injection in all situations. An allowlist is the safer route.

What about a dynamic IN list?

The cheat sheet does not cover it. A common approach is one placeholder per value, but check it against your database driver's documentation.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.