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.
npx -y skills add jeremylongshore/claude-code-plugins-plus-skills --skill detecting-sql-injection-patternsAssembled 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
| Finding | Severity | Threshold | Affected control |
|---|---|---|---|
| f-string with SQL keywords + user input | CRITICAL | f"SELECT * FROM users WHERE id = {user_id}" | CWE-89 |
| String concat into SQL keyword string | CRITICAL | "SELECT ... " + var + " ..." | CWE-89 |
| %-format SQL string | HIGH | "SELECT * FROM %s" % table_name | CWE-89 |
.format() into SQL string | HIGH | "SELECT {} FROM users".format(col) | CWE-89 |
cursor.execute(f"...") | CRITICAL | f-string passed directly to cursor.execute | CWE-89 |
sequelize.query with template literal | HIGH | sequelize.query(\SELECT * FROM ${table}`)` | CWE-89 |
| Knex / sequelize raw() with interpolation | HIGH | knex.raw('SELECT * FROM ' + table) | CWE-89 |
Django .extra() with raw SQL | MEDIUM | Model.objects.extra(where=['col = ' + val]) | CWE-89 |
cursor.executemany with string-built query | CRITICAL | Same risk as execute | CWE-89 |
JDBC Statement.execute with concat | HIGH | Java pattern: not PreparedStatement | CWE-89 |
Rails where() with string interpolation | HIGH | User.where("name = '#{name}'") | CWE-89 |
Go db.Query with fmt.Sprintf | HIGH | db.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}"wheretablenameis 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 workreferences/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)