agentsclimarketplace

Detecting sql injection patterns

Skill jeremylongshore/claude-code-plugins-plus-skills/plugins/security/penetration-tester/skills/detecting-sql-injection-patterns

425 plugins, 2,810 skills, 200 agents for Claude Code. Open-source marketplace at tonsofskills.com with the ccpi CLI package manager.

Install
npx -y skills add jeremylongshore/claude-code-plugins-plus-skills --skill detecting-sql-injection-patterns

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

What its author says it does

Copied from the file, not written here

Scan a source tree for SQL-injection vulnerable patterns: string concatenation into queries, f-string interpolation in SQL, string-format substitution into raw queries, deprecated cursor methods (cursor.execute with % formatting), Knex / Sequelize raw() with template interpolation, sequelize.query with replacements. Use when: pre-commit code review, post-feature SQL-touching release, inheriting a legacy codebase that predates ORMs, or post-bug-report investigation. Threshold: any source line where SQL keywords (SELECT / INSERT / UPDATE / DELETE / FROM / WHERE) appear in a string that's being built via concatenation, f-string, %-format, or .format() with variable input. Trigger with: "scan for sqli", "sql injection patterns", "check raw queries", "audit cursor.execute".

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

5.8 KB, as published. Nobody here has run it

Detecting SQL Injection Patterns

Overview

SQL injection (CWE-89, OWASP A03:2021) remains one of the highest- impact and most-easily-introduced vulnerability classes. The fix is near-universal: use parameterized queries. The cause when introduced: an engineer concatenates user input into a SQL string because the ORM's parameterization mechanism wasn't obvious, or because they "just need to add a quick condition."

The scanner reads source files and grades each apparent SQL-string construction against the threshold table.

When the skill produces findings

FindingSeverityThresholdAffected control
f-string with SQL keywords + user inputCRITICALf"SELECT * FROM users WHERE id = {user_id}"CWE-89
String concat into SQL keyword stringCRITICAL"SELECT ... " + var + " ..."CWE-89
%-format SQL stringHIGH"SELECT * FROM %s" % table_nameCWE-89
.format() into SQL stringHIGH"SELECT {} FROM users".format(col)CWE-89
cursor.execute(f"...")CRITICALf-string passed directly to cursor.executeCWE-89
sequelize.query with template literalHIGHsequelize.query(\SELECT * FROM ${table}`)`CWE-89
Knex / sequelize raw() with interpolationHIGHknex.raw('SELECT * FROM ' + table)CWE-89
Django .extra() with raw SQLMEDIUMModel.objects.extra(where=['col = ' + val])CWE-89
cursor.executemany with string-built queryCRITICALSame risk as executeCWE-89
JDBC Statement.execute with concatHIGHJava pattern: not PreparedStatementCWE-89
Rails where() with string interpolationHIGHUser.where("name = '#{name}'")CWE-89
Go db.Query with fmt.SprintfHIGHdb.Query(fmt.Sprintf("...", arg))CWE-89

Prerequisites

  • Python 3.9+
  • Target source tree on local filesystem

Instructions

Step 1 — Run the scanner

python3 ${CLAUDE_PLUGIN_ROOT}/skills/detecting-sql-injection-patterns/scripts/scan_sqli.py /path/to/repo

Options:

Usage: scan_sqli.py PATH [OPTIONS]

Options:
  --output FILE      Write findings to FILE
  --format FMT       json | jsonl | markdown (default: markdown)
  --min-severity SEV (default: info)
  --include-tests    Include test directories (default: excluded)
  --languages LIST   Comma-separated: python,javascript,typescript,java,
                     ruby,go,php,csharp (default: all)

Step 2 — Interpret findings

CRITICAL = direct user-input → query string construction. Fix the specific query AND audit nearby code for the same pattern.

HIGH = pattern suggests interpolation but might be a fixed identifier (table/column name). Verify by reading the code.

MEDIUM = framework-specific pattern that's safe ONLY with strict input validation (Django .extra(), Rails string where()).

Step 3 — Remediation

For each finding, the fix is the same shape per language: use the language/library's parameterized-query API. See references/PLAYBOOK.md for per-language snippets.

Step 4 — Cross-skill chaining

Consider running scanning-for-hardcoded-secrets (#10) on the same target — same audit, different class of finding.

Examples

Example 1 — Pre-merge code review

python3 ${CLAUDE_PLUGIN_ROOT}/skills/detecting-sql-injection-patterns/scripts/scan_sqli.py \
    --min-severity high $(git diff --name-only main...HEAD | tr '\n' ' ')

Scans only files changed in the current branch — fast feedback for PR review.

Example 2 — Legacy codebase audit

python3 ${CLAUDE_PLUGIN_ROOT}/skills/detecting-sql-injection-patterns/scripts/scan_sqli.py \
    /path/to/legacy-app --format markdown > sqli-audit.md

Expect dozens to hundreds of findings on a pre-ORM Java/PHP codebase. Prioritize by reachability: the queries reached from public endpoints first.

Output

JSON / JSONL / Markdown. Exit codes: 0 clean, 1 high/critical, 2 error.

Error Handling

  • False positives on fixed-identifier interpolation (e.g., f"SELECT * FROM {tablename}" where tablename is hardcoded) → verify manually. The scanner can't reason about variable provenance without a full AST + control-flow pass.
  • String-built dynamic-table queries are sometimes legitimate (multi-tenant routing). Flag and review; the fix is usually allow-list validation + identifier quoting.

Resources

  • references/THEORY.md — Per-language interpolation patterns, ORM-specific safe vs unsafe APIs, why prepared statements work
  • references/PLAYBOOK.md — Per-language parameterization snippets (Python sqlite3 + psycopg + SQLAlchemy, Node mysql2 + pg + knex
    • sequelize, Ruby ActiveRecord, Go database/sql, Java JDBC PreparedStatement, PHP PDO)

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.