sql-injection-prevention

v2026.09.25

Detect and fix SQL injection vulnerabilities in any framework. Covers Laravel (DB::raw, whereRaw), Node.js (template literals in queries), Python (f-strings in SQL), and Cloudflare D1. Enforces parameterized bindings everywhere. Use when writing database queries, reviewing code for injection, or fixing SQL injection findings.

GitHub
安装命令
npx skhub add afu-it/sql-injection-prevention
Markdown
SKILL.md

SQL Injection Prevention

Detect and fix SQL injection vulnerabilities across any framework. This is Finding #1 from Malaysian PDPA court cases -- the most common and most dangerous vulnerability.

The Rule

NEVER concatenate user input into SQL strings. ALWAYS use parameterized bindings.

Detection Patterns

Node.js / TypeScript

BAD (vulnerable):

// Template literal injection
const result = await db.query(`SELECT * FROM users WHERE id = '${userId}'`);

// String concatenation
const result = await db.query("SELECT * FROM users WHERE name = '" + name + "'");

// Tagged template without proper escaping
const result = await db.raw(`SELECT * FROM orders WHERE status = ${status}`);

GOOD (safe):

// Parameterized binding with ?
const result = await db.prepare('SELECT * FROM users WHERE id = ?').bind(userId).first();

// Named parameters
const result = await db.query('SELECT * FROM users WHERE id = $1', [userId]);

// ORM with built-in escaping
const result = await prisma.user.findUnique({ where: { id: userId } });

Cloudflare D1

BAD:

await db.exec(`INSERT INTO logs (msg) VALUES ('${userInput}')`);

GOOD:

await db.prepare('INSERT INTO logs (msg) VALUES (?)').bind(userInput).run();
await db.batch([
  db.prepare('UPDATE credits SET amount = amount - 1 WHERE user_id = ?').bind(userId),
  db.prepare('INSERT INTO transactions (user_id, amount) VALUES (?, ?)').bind(userId, -1),
]);

Laravel / PHP

BAD:

DB::raw("SELECT * FROM users WHERE email = '$email'");
DB::select("SELECT * FROM users WHERE id = " . $request->id);
$query->whereRaw("status = '$status'");
$query->orderByRaw($request->sort_column . ' ' . $request->sort_direction);

GOOD:

DB::select('SELECT * FROM users WHERE email = ?', [$email]);
$query->whereRaw('status = ?', [$status]);
$query->orderByRaw('?? ??', [$sortColumn, $sortDirection]);
User::where('email', $email)->first();

Python

BAD:

cursor.execute(f"SELECT * FROM users WHERE id = {user_id}")
cursor.execute("SELECT * FROM users WHERE name = '" + name + "'")
cursor.execute("SELECT * FROM users WHERE id = %s" % user_id)

GOOD:

cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
cursor.execute("SELECT * FROM users WHERE id = :id", {"id": user_id})
User.objects.filter(id=user_id).first()  # Django ORM

Search Patterns

When auditing a codebase, search for these regex patterns:

# Node.js/TypeScript
`.*\$\{.*\}.*` near SELECT|INSERT|UPDATE|DELETE
".*" \+ .* near query|execute|raw
\.raw\(.*\$\{
\.exec\(`

# Laravel
DB::raw\(.*\$
whereRaw\(.*\$
orderByRaw\(.*\$
->select\(DB::raw\(.*\$

# Python
execute\(f"
execute\(".*" \+
execute\(".*%s" %

Fix Process

  1. Find all database query locations -- search for query/prepare/execute/raw calls
  2. Check each one -- does it use ? placeholders or string interpolation?
  3. Replace interpolation with bindings -- swap ${var} with ? and add .bind(var)
  4. Verify with tests -- run existing tests to ensure queries still work
  5. Add integration tests -- test that malicious input is safely handled

PDPA 2024 Consequence

Seksyen 5(1) dan 5(2) PDPA 2010 (Pindaan 2024):

  • Denda sehingga RM1,000,000
  • Penjara sehingga 3 tahun
  • Atau kedua-duanya sekali

SQL injection is the #1 finding in forensic digital analysis of negligent systems.

发现
标签

此技能尚未发布标签。

版本
最新版本元数据

版本

v2026.09.25

发布时间

Sep 25, 2026

分类

未分类

许可证

未指定

源路径

skills/sql-injection-prevention

默认分支

main

最新提交

6aeeb8f

Tree SHA

14cb46d