Skip to content

feat(rules): avoid SQL injection false positives on parameterized tagged template literals #78

Description

@jeremyjs

Problem

The A03-SQL-INJECTION native rule fires on parameterized query libraries that use tagged template literals, producing a large volume of false positives.

Reproduction

Using @neondatabase/serverless (the standard Neon Postgres driver):

import { neon } from "@neondatabase/serverless";
const sql = neon(process.env.DATABASE_URL!);

// This line is flagged as "SQL Injection" — but it is SAFE
const rows = await sql`SELECT * FROM users WHERE id = ${userId}`;

The ${userId} interpolation is handled by the sql tag function, which converts it to a parameterized query ($1) and passes the value separately to Postgres. The user input is never concatenated into the SQL string.

OWASP.WTF currently flags this because the rule matches:

  1. A SQL keyword (SELECT)
  2. A template literal with ${...} interpolation

Impact

In our production monorepo (~80 packages, 200k LOC), this pattern produces 28 critical "SQL Injection" findings, all of which are false positives. This drowns out the 2-3 real issues we actually want to catch.

Proposed Solutions

Option A: Detect known-safe tag functions (recommended)

Maintain a list of known-safe tagged-template query builders:

  • sql\...`(from@neondatabase/serverless`)
  • db\...`(fromdrizzle-orm, kysely`, other ORMs)
  • query\...`` (generic convention)

When the line matches a SQL keyword + template literal, check if the preceding token on the same line (or within 2-3 lines above) is a tagged template invocation with a known-safe tag. Skip the finding if so.

Option B: Check for explicit concatenation only

Only flag SQL injection when there's actual string concatenation (+ operator, .concat(), or template literals used as function arguments to raw SQL methods). Skip tagged template literals entirely, since most modern JS SQL libraries use them safely.

Option C: Configurable allowlist

Add a config option for consumers to register safe tag names:

// ~/.owasp-wtf/config.json
{
  "rules": {
    "A03-SQL-INJECTION": {
      "safeTemplateTags": ["sql", "db", "query"]
    }
  }
}

Preference

Option A gives the best out-of-box experience for the most common libraries. Option C is a good fallback for less-common libraries.


Reported from Dial-WTF/x402-dial production rollout — PR #120

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions