Agent skill

Sast Sqli

by utkusen in utkusen/sast-skills

Detect SQL injection vulnerabilities in a codebase using a three-phase approach: recon (find unsafe SQL construction sites), batched verify (trace user input to those sites in parallel subagents, 3…

MITAuto-check passedSecurity

Install Sast Sqli

skills CLI
$ npx skills add utkusen/sast-skills --skill sast-sqli -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install utkusen/sast-skills sast-sqli --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/utkusen/sast-skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/sast-files/.agents/skills/sast-sqli .claude/skills/sast-sqli && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
sast-sqli
GitHub stars
1.3k
Token cost
~6k tokens
SKILL.md length
2,145 words
Files
1
Skills in repo
16
Repo updated
First seen
Licence
MIT

At a glance

Detect SQL injection vulnerabilities in a codebase using a three-phase approach: recon (find unsafe SQL construction sites), batched verify (trace user input to those sites in parallel subagents, 3…

  • Works in 3 steps: Recon — Find Vulnerable SQL Construction… → Verify — Taint Analysis (Batched) → Merge — Consolidate Batch Results
  • Asked to find SQLi
  • SKILL.md covers What is SQL Injection, Vulnerable vs. Secure Examples, Execution and Important Reminders
  • Instructions only: no scripts, shell commands, URLs or credentials in SKILL.md

What it does

Sast Sqli is an agent skill from utkusen/sast-skills. Detect SQL injection vulnerabilities in a codebase using a three-phase approach: recon (find unsafe SQL construction sites), batched verify (trace user input to those sites in parallel subagents, 3 sites each), and merge (consolidate batch results). Covers string concat, f-strings, unsafe ORM methods, and dynamic identifiers. Requires sast/architecture.md (run sast-analysis first). Outputs findings to sast/sqli-results.md. Use when asked to find SQLi or database injection bugs.

Its SKILL.md is about 6k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Security, covering Static analysis and SAST, Web application vulnerabilities and ORMs and data access. It works with SQL and Python. The repository describes itself as: Collection of agent skills to find vulnerabilities inside your web/mobile apps. The licence is MIT.

When your agent uses it

  • Asked to find SQLi
  • Database injection bugs

Example prompts

  • “/sast-sqli”

Requirements

  • Python 3
  • Node.js

Workflow steps

3 steps, taken from the step headings in SKILL.md.

  1. Recon — Find Vulnerable SQL Construction Sites
  2. Verify — Taint Analysis (Batched)
  3. Merge — Consolidate Batch Results

What it can do on your machine

Read from SKILL.md and the folder at commit db52227. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    No scripts in the folder and no shell commands in SKILL.md (its code samples are python, javascript, markdown, ruby, java, go, php and csharp).

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Sast Sqli loads about 6k tokens when it runs. Until then it costs about 123 tokens; SKILL.md has 2,145 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~123
When it runs · the whole SKILL.md, loaded when a task matches
~6k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from utkusen/sast-skills at commit db52227, republished under its MIT licence (© utkusen). 2,145 words, ~6,041 tokens.

Download SKILL.mdSave it as .claude/skills/sast-sqli/SKILL.md (or your agent's skills folder).
name
sast-sqli
description
Detect SQL injection vulnerabilities in a codebase using a three-phase approach: recon (find unsafe SQL construction sites), batched verify (trace user input to those sites in parallel subagents, 3 sites each), and merge (consolidate batch results). Covers string concat, f-strings, unsafe ORM methods, and dynamic identifiers. Requires sast/architecture.md (run sast-analysis first). Outputs findings to sast/sqli-results.md. Use when asked to find SQLi or database injection bugs.

SQL Injection (SQLi) Detection

You are performing a focused security assessment to find SQL injection vulnerabilities in a codebase. This skill uses a three-phase approach with subagents: recon (find vulnerable SQL construction sites), batched verify (taint analysis in parallel batches of 3), and merge (consolidate batch reports into one file).

Prerequisites: sast/architecture.md must exist. Run the analysis skill first if it doesn't.


What is SQL Injection

SQL injection occurs when user-supplied input is incorporated into SQL queries through string concatenation or interpolation rather than parameterized binding. This allows attackers to alter query logic, bypass authentication, extract sensitive data, modify or delete records, and in some configurations execute OS commands.

The core pattern: unvalidated, unparameterized user input reaches a SQL query execution call.

What SQLi IS
  • Concatenating user input directly into a SQL string: "SELECT * FROM users WHERE name = '" + username + "'"
  • Using string formatting to build queries: f"SELECT * FROM orders WHERE id = {order_id}"
  • Dynamic ORDER BY / GROUP BY / table/column names from user input with no allowlist validation
  • ORM raw query methods with unsanitized input: User.objects.raw(f"SELECT * WHERE id={id}"), $queryRawUnsafe(input)
  • Second-order injection: input is stored in the DB and later used in a raw query without re-sanitization
What SQLi is NOT

Do not flag these as SQLi:

  • IDOR: Changing ?id=1 to ?id=2 to access another user's data — that's Insecure Direct Object Reference, a separate class
  • Mass assignment: Setting extra ORM model fields from user input — different vulnerability
  • XSS via database: Storing a <script> tag in the DB that's later rendered unescaped — that's XSS, not SQLi
  • NoSQL injection: Injecting into MongoDB operators — similar concept but a distinct vulnerability class
  • Safe ORM queries: Parameterized ORM lookups like User.objects.filter(id=user_id) or User.find(params[:id]) — do not flag these
Patterns That Prevent SQLi

When you see these patterns, the code is likely not vulnerable:

1. Parameterized queries / prepared statements (most common fix)

# Python — cursor.execute with tuple binding
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))

# Node.js — mysql2 / pg placeholder binding
db.query("SELECT * FROM users WHERE id = ?", [userId])
pool.query("SELECT * FROM users WHERE id = $1", [userId])

# Java — PreparedStatement
PreparedStatement ps = conn.prepareStatement("SELECT * FROM users WHERE id = ?");
ps.setInt(1, userId);

# Go — database/sql placeholder
db.QueryRow("SELECT * FROM users WHERE id = $1", userID)

# PHP — PDO with named params
$stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
$stmt->execute(['id' => $userId]);

# C# — SqlCommand with parameters
cmd.CommandText = "SELECT * FROM users WHERE id = @id";
cmd.Parameters.AddWithValue("@id", userId);

2. ORM query builder (safe by default)

# Django ORM
User.objects.filter(id=user_id)

# ActiveRecord (Rails)
User.find(params[:id])
User.where(name: params[:name])

# Prisma (tagged template literal form of $queryRaw)
await prisma.$queryRaw`SELECT * FROM users WHERE id = ${userId}`

# Laravel Eloquent (non-raw)
User::find($id)

3. Allowlist validation for dynamic identifiers

# Dynamic ORDER BY — validate column name against a hardcoded set before interpolating
ALLOWED_COLUMNS = {'name', 'created_at', 'price'}
if sort_col not in ALLOWED_COLUMNS:
    raise ValueError("Invalid column")
query = f"SELECT * FROM products ORDER BY {sort_col}"  # safe only after allowlist check

Vulnerable vs. Secure Examples

Python — Django (raw SQL)
python
# VULNERABLE: f-string interpolation in raw()
def search_users(request):
    username = request.GET.get('username')
    users = User.objects.raw(f"SELECT * FROM auth_user WHERE username = '{username}'")
    return JsonResponse(list(users.values()), safe=False)

# SECURE: parameterized raw()
def search_users(request):
    username = request.GET.get('username')
    users = User.objects.raw("SELECT * FROM auth_user WHERE username = %s", [username])
    return JsonResponse(list(users.values()), safe=False)
Python — Flask / SQLAlchemy
python
# VULNERABLE: f-string into text()
@app.route('/search')
def search():
    name = request.args.get('name')
    result = db.session.execute(text(f"SELECT * FROM products WHERE name = '{name}'"))
    return jsonify(result.fetchall())

# SECURE: named bound parameter
@app.route('/search')
def search():
    name = request.args.get('name')
    result = db.session.execute(
        text("SELECT * FROM products WHERE name = :name"), {"name": name}
    )
    return jsonify(result.fetchall())
Python — sqlite3 / psycopg2
python
# VULNERABLE
def get_user(username):
    cursor.execute("SELECT * FROM users WHERE username = '" + username + "'")
    return cursor.fetchone()

# SECURE
def get_user(username):
    cursor.execute("SELECT * FROM users WHERE username = ?", (username,))
    return cursor.fetchone()
Node.js — mysql2
javascript
// VULNERABLE: template literal in query string
app.get('/user', async (req, res) => {
  const { id } = req.query;
  const [rows] = await db.query(`SELECT * FROM users WHERE id = ${id}`);
  res.json(rows);
});

// SECURE: placeholder binding
app.get('/user', async (req, res) => {
  const { id } = req.query;
  const [rows] = await db.query('SELECT * FROM users WHERE id = ?', [id]);
  res.json(rows);
});
Node.js — pg (PostgreSQL)
javascript
// VULNERABLE
app.get('/orders', async (req, res) => {
  const status = req.query.status;
  const result = await pool.query(`SELECT * FROM orders WHERE status = '${status}'`);
  res.json(result.rows);
});

// SECURE
app.get('/orders', async (req, res) => {
  const status = req.query.status;
  const result = await pool.query('SELECT * FROM orders WHERE status = $1', [status]);
  res.json(result.rows);
});
Ruby on Rails
ruby
# VULNERABLE: string interpolation in where()
def search
  @users = User.where("name = '#{params[:name]}'")
end

# VULNERABLE: find_by_sql with interpolation
def find_user
  @user = User.find_by_sql("SELECT * FROM users WHERE email = '#{params[:email]}'")
end

# SECURE: parameterized where()
def search
  @users = User.where("name = ?", params[:name])
  # or using hash form: User.where(name: params[:name])
end
Java — Spring JDBC
java
// VULNERABLE: string concatenation
public User findUser(String username) {
    String sql = "SELECT * FROM users WHERE username = '" + username + "'";
    return jdbcTemplate.queryForObject(sql, userRowMapper);
}

// SECURE: parameterized query
public User findUser(String username) {
    return jdbcTemplate.queryForObject(
        "SELECT * FROM users WHERE username = ?", userRowMapper, username
    );
}
Go — database/sql
go
// VULNERABLE: fmt.Sprintf to build query
func GetUserByName(name string) (*User, error) {
    query := fmt.Sprintf("SELECT * FROM users WHERE name = '%s'", name)
    row := db.QueryRow(query)
    // ...
}

// SECURE: parameterized query
func GetUserByName(name string) (*User, error) {
    row := db.QueryRow("SELECT * FROM users WHERE name = $1", name)
    // ...
}
PHP — PDO
php
// VULNERABLE: string concatenation
function getUser($id) {
    $stmt = $pdo->query("SELECT * FROM users WHERE id = " . $id);
    return $stmt->fetch();
}

// SECURE: prepared statement
function getUser($id) {
    $stmt = $pdo->prepare("SELECT * FROM users WHERE id = :id");
    $stmt->execute(['id' => $id]);
    return $stmt->fetch();
}
C# — ADO.NET
csharp
// VULNERABLE: string concatenation
public User GetUser(string username) {
    using var cmd = new SqlCommand(
        "SELECT * FROM Users WHERE Username = '" + username + "'", conn);
    return ReadUser(cmd.ExecuteReader());
}

// SECURE: parameterized command
public User GetUser(string username) {
    using var cmd = new SqlCommand(
        "SELECT * FROM Users WHERE Username = @username", conn);
    cmd.Parameters.AddWithValue("@username", username);
    return ReadUser(cmd.ExecuteReader());
}
Dynamic ORDER BY / Column Names (all stacks)
python
# VULNERABLE: unsanitized user input as column name (parameterization can't help here)
sort_col = request.args.get('sort', 'name')
cursor.execute(f"SELECT * FROM products ORDER BY {sort_col}")

# SECURE: allowlist validation before interpolation
ALLOWED_SORT_COLS = {'name', 'price', 'created_at'}
sort_col = request.args.get('sort', 'name')
if sort_col not in ALLOWED_SORT_COLS:
    return abort(400)
cursor.execute(f"SELECT * FROM products ORDER BY {sort_col}")

Execution

This skill runs in three phases using subagents. Pass the contents of sast/architecture.md to all subagents as context.

Phase 1: Recon — Find Vulnerable SQL Construction Sites

Launch a subagent with the following instructions:

Goal: Find every location in the codebase where a SQL query is constructed in a vulnerable way — using string concatenation, interpolation, or formatting with any variable (regardless of where that variable comes from). Write results to sast/sqli-recon.md.

Context: You will be given the project's architecture summary. Use it to understand the tech stack, database layer, ORM patterns, and query execution methods.

What to search for — vulnerable query construction patterns:

Look for SQL query execution calls where the query string argument is built dynamically rather than being a static string with placeholder parameters. Flag ANY dynamic variable embedded into the query — you are not yet tracing whether the variable is user-controlled; that is Phase 2's job.

  1. String concatenation into a SQL execution call:

    • cursor.execute("SELECT ... WHERE id = " + var)
    • $pdo->query("SELECT * FROM users WHERE id = " . $var)
    • jdbcTemplate.query("SELECT * WHERE username = '" + var + "'")
  2. F-strings / template literals used as a query argument:

    • cursor.execute(f"SELECT * WHERE name = '{var}'")
    • db.query(`SELECT * WHERE id = ${var}`)
    • db.QueryRow(fmt.Sprintf("SELECT * WHERE id = '%s'", var))
  3. String formatting functions used to build the query:

    • cursor.execute("SELECT * WHERE id = %s" % var) (note: % formatting, NOT parameterized binding)
    • cursor.execute("SELECT * WHERE id = {}".format(var))
    • String.format("SELECT * WHERE id = '%s'", var) (Java)
    • sprintf("SELECT * WHERE id = %s", $var) (PHP)
  4. ORM raw/unsafe methods called with a dynamically built string (not a static template with bound params):

    • Django: Model.objects.raw(f"..."), RawSQL(f"..."), extra(where=[f"..."])
    • ActiveRecord: where("col = '#{var}'") (Ruby interpolation inside string arg)
    • Sequelize: sequelize.query(`...${var}...`), literal(var)
    • TypeORM: createQueryBuilder().where(`col = '${var}'`), .query("..." + var)
    • Prisma: $queryRawUnsafe(...), $executeRawUnsafe(...)
    • Entity Framework: FromSqlRaw("..." + var), ExecuteSqlRaw("..." + var)
  5. Dynamic identifiers — any variable used as a column name, table name, ORDER BY / GROUP BY value in a query string (parameterization cannot protect identifiers; only allowlist validation can):

    • f"SELECT * FROM {table_var}"
    • `SELECT * FROM ${tableVar}`
    • f"SELECT * ORDER BY {sort_col}"

What to skip (these are safe construction patterns — do not flag):

  • Static query strings with no dynamic parts: cursor.execute("SELECT * FROM users WHERE id = %s", (val,))
  • ORM safe query builder methods: .filter(), .where(col: val), .findOne(), .findUnique(), prisma.$queryRaw with tagged template literals
  • Properly parameterized raw queries where the string itself is static and values are passed as a separate argument list: execute("SELECT * WHERE id = %s", (val,)), query("SELECT * WHERE id = ?", [val])

Output format — write to sast/sqli-recon.md:

markdown
# SQLi Recon: [Project Name]

## Summary
Found [N] locations where SQL queries are constructed in a vulnerable way.

## Vulnerable Construction Sites

### 1. [Descriptive name — e.g., "String concat in get_user query"]
- **File**: `path/to/file.ext` (lines X-Y)
- **Function / endpoint**: [function name or route]
- **Query execution method**: [cursor.execute / db.query / raw / etc.]
- **Construction pattern**: [string concat / f-string / template literal / % format / .format() / fmt.Sprintf / ORM raw]
- **Interpolated variable(s)**: `var_name` — [brief note on what it appears to represent, e.g., "looks like a sort column" or "unknown origin"]
- **Code snippet**:

[the vulnerable query construction + execution call]


[Repeat for each site]
After Phase 1: Check for Candidates Before Proceeding

After Phase 1 completes, read sast/sqli-recon.md. If the recon found zero vulnerable construction sites (the summary reports "Found 0" or the "Vulnerable Construction Sites" section is empty or absent), skip Phase 2 entirely. Instead, write the following content to sast/sqli-results.md and stop:

markdown
# SQLi Analysis Results

No vulnerabilities found.

Only proceed to Phase 2 if Phase 1 found at least one vulnerable construction site.

Phase 2: Verify — Taint Analysis (Batched)

After Phase 1 completes, read sast/sqli-recon.md and split the construction sites into batches of up to 3 sites each. Launch one subagent per batch in parallel. Each subagent traces user input only for its assigned sites and writes results to its own batch file.

Batching procedure (you, the orchestrator, do this — not a subagent):

  1. Read sast/sqli-recon.md and count the numbered site sections under "Vulnerable Construction Sites" (### 1., ### 2., etc.).
  2. Divide them into batches of up to 3. For example, 8 sites → 3 batches (1-3, 4-6, 7-8).
  3. For each batch, extract the full text of those site sections from the recon file.
  4. Launch all batch subagents in parallel, passing each one only its assigned sites.
  5. Each subagent writes to sast/sqli-batch-N.md where N is the 1-based batch number.
  6. Identify the project's primary language/framework from sast/architecture.md and select only the matching examples from the "Vulnerable vs. Secure Examples" section above. For example, if the project uses Node.js with pg, include the "Node.js — pg (PostgreSQL)" and related Node examples. Include these selected examples in each subagent's instructions where indicated by [TECH-STACK EXAMPLES] below.

Give each batch subagent the following instructions (substitute the batch-specific values):

Goal: For each assigned vulnerable SQL construction site, determine whether a user-supplied value reaches the interpolated variable. Our goal is to find SQL injection vulnerabilities. Write results to sast/sqli-batch-[N].md.

Your assigned construction sites (from the recon phase):

[Paste the full text of the assigned site sections here, preserving the original numbering]

Context: You will be given the project's architecture summary. Use it to understand request entry points, middleware, and how data flows through the application.

SQLi reference — trace the interpolated variable(s) backwards to their origin:

  1. Direct user input — the variable is assigned directly from a request source with no transformation:

    • HTTP query params: request.GET.get(...), req.query.x, params[:x], $_GET['x'], c.Query("x")
    • Path parameters: request.path_params['id'], req.params.id, params[:id]
    • Request body / form fields: request.POST.get(...), req.body.x, params[:x], $_POST['x']
    • HTTP headers: request.headers.get(...), req.headers['x']
    • Cookies: request.COOKIES.get(...), req.cookies.x
  2. Indirect user input — the variable is derived from user input through transformations, function calls, or intermediate assignments. Trace the full chain:

    • Variable assigned from a function return value → check that function's parameter origin
    • Variable passed as a function argument → check the call site(s)
    • Variable read from a class attribute or shared state set elsewhere → find the setter
    • Variable conditionally assigned — check all branches
  3. Second-order input — the variable is read from the database, but the stored value originally came from user input:

    • Find where this value was written to the DB — was it stored from a user-supplied field?
    • Was it sanitized or parameterized at write time?
  4. Server-side / hardcoded value — the variable comes from config, an environment variable, a hardcoded constant, or server-side logic with no user influence — this site is NOT exploitable.

Mitigations (check even if user input might reach the variable):

  • Allowlist validation before use (especially for dynamic identifiers — column/table names, ORDER BY)
  • Type casts that genuinely constrain the value in context (e.g., int(val) in purely numeric SQL fragments)
  • Custom escaping (mysql_real_escape_string, addslashes, homegrown sanitizers) is not equivalent to parameterization — still classify as Likely Vulnerable if taint is present

Vulnerable vs. Secure examples for this project's tech stack:

[TECH-STACK EXAMPLES]

Classification:

  • Vulnerable: User input demonstrably reaches the interpolated variable with no effective mitigation.
  • Likely Vulnerable: User input probably reaches the variable (indirect flow) or only weak mitigation (custom escaping) is present.
  • Not Vulnerable: The variable is server-side only, OR effective parameterization / allowlist validation is in place.
  • Needs Manual Review: Cannot determine the variable's origin with confidence (opaque helpers, complex flows, external libraries).

Output format — write to sast/sqli-batch-[N].md:

markdown
# SQLi Batch [N] Results

## Findings

### [VULNERABLE] Descriptive name
- **File**: `path/to/file.ext` (lines X-Y)
- **Endpoint / function**: [route or function name]
- **Issue**: [e.g., "HTTP query param `username` flows directly into f-string SELECT query"]
- **Taint trace**: [Step-by-step from entry point to the construction site]
- **Impact**: [What an attacker can do — extract records, bypass auth, delete data, etc.]
- **Remediation**: [Parameterized query, ORM equivalent, or allowlist for identifiers]
- **Dynamic Test**:

[sqlmap command or manual curl payload. Show parameter, payload, expected response signal. Example: sqlmap -u "https://app.example.com/search?q=test" -p q --dbs]


### [LIKELY VULNERABLE] Descriptive name
- **File**: `path/to/file.ext` (lines X-Y)
- **Endpoint / function**: [route or function name]
- **Issue**: [e.g., "Indirect flow or custom escaping only"]
- **Taint trace**: [Best-effort trace; mark uncertain steps]
- **Concern**: [Why it remains a risk]
- **Remediation**: [Replace with parameterized query]
- **Dynamic Test**:

[payload to attempt bypass]


### [NOT VULNERABLE] Descriptive name
- **File**: `path/to/file.ext` (lines X-Y)
- **Endpoint / function**: [route or function name]
- **Reason**: [e.g., "Server-side constant" or "Allowlist gates sort column"]

### [NEEDS MANUAL REVIEW] Descriptive name
- **File**: `path/to/file.ext` (lines X-Y)
- **Endpoint / function**: [route or function name]
- **Uncertainty**: [Why origin could not be determined]
- **Suggestion**: [What to trace manually]
Show full SKILL.md (470 more words)Show less
Phase 3: Merge — Consolidate Batch Results

After all Phase 2 batch subagents complete, read every sast/sqli-batch-*.md file and merge them into a single sast/sqli-results.md. You (the orchestrator) do this directly — no subagent needed.

Merge procedure:

  1. Read all sast/sqli-batch-1.md, sast/sqli-batch-2.md, ... files.
  2. Collect all findings from each batch file and combine them into one list, preserving the original classification and all detail fields.
  3. Count totals across all batches for the executive summary (construction sites analyzed = total sites from recon that were batched, i.e., sum of sites across batches).
  4. Write the merged report to sast/sqli-results.md using this format:
markdown
# SQLi Analysis Results: [Project Name]

## Executive Summary
- Construction sites analyzed: [total across all batches]
- Vulnerable: [N]
- Likely Vulnerable: [N]
- Not Vulnerable: [N]
- Needs Manual Review: [N]

## Findings

[All findings from all batches, grouped by classification:
 VULNERABLE first, then LIKELY VULNERABLE, then NEEDS MANUAL REVIEW, then NOT VULNERABLE.
 Preserve every field from the batch results exactly as written.]
  1. After writing sast/sqli-results.md, delete all intermediate batch files (sast/sqli-batch-*.md).

Important Reminders

  • Read sast/architecture.md and pass its content to all subagents as context.
  • Phase 2 must run AFTER Phase 1 completes — it depends on the recon output.
  • Phase 3 must run AFTER all Phase 2 batches complete — it depends on all batch outputs.
  • Batch size is 3 construction sites per subagent. If there are 1-3 sites total, use a single subagent. If there are 10, use 4 subagents (3+3+3+1).
  • Launch all batch subagents in parallel — do not run them sequentially.
  • Each batch subagent receives only its assigned sites' text from the recon file, not the entire recon file. This keeps each subagent's context small and focused.
  • Phase 1 is purely structural: flag any dynamic variable embedded in a SQL query string, regardless of origin. Do not trace user input in Phase 1 — that is Phase 2's job.
  • Phase 2 is purely taint analysis: for each assigned site, trace the interpolated variable back to its origin. If it comes from a user-controlled source, the site is a real vulnerability.
  • Focus on raw SQL and ORM raw/unsafe methods. Standard ORM query builder calls (.filter(), .where(col: val), .find()) are safe by default — do not flag them.
  • When in doubt, classify as "Needs Manual Review" rather than "Not Vulnerable". False negatives are worse than false positives in security assessment.
  • Taint can flow indirectly: a request parameter may be extracted in a middleware, stored in a shared object, passed through several helper functions, and finally reach the query construction. Trace the full chain.
  • Custom escaping (including mysql_real_escape_string, addslashes, or homegrown sanitizers) is not equivalent to parameterization — flag as Likely Vulnerable even if escaping is present.
  • For dynamic identifiers (column/table names), parameterization cannot help — the only safe fix is allowlist validation. Flag any dynamic identifier without an allowlist, regardless of whether it appears user-controlled.
  • Second-order injection is easy to miss: a value stored in the DB from user input may later be read and used unsafely in a raw query elsewhere in the codebase. In Phase 2, treat DB-read values as potentially tainted and trace back to where they were written.
  • Clean up intermediate files: delete sast/sqli-recon.md and all sast/sqli-batch-*.md files after the final sast/sqli-results.md is written.

© utkusen, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in sast-files/.agents/skills/sast-sqli of utkusen/sast-skills.

Open the folder on GitHubat commit db52227

Compare with similar skills

Sast Sqli next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Sast Sqli compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Sast Sqli this skillutkusen/sast-skills1.3k—~6kAutomated safety check: PassMIT
Php Thinkphp Audit0xShe/PHP-Code-Audit-Skill4021 repos~779Automated safety check: PassNone
Detecting SQL Injection Patternsjeremylongshore/tons-of-skills-marketplace2.8k—~1.5kAutomated safety check: PassMIT
Secknowledge SkillPa55w0rd/secknowledge-skill425—~2.7kAutomated safety check: PassNone
Query Builderthalysjuvenal/advpl-specialist186—~594Automated safety check: PassMIT
Frappe Syntax Query BuilderImpertio-Studio/Frappe_Claude_Skill_Package189—~1.7kAutomated safety check: PassMIT

Similar skills

  • Php Thinkphp Audit

    0xShe/PHP-Code-Audit-Skill

    ThinkPHP 框架特效安全审计工具。针对 ThinkPHP 常见的鉴权/CSRF/模板转义/ORM 写入(Mass Assignment)/调试与配置暴露等机制进行白盒静态审计,并映射到通用漏洞类型体系(AUTH/CSRF/TPL/XSS/LOGIC/CFG/SESS/SQL 等)。

    402 GitHub starsUsed in 1 repo~779 tokens
    SecurityAuto-check passed
  • Detecting SQL Injection Patterns

    jeremylongshore/tons-of-skills-marketplace

    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…

    2.8k GitHub stars~1.5k tokensUpdated yesterday
    SecurityAuto-check passed
  • Secknowledge Skill

    Pa55w0rd/secknowledge-skill

    Web+AI 安全测试知识库。融合 WooYun 88,636 案例 + 先知 L1-L4 方法论 + GAARM 173 风险 + OWASP Top 10 (LLM/ASI/WSTG)。

    425 GitHub stars~2.7k tokensUpdated 3 mo ago
    SecurityAuto-check passed
  • Query Builder

    thalysjuvenal/advpl-specialist

    A skill your agent uses when the user needs to build, choose the pattern for, or optimize a SQL query against Protheus ERP tables -- covering Workarea (DbSelectArea/DbSeek) vs Embedded SQL vs…

    186 GitHub stars~594 tokensUpdated 26 days ago
    DatabasesAuto-check passed
  • Frappe Syntax Query Builder

    Impertio-Studio/Frappe_Claude_Skill_Package

    A skill your agent uses when building database queries with frappe.qb in Frappe v14-v16.

    189 GitHub stars~1.7k tokensUpdated 23 days ago
    DatabasesAuto-check passed
  • Java Injection Audit

    wgpsec/AboutSecurity

    Java 源码注入类漏洞审计。当在 Java 白盒审计中需要检测注入类漏洞时触发. An agent skill from wgpsec/AboutSecurity.

    1.8k GitHub stars~1.1k tokensUpdated yesterday
    DatabasesAuto-check passed

More from utkusen/sast-skills

All 16 skills in this repo
  • Sast Analysis

    utkusen/sast-skills

    Perform codebase analysis and architecture mapping as the first phase of a security assessment.

    1.3k GitHub stars~1k tokensUpdated 6 mo ago
    Auto-check passed
  • Sast Graphql

    utkusen/sast-skills

    Detect GraphQL injection vulnerabilities in a codebase using a three-phase approach: recon (confirm GraphQL usage and find unsafe operation document assembly sites), batched verify (trace user input…

    1.3k GitHub stars~4.7k tokensUpdated 6 mo ago
    Auto-check passed
  • Sast Idor

    utkusen/sast-skills

    Detect Insecure Direct Object Reference (IDOR) vulnerabilities in a codebase using a three-phase approach: recon (find candidates), batched verify (check authorization in parallel subagents, 3…

    1.3k GitHub stars~4.9k tokensUpdated 6 mo ago
    Auto-check passed
  • Sast Report

    utkusen/sast-skills

    Consolidate all SAST vulnerability results from the sast/ folder into a single final report ranked by severity and confidentiality impact.

    1.3k GitHub stars~1.7k tokensUpdated 6 mo ago
    Auto-check passed
  • Sast Businesslogic

    utkusen/sast-skills

    Detect business logic vulnerabilities in a codebase using a three-phase approach: threat modeling (domain analysis and attack scenarios), batched verify (check exploitable gaps in parallel…

    1.3k GitHub stars~5.3k tokensUpdated 6 mo ago
    Auto-check passed
  • Sast Fileupload

    utkusen/sast-skills

    Detect insecure file upload vulnerabilities in a codebase using a three-phase approach: discovery (find all upload sites), batched verify (check extension bypass and related issues in parallel…

    1.3k GitHub stars~7.3k tokensUpdated 6 mo ago
    Auto-check passed

Works with

Questions about Sast Sqli

What does Sast Sqli do?

Detect SQL injection vulnerabilities in a codebase using a three-phase approach: recon (find unsafe SQL construction sites), batched verify (trace user input to those sites in parallel subagents, 3…. Sast Sqli is an agent skill from utkusen/sast-skills. Detect SQL injection vulnerabilities in a codebase using a three-phase approach: recon (find unsafe SQL construction sites), batched verify (trace user input to those sites in parallel subagents, 3 sites each), and merge (consolidate batch results).

When should I use Sast Sqli?

Sast Sqli fits situations like: asked to find SQLi; database injection bugs.

How do I install Sast Sqli in Claude Code?

Run `npx skills add utkusen/sast-skills --skill sast-sqli -a claude-code`. Or copy the skill folder (sast-files/.agents/skills/sast-sqli in utkusen/sast-skills) into .claude/skills/sast-sqli in your project. Claude Code loads it when a task matches its description.

How do I install Sast Sqli in Codex?

Run `npx skills add utkusen/sast-skills --skill sast-sqli -a codex`. Or copy the skill folder (sast-files/.agents/skills/sast-sqli in utkusen/sast-skills) into .agents/skills/sast-sqli in your project. Codex loads it when a task matches its description.

Can I use Sast Sqli in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add utkusen/sast-skills --skill sast-sqli -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/sast-sqli, .gemini/skills/sast-sqli, .github/skills/sast-sqli and .opencode/skills/sast-sqli in your project.

What does Sast Sqli need to run?

SKILL.md names no scripts, command-line tools or credentials: Sast Sqli is instructions for the agent only. Our summary lists: Python 3; Node.js.

Does Sast Sqli access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Sast Sqli safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Sast Sqli use?

Sast Sqli is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Sast Sqli use?

About 6k tokens (SKILL.md is roughly 24k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Sast Sqli?

Skills that share tags, products or a category with Sast Sqli: Php Thinkphp Audit (0xShe/PHP-Code-Audit-Skill, 402 stars), Detecting SQL Injection Patterns (jeremylongshore/tons-of-skills-marketplace, 2.8k stars), Secknowledge Skill (Pa55w0rd/secknowledge-skill, 425 stars) and Query Builder (thalysjuvenal/advpl-specialist, 186 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Sast Sqli?

utkusen (a GitHub user) maintains it in utkusen/sast-skills, which has 1,331 GitHub stars. The repository holds 16 skills in this directory. The repository was last updated on April 8, 2026.

Source: utkusen/sast-skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.