agentleFS
Smaui94Smaui94/ClaudeSkillCollection/sql-review/SKILL.md

sql-review

Skill0 starsChanged 9 days agoMITView on GitHub

Review SQL in application code and .sql/migration files - SQL injection through string building (also in ORM raw queries), UPDATE/DELETE without WHERE, SELECT *, N+1 queries, missing indexes, missing transactions, lost updates, non-sargable predicates, unbounded result sets, NULL pitfalls and risky migrations. Use when asked to check/review/audit SQL, queries, database access code, ORM usage, migrations or "is my query safe/fast".

10 other projects use a version of this.

Adopted by

Most recently taken up by

Used with

Projects with it also use code-review.

Other files people use alongside this one.

Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
  • GoogleSkill

    code-review

    Adversarial systems, concurrency, memory-model, and architecture code review protocol. Use this skill whenever asked to review code, PRs, diffs, or branches in Filament.

    Also in 4 projects that use this

The file

We split this skill into the rules it gives an agent

4 rules. 0 are common, 3 are distinctive, and 1 is very specific to this project.

  • 0

    Common

    Most of the 8 edited versions we read keep these.

  • 3

    Distinctive

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Read the schema (migrations, DDL, ORM models) for SQ5/SQ10.

    line 17
  2. Very specific:

    Use a linter if installed (never install it.

    line 18
  3. Distinctive:

    Every finding has a concrete location.

    line 61
  4. Distinctive:

    Do not change code. Apply fixes only when the user explicitly asks for it.

    line 65

“Common” is measured: kept by at least 6 in 10 of the 8 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

SQL review

Review only: report findings, never change queries, schemas or migrations unless the user explicitly asks. Never run queries, EXPLAIN ANALYZE or migrations against a real database without asking - they can be slow, lock tables or change data.

Scope

Check the files/directories the user names, otherwise the whole repo: .sql files, migrations (migrations/, db/migrate/, Flyway V*__*.sql, Liquibase, EF Migrations/, Alembic versions/), and code that builds or runs queries. Skip .git/, build output, vendor/, node_modules/, .venv/, generated code (EF model snapshots, ORM-generated clients) and seed/test data dumps.

Steps

  1. Detect the database (connection strings, drivers, migration tool, dialect hints) and the data access stack (table below).
  2. Find query construction: grep for SELECT|INSERT|UPDATE|DELETE in strings, raw-query APIs (execute, query, raw, FromSqlRaw, $queryRawUnsafe, createNativeQuery, text(), and string building near them (+, f-strings, %, .format, ${}, Sprintf, String.format, $"...").
  3. For each query, trace where the dynamic parts come from (user input, config, constants) and check SQ1-SQ14.
  4. Read the schema (migrations, DDL, ORM models) for SQ5/SQ10. Without a schema, SQ5 findings are "possible".
  5. Use a linter if installed (never install it; mention it if it would help): sqlfluff lint for .sql files, squawk for Postgres migrations, semgrep with SQL injection rules.
  6. Report (format below).

Rules

  • SQ1 error: SQL injection - dynamic values concatenated/formatted into the query instead of bound parameters (also inside ORM raw APIs). Dynamic identifiers (table, column, ORDER BY, ASC/DESC) can't be parameterized and need an allowlist.
  • SQ2 error: UPDATE/DELETE without WHERE, or with a WHERE clause that can end up empty when built dynamically
  • SQ3 warning: SELECT * in application code (over-fetching; breaks mapping when the schema changes)
  • SQ4 warning: N+1 - a query inside a loop over the results of another query; ORM lazy loading inside loops
  • SQ5 warning: missing index (possible) for columns used in frequent WHERE/JOIN/ORDER BY; foreign keys without index
  • SQ6 error: multi-statement write that must be atomic without a transaction; warning: transaction kept open during network calls or user interaction
  • SQ7 warning: lost update - read value, compute, write back without locking or version check (SELECT then UPDATE with the computed value)
  • SQ8 warning: non-sargable predicate or implicit conversion: function on an indexed column (WHERE LOWER(email) = ?, DATE(created_at) = ?), leading wildcard LIKE '%x', comparing text to number
  • SQ9 warning: unbounded result set for user-facing lists (no LIMIT/pagination); LIMIT without ORDER BY (non-deterministic pages)
  • SQ10 warning: risky migration: long table locks (index creation without CONCURRENTLY/ONLINE, rewriting large tables, adding NOT NULL without default on large tables depending on DB version), no down/rollback path, schema and data changes mixed
  • SQ11 error: = NULL / <> NULL instead of IS NULL; warning: NOT IN (subquery) where the subquery can return NULL (returns no rows)
  • SQ12 warning: connections/cursors not closed or no pool → error-handling-review EH6; credentials in connection strings → secrets-scan
  • SQ13 info: DISTINCT/GROUP BY used to hide duplicate rows from a wrong join
  • SQ14 info: dialect-specific syntax in a project that claims to support several databases

Safe vs. unsafe per stack

StackSafeUnsafe (SQ1)
JDBCPreparedStatement with ?Statement.execute("..." + x)
JPA / HibernatesetParameter, Criteria APIcreateQuery/createNativeQuery with concatenation
ADO.NET / DapperSqlParameter, Dapper new { id }interpolation into CommandText
EF CoreLINQ, FromSql($"..."), FromSqlInterpolatedFromSqlRaw/ExecuteSqlRaw with a pre-built string
Python DB-API (sqlite3, psycopg)cur.execute(sql, params) with ?/%sf-string, %, .format into sql
SQLAlchemytext("... :id") with bind params, ORMtext(f"...")
DjangoORM, raw(sql, params)raw(f"..."), extra() with strings
node-postgres / mysql2query(text, values) with $1/?template literal into text
Prisma$queryRaw`...${x}` (tagged)$queryRawUnsafe with concatenation
Knexquery builder, raw('?', [x])raw(`... ${x}`)
Go database/sql, GORMQuery(sql, args...), Where("x = ?", v)fmt.Sprintf into Query/Where
PHP PDOprepare + executequery("..." . $x)

False positives to drop

Concatenation of constant strings only (no external input) · identifiers from a hard-coded allowlist · SELECT * in ad-hoc scripts, EXISTS (SELECT * ...) and COUNT(*) · N+1 on tiny bounded lists (report as info) · migrations for tables that are known to be small.

Report

In the user's language, grouped by file:

path/to/file:line - error|warning|info - <ID> <rule> - <what can happen, e.g. "name=' OR 1=1 -- returns all users"> - direction: <what the fix must achieve, e.g. "bind the value as a parameter">
  • Every finding has a concrete location; for SQ1 name the source of the dynamic value. Don't write working attack payloads beyond a minimal illustration like the one above.
  • Mark findings that depend on unknown data size or schema as "possible".
  • Bulk hits with one root cause (e.g. one query helper that concatenates): report once with count and 2-3 call sites.
  • End with a summary: database and access stack, findings per severity, then the 3 most important things to fix first.
  • Do not change code. Apply fixes only when the user explicitly asks for it.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.