Skip to content
Security
Skill

/sast-sqli

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,

From plugin
sast-skills
1.4k16 skills

Claude Code

$ npx -y skills add utkusen/sast-skills --skill sast-sqli --agent claude-code

SKILL.md

sast-sqli.SKILL.md
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)

# 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

# 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

# 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

// 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
Read more
@utkusen
Ships withsast-skills

A collection of agent skills that turn your LLM coding assistant into a fully functional SAST scanner to find vulnerabilities in your codebase. Works natively with Claude Code, Codex, Opencode, Cursor and any other assistant that supports agent skills.

Stars on GitHub

Momentum

stars in total
1.4k
Star history of utkusen/sast-skills on GitHub, a chart by star-history.com

Other skills on sast-skills.

sast-analysis

sast-analysis

Perform codebase analysis and architecture mapping as the first phase of a security assessment. Explores the tech stack,…

@utkusen@utkusenInstall Skill
sast-businesslogic

sast-businesslogic

Detect business logic vulnerabilities in a codebase using a three-phase approach: threat modeling (domain analysis and attack…

@utkusen@utkusenInstall Skill
sast-fileupload

sast-fileupload

Detect insecure file upload vulnerabilities in a codebase using a three-phase approach: discovery (find all upload sites),…

@utkusen@utkusenInstall Skill
sast-graphql

sast-graphql

Detect GraphQL injection vulnerabilities in a codebase using a three-phase approach: recon (confirm GraphQL usage and find unsafe…

@utkusen@utkusenInstall Skill
sast-hardcodedsecrets

sast-hardcodedsecrets

Detect hardcoded sensitive data (API keys, access tokens, private keys, passwords, etc.) in publicly accessible code — frontend…

@utkusen@utkusenInstall Skill
sast-idor

sast-idor

Detect Insecure Direct Object Reference (IDOR) vulnerabilities in a codebase using a three-phase approach: recon (find…

@utkusen@utkusenInstall Skill

More skills from other plugins.

api-security

api-security

Use for authorized security assessment of REST, GraphQL, WebSocket, or SOAP APIs, including discovery, authentication,…

@zhaoxuya520@zhaoxuya520Install Skill
nemoclaw-user-guide

nemoclaw-user-guide

Find official NemoClaw documentation for installation, configuration, operation, or troubleshooting. Also handles requested docs…

@nvidia@nvidiaInstall Skill

Questions about sast-sqli.

Which coding agents can use sast-sqli?
sast-sqli installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.