# SAFE — parameterizedcursor.execute("SELECT * FROM users WHERE email = %s", (email,))
Raw SQL with tagged templates
// SAFE — sql tagged template (e.g., postgres.js)const users = await sql`SELECT * FROM users WHERE email = ${email}`;
ORM Safety
ORMs like Prisma, Drizzle, and SQLAlchemy parameterize queries automatically:
// Prisma — safe by defaultconst user = await prisma.user.findUnique({ where: { email } });// Drizzle — safe by defaultconst user = await db.select().from(users).where(eq(users.email, email));
Danger zone: Raw query methods bypass safety:
// VULNERABLE — raw query with string interpolationawait prisma.$queryRawUnsafe(`SELECT * FROM users WHERE email = '${email}'`);// SAFE — raw query with parametersawait prisma.$queryRaw`SELECT * FROM users WHERE email = ${email}`;
Dynamic Queries
When building queries with variable columns or table names:
// VULNERABLE — dynamic column nameconst query = `SELECT * FROM users ORDER BY ${sortColumn}`;// SAFE — allowlist approachconst ALLOWED_COLUMNS = ["name", "email", "created_at"];if (!ALLOWED_COLUMNS.includes(sortColumn)) { throw new Error("Invalid sort column");}const query = `SELECT * FROM users ORDER BY ${sortColumn}`;