Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 180 additions & 0 deletions javascript/drizzle-orm/security/audit/ban-drizzle-sql-raw.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
/**
* CommonJS import
*/

const { sql } = require("drizzle-orm");
async function rawGetUser(id) {
// ruleid: ban-drizzle-sql-raw
return sql.raw(`select * from users where id = ${id}`);
}

async function sqlEscapedGetUser(id) {
// ok: ban-drizzle-sql-raw
return sql.execute(sql`select * from users where id = ${id}`);
}


async function rawGetUserInTemplateLiteralsVariable(id) {
// ruleid: ban-drizzle-sql-raw
const query = `select * from users where id = ${id}`;
return sql.raw(query);
}

async function rawGetUserWithPlusOperator(id) {
// ruleid: ban-drizzle-sql-raw
const query = "select * from users where id = " + id;
return sql.raw(query);
}

async function rawGetUserWithPlusOperatorVariable(id) {
// ruleid: ban-drizzle-sql-raw
return sql.raw("select * from users where id = " + id);
}

async function rawGetUserWithoutInjection() {
// ok: ban-drizzle-sql-raw
return sql.raw("select * from users where id = 1");
}

/**
* ESM import
*/

import { sql } from "drizzle-orm";
async function rawGetUser(id) {
// ruleid: ban-drizzle-sql-raw
return sql.raw(`select * from users where id = ${id}`);
}

async function sqlEscapedGetUser(id) {
// ok: ban-drizzle-sql-raw
return sql.execute(sql`select * from users where id = ${id}`);
}

async function rawGetUserInTemplateLiteralsVariable(id) {
// ruleid: ban-drizzle-sql-raw
const query = `select * from users where id = ${id}`;
return sql.raw(query);
}

async function rawGetUserWithPlusOperator(id) {
// ruleid: ban-drizzle-sql-raw
const query = "select * from users where id = " + id;
return sql.raw(query);
}

async function rawGetUserWithPlusOperatorVariable(id) {
// ruleid: ban-drizzle-sql-raw
return sql.raw("select * from users where id = " + id);
}

async function rawGetUserWithoutInjection() {
// ok: ban-drizzle-sql-raw
return sql.raw("select * from users where id = 1");
}

/**
* CommonJS import sql as SQL
*/

const { sql: SQL } = require("drizzle-orm");

async function rawGetUser(id) {
// ruleid: ban-drizzle-sql-raw
return SQL.raw(`select * from users where id = ${id}`);
}

async function sqlEscapedGetUser(id) {
// ok: ban-drizzle-sql-raw
return SQL.execute(sql`select * from users where id = ${id}`);
}

/**
* ESM import sql as SQL
*/

import { sql as SQL } from "drizzle-orm";
async function rawGetUser(id) {
// ruleid: ban-drizzle-sql-raw
return SQL.raw(`select * from users where id = ${id}`);
}

async function sqlEscapedGetUser(id) {
// ok: ban-drizzle-sql-raw
return SQL.execute(sql`select * from users where id = ${id}`);
}

async function rawGetUserInTemplateLiteralsVariable(id) {
// ruleid: ban-drizzle-sql-raw
const query = `select * from users where id = ${id}`;
return SQL.raw(query);
}

async function rawGetUserWithPlusOperator(id) {
// ruleid: ban-drizzle-sql-raw
const query = "select * from users where id = " + id;
return SQL.raw(query);
}

async function rawGetUserWithPlusOperatorVariable(id) {
// ruleid: ban-drizzle-sql-raw
return SQL.raw("select * from users where id = " + id);
}

async function rawGetUserWithoutInjection() {
// ok: ban-drizzle-sql-raw
return SQL.raw("select * from users where id = 1");
}

/**
* ESM import Drizzle
*/

import Drizzle from "drizzle-orm";
async function rawGetUser(id) {
// ruleid: ban-drizzle-sql-raw
return Drizzle.sql.raw(`select * from users where id = ${id}`);
}

async function sqlEscapedGetUser(id) {
// ok: ban-drizzle-sql-raw
return Drizzle.sql.execute(sql`select * from users where id = ${id}`);
}

/**
* CommonJS import Drizzle
*/

const Drizzle = require("drizzle-orm");
async function rawGetUser(id) {
// ruleid: ban-drizzle-sql-raw
return Drizzle.sql.raw(`select * from users where id = ${id}`);
}

async function sqlEscapedGetUser(id) {
// ok: ban-drizzle-sql-raw
return Drizzle.sql.execute(sql`select * from users where id = ${id}`);
}

async function rawGetUserInTemplateLiteralsVariable(id) {
// ruleid: ban-drizzle-sql-raw
const query = `select * from users where id = ${id}`;
return Drizzle.sql.raw(query);
}

async function rawGetUserWithPlusOperator(id) {
// ruleid: ban-drizzle-sql-raw
const query = "select * from users where id = " + id;
return Drizzle.sql.raw(query);
}

async function rawGetUserWithPlusOperatorVariable(id) {
// ruleid: ban-drizzle-sql-raw
return Drizzle.sql.raw("select * from users where id = " + id);
}

async function rawGetUserWithoutInjection() {
// ok: ban-drizzle-sql-raw
return Drizzle.sql.raw("select * from users where id = 1");
}

91 changes: 91 additions & 0 deletions javascript/drizzle-orm/security/audit/ban-drizzle-sql-raw.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
rules:
- id: ban-drizzle-sql-raw
message:
Use of sql.raw() with SQL string concatenation is not allowed as it may lead to SQL injection.
Use parameterized queries with Drizzle's query builders instead.
fix: "/* Use sql`...` template literals or parameterized queries instead */"
metadata:
category: security
references:
- https://orm.drizzle.team/docs/sql#sqlraw
technology:
- javascript
- typescript
- drizzle-orm
cwe:
- "CWE-89: Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')"
subcategory:
- audit
likelihood: LOW
impact: HIGH
confidence: LOW
languages:
- javascript
- typescript
severity: ERROR
pattern-either:
- patterns:
- pattern-either:
- pattern-inside: |
const { sql } = require('drizzle-orm')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Explicit const/var/let here necessitates coverage of the other two, unless you are certain that this will only ever be a const import. Not making this change will cause CI to throw linter errors on this rule.

...
- pattern-inside: |
import { sql } from 'drizzle-orm'
...
- pattern-either:
- pattern: |
sql.raw(`...${...}...`)
- pattern: |
$QUERY = `...${...}...`
...
sql.raw($QUERY)
- pattern: |
$QUERY = $SQL + $VALUE
...
sql.raw($QUERY)
- pattern: |
sql.raw($SQL + $VALUE)

- patterns:
- pattern-either:
- pattern-inside: |
import { sql as $ALIAS } from 'drizzle-orm'
...
- pattern-inside: |
const { sql: $ALIAS } = require('drizzle-orm')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

...
- pattern-either:
- pattern: |
$ALIAS.raw(`...${...}...`)
- pattern: |
$QUERY = `...${...}...`
...
$ALIAS.raw($QUERY)
- pattern: |
$QUERY = $SQL + $VALUE
...
$ALIAS.raw($QUERY)
- pattern: |
$ALIAS.raw($SQL + $VALUE)

- patterns:
- pattern-either:
- pattern-inside: |
const $DRIZZLE = require('drizzle-orm')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

...
- pattern-inside: |
import $DRIZZLE from 'drizzle-orm'
...
- pattern-either:
- pattern: |
$DRIZZLE.sql.raw(`...${...}...`)
- pattern: |
$QUERY = `...${...}...`
...
$DRIZZLE.sql.raw($QUERY)
- pattern: |
$QUERY = $SQL + $VALUE
...
$DRIZZLE.sql.raw($QUERY)
- pattern: |
$DRIZZLE.sql.raw($SQL + $VALUE)
Loading