SQL injection prevention in Node.js — parametrize everything
SQL injection is a solved problem — and AI coding assistants keep re-introducing it. Here are the exact patterns to watch for in Prisma, Supabase, Drizzle, and raw pg.
Every ORM supports parameterized queries. AI-generated code sometimes reaches for raw SQL anyway — to ship faster, to match a copy-pasted example. This guide covers the exact patterns that slip through code review.
What it is
SQL injection happens when user input is interpolated into a SQL string. The fix is parameter binding, where the database receives SQL and values as separate inputs and never compiles user input as SQL.
Vulnerable example
// Vulnerable in every ORM:
// 1. Raw pg
const result = await pool.query(`SELECT * FROM users WHERE email = '${email}'`);
// 2. Prisma raw query
const users = await prisma.$queryRawUnsafe(`SELECT * FROM users WHERE email = '${email}'`);
// 3. Drizzle sql template with interpolation
const users = await db.execute(sql`${sql.raw(`SELECT * FROM users WHERE email = '${email}'`)}`);Fixed example
// Fixed: parameter binding
// 1. Raw pg
const result = await pool.query("SELECT * FROM users WHERE email = $1", [email]);
// 2. Prisma typed
const users = await prisma.user.findMany({ where: { email } });
// 3. Prisma raw with bindings
const users = await prisma.$queryRaw`SELECT * FROM users WHERE email = ${email}`;
// 4. Drizzle typed
const users = await db.select().from(usersTable).where(eq(usersTable.email, email));How Securie catches it
Securie's taint analyzer traces every user input into every SQL sink across the most common Node ORMs, flagging any string interpolation that reaches SQL.
Checklist
- Zero string concatenation in SQL
- Raw query APIs (`$queryRawUnsafe`, `pool.query` with template strings) are grep'd for and each use is reviewed
- LIKE clauses use parameterized %s with explicit escape
- Dynamic identifiers (table/column names from user input) are whitelisted, not concatenated
- Database users have read-only where possible; prod DB cannot DROP
FAQ
What about NoSQL injection?
Same principle. MongoDB drivers bind parameters correctly; `$where` with interpolation is the equivalent anti-pattern. Securie covers MongoDB too.