Skip to content

Commit 13ea1ae

Browse files
committed
Fix SQL injection false positives: require SQL structure in pattern
The regex now requires SQL keyword + structure (SELECT...FROM, INSERT INTO, UPDATE...SET, DELETE FROM, etc) instead of just matching bare keywords like DELETE or SELECT. This eliminates false positives like res.send('delete ' + name) being flagged as SQL injection. Applied to JS, Go, and Python rules. All test fixtures still detected. Express.js: 0 critical (was 1 false positive). none
1 parent 873fdb3 commit 13ea1ae

3 files changed

Lines changed: 7 additions & 4 deletions

File tree

src/rules/go.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ impl Rule for NoSqlInjection {
103103
fn check(&self, source: &str, tree: &tree_sitter::Tree) -> Vec<Finding> {
104104
let mut findings = Vec::new();
105105
let sql_pattern =
106-
Regex::new(r"(?i)(SELECT|INSERT|UPDATE|DELETE|DROP|ALTER|CREATE|EXEC)\s").unwrap();
106+
Regex::new(r"(?i)(SELECT\s+.{0,40}\s+FROM|INSERT\s+INTO|UPDATE\s+.{0,40}\s+SET|DELETE\s+FROM|DROP\s+TABLE|ALTER\s+TABLE|CREATE\s+TABLE|EXEC\s+)").unwrap();
107107

108108
walk_tree(tree.root_node(), source, &mut |node, src| {
109109
// Detect: "SELECT ... WHERE id = " + userId (binary_expression with +)

src/rules/javascript.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,11 @@ impl Rule for NoSqlInjection {
210210

211211
fn check(&self, source: &str, tree: &tree_sitter::Tree) -> Vec<Finding> {
212212
let mut findings = Vec::new();
213-
let sql_pattern =
214-
Regex::new(r"(?i)(SELECT|INSERT|UPDATE|DELETE|DROP|ALTER|CREATE|EXEC)\s").unwrap();
213+
// Require SQL keyword followed by SQL structure (FROM, INTO, SET, WHERE, TABLE, VALUES)
214+
// This avoids matching plain English like res.send('delete ' + name)
215+
let sql_pattern = Regex::new(
216+
r"(?i)(SELECT\s+.{0,40}\s+FROM|INSERT\s+INTO|UPDATE\s+.{0,40}\s+SET|DELETE\s+FROM|DROP\s+TABLE|ALTER\s+TABLE|CREATE\s+TABLE|EXEC\s+)"
217+
).unwrap();
215218

216219
walk_tree(tree.root_node(), source, &mut |node, src| {
217220
// Detect: query("SELECT * FROM users WHERE id = " + userId)

src/rules/python.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ impl Rule for NoSqlInjection {
183183
fn check(&self, source: &str, tree: &tree_sitter::Tree) -> Vec<Finding> {
184184
let mut findings = Vec::new();
185185
let sql_pattern =
186-
Regex::new(r"(?i)(SELECT|INSERT|UPDATE|DELETE|DROP|ALTER|CREATE|EXEC)\s").unwrap();
186+
Regex::new(r"(?i)(SELECT\s+.{0,40}\s+FROM|INSERT\s+INTO|UPDATE\s+.{0,40}\s+SET|DELETE\s+FROM|DROP\s+TABLE|ALTER\s+TABLE|CREATE\s+TABLE|EXEC\s+)").unwrap();
187187

188188
walk_tree(tree.root_node(), source, &mut |node, src| {
189189
// Detect f-strings with SQL: f"SELECT * FROM users WHERE id = {user_id}"

0 commit comments

Comments
 (0)