exploit-hunt
Overview
The offensive counterpart to eskills:security-bar. security-bar asks "is this built
right?"; this asks "can an attacker actually reach a sink?". Use it for a deeper, on-demand
pass on a codebase — not as a per-task lens. It is not in the default eskills:task-flow
quality stage; reach for it when a change touches a real boundary, or when auditing an app
end-to-end.
The principle
Unreachable is not a finding. A theoretically-unsafe call that no external input can
reach is a note, not a vulnerability. Prove that user-controlled input travels from a real
boundary to a meaningful sink — or drop it. Bias hard toward remotely reachable, user-driven
paths; throw away the rest.
In scope — prove user control reaches the sink
| Pattern |
CWE |
Impact |
| SSRF via user-controlled URL |
918 |
internal network, cloud metadata theft |
| Auth bypass in middleware / API guards |
287 |
unauthorized account or data access |
| Remote deserialization / upload→RCE |
502 |
code execution |
| SQL injection in a reachable endpoint |
89 |
exfiltration, auth bypass, data loss |
| Command injection in a request handler |
78 |
code execution |
| Path traversal in file-serving paths |
22 |
arbitrary file read/write |
| Auto-triggered XSS |
79 |
session/admin compromise |
| Open RLS / PostgREST direct write reachable with the anon key |
284/639 |
read/overwrite any row, bypassing the app |
Skip these — low signal, drop them
- Local-only
pickle.loads / torch.load / equivalent with no remote path
eval() / exec() in CLI-only tooling
shell=True on a fully hardcoded command
- Missing security headers on their own
- Generic rate-limiting complaints with no exploit impact
- Self-XSS that needs the victim to paste code manually
- Demo, example, fixture, vendored, or test-only code
My stack: where the real boundary is
The React/PWA UI is not the boundary. My apps ship the Supabase anon key, so the real
attack surface is PostgREST + Edge Functions / RPCs — anything reachable with that key is
a public API, regardless of what the UI exposes. So:
- Treat every table reachable via the anon key as a public, unauthenticated endpoint. A guard
that lives only in front-end code does not exist for an attacker (see
eskills:security-bar
for the RLS / server-side-PIN rules this feeds).
- The sinks that matter are server-side: an RPC that builds dynamic SQL, an Edge Function that
fetches a user-supplied URL (SSRF) or shells out, a storage path built from user input.
Workflow
- Map entrypoints — HTTP handlers, RPCs, Edge Functions, upload paths, webhooks,
background jobs, parsers, any table exposed through PostgREST.
- Trace reachability — follow user-controlled input from the boundary inward.
- Find the sink — does that input reach SQL, a shell, a URL fetch, a deserializer, a
file path, the DOM?
- Prove it — confirm user control reaches the sink with the smallest safe PoC (a single
request or
curl against PostgREST is usually enough).
- Triage tooling as input only —
semgrep --config=auto --severity=ERROR --severity=WARNING
to seed candidates, then manually drop the unreachable / test / vendored hits.
Output
Per finding: file:line → reachability (which boundary, which input) → what the attacker achieves → the fix, plus the minimal PoC. State the boundary explicitly — if you can't name
how it's reached, it goes in a separate "theoretical / needs-confirmation" list, not the
findings. Don't re-report an already-accepted, documented risk.
1---2name: exploit-hunt3description: Use when hunting for actually-exploitable vulnerabilities — reachable, user-controlled paths into a real sink (SSRF, SQLi, command injection, RCE, deserialization, path traversal, XSS), discarding theoretical or local-only noise. Offensive triage, the counterpart to security-bar's defensive checklist.4---56# exploit-hunt78## Overview910The offensive counterpart to `eskills:security-bar`. security-bar asks _"is this built11right?"_; this asks _"can an attacker actually reach a sink?"_. Use it for a deeper, on-demand12pass on a codebase — not as a per-task lens. It is **not** in the default `eskills:task-flow`13quality stage; reach for it when a change touches a real boundary, or when auditing an app14end-to-end.1516## The principle1718**Unreachable is not a finding.** A theoretically-unsafe call that no external input can19reach is a note, not a vulnerability. Prove that user-controlled input travels from a real20boundary to a meaningful sink — or drop it. Bias hard toward remotely reachable, user-driven21paths; throw away the rest.2223## In scope — prove user control reaches the sink2425| Pattern | CWE | Impact |26| ------------------------------------------------------------- | ------- | ----------------------------------------- |27| SSRF via user-controlled URL | 918 | internal network, cloud metadata theft |28| Auth bypass in middleware / API guards | 287 | unauthorized account or data access |29| Remote deserialization / upload→RCE | 502 | code execution |30| SQL injection in a reachable endpoint | 89 | exfiltration, auth bypass, data loss |31| Command injection in a request handler | 78 | code execution |32| Path traversal in file-serving paths | 22 | arbitrary file read/write |33| Auto-triggered XSS | 79 | session/admin compromise |34| Open RLS / PostgREST direct write reachable with the anon key | 284/639 | read/overwrite any row, bypassing the app |3536## Skip these — low signal, drop them3738- Local-only `pickle.loads` / `torch.load` / equivalent with no remote path39- `eval()` / `exec()` in CLI-only tooling40- `shell=True` on a fully hardcoded command41- Missing security headers on their own42- Generic rate-limiting complaints with no exploit impact43- Self-XSS that needs the victim to paste code manually44- Demo, example, fixture, vendored, or test-only code4546## My stack: where the real boundary is4748The React/PWA UI is **not** the boundary. My apps ship the Supabase anon key, so the real49attack surface is **PostgREST + Edge Functions / RPCs** — anything reachable with that key is50a public API, regardless of what the UI exposes. So:5152- Treat every table reachable via the anon key as a public, unauthenticated endpoint. A guard53 that lives only in front-end code does not exist for an attacker (see `eskills:security-bar`54 for the RLS / server-side-PIN rules this feeds).55- The sinks that matter are server-side: an RPC that builds dynamic SQL, an Edge Function that56 fetches a user-supplied URL (SSRF) or shells out, a storage path built from user input.5758## Workflow59601. **Map entrypoints** — HTTP handlers, RPCs, Edge Functions, upload paths, webhooks,61 background jobs, parsers, any table exposed through PostgREST.622. **Trace reachability** — follow user-controlled input from the boundary inward.633. **Find the sink** — does that input reach SQL, a shell, a URL fetch, a deserializer, a64 file path, the DOM?654. **Prove it** — confirm user control reaches the sink with the smallest safe PoC (a single66 request or `curl` against PostgREST is usually enough).675. **Triage tooling as input only** — `semgrep --config=auto --severity=ERROR --severity=WARNING`68 to seed candidates, then manually drop the unreachable / test / vendored hits.6970## Output7172Per finding: `file:line → reachability (which boundary, which input) → what the attacker73achieves → the fix`, plus the minimal PoC. State the boundary explicitly — if you can't name74how it's reached, it goes in a separate "theoretical / needs-confirmation" list, not the75findings. Don't re-report an already-accepted, documented risk.