Systematic, authorized web-application penetration testing with Claude Code — the LLM-plus-discipline pair, not the LLM alone.
What & Why · Philosophy · Measurement · Quickstart · Companion Tooling · Methodology · Layout · Safety
⚠️ Authorized testing only. Fiach is for assessments you are explicitly permitted to perform. Scope is declared per engagement inscope.yaml; the framework refuses to act outside it, and exploitation is non-destructive by default.
An LLM pointed at a target generates — plausible payloads, plausible conclusions. What it lacks on its own is coverage (it declares "not vulnerable" too early) and falsification (it believes a payload reached a sink without proving impact). Left alone, that produces confident false negatives and unverified findings.
Fiach (Irish: the hunt) is the discipline layer that fixes it. Claude generates hypotheses and mutates payloads; the framework's gates, evidence levels, base-rate sweeps, and catalog skills supply the coverage and proof an LLM can't self-impose. It pairs with lorg (Irish: to track / trace) — lorg is the intercepting proxy that traces the traffic; Fiach is the disciplined hunter that reasons over it.
Three pillars:
- Attacker-mindset methodology — detection is not a finding; every vulnerability is escalated to maximum demonstrated impact; client-side issues are proven in a real browser.
- Persistence mechanics — exhaustion gates block premature "not vulnerable"; staged evidence levels (0–4); hook-enforced testing thresholds.
- Progressive-loading skills — per-phase and per-vuln-class skills load just-in-time to keep context focused.
All engagement data lives under Projects/<engagement-id>/ (gitignored). The framework repo stays clean across engagements.
Detection is not a finding. Every vulnerability is escalated to maximum demonstrated impact, or it isn't done.
{{7*7}}→49 is a lead, not a result — SSTI is done when it's RCE; a '-error is done when it's data extraction; a reflected payload is done when alert() fires in a real browser. The framework encodes that so the model can't stop at "looks vulnerable."
A premature "not vulnerable" is a false negative delivered with false confidence.
So persistence is enforced, not requested: Claude cannot close an endpoint-class without meeting a per-class minimum of payloads and bypass variants. The gates are the falsification discipline an eager model skips on its own.
What is enforced (hook-verified): findings can't claim a level they haven't earned — finding-validator demands a Level-3+ PoC (verified in Serval), exhaustion gates block early abandonment, and the severity rubric is calibrated, not vibed. The mechanism holds the model to the standard.
What is measured: real-world efficacy is an engagement-by-engagement result, not a blanket claim — ctf-mode runs the pipeline against single-target benchmarks (e.g. XBOW) for a repeatable score. And confirmed (Level 3/4) findings optionally emit an ISE ledger closure (hooks/ise-closure.mjs) so momento's aggregate_ledger can read what-worked across engagements. Treat any "it finds more" claim as a hypothesis until a benchmark cites a number.
Requires Claude Code CLI, Go (to build lorg), Node 18+, Python 3, plus a lorg checkout (LORG_SRC) and Serval + Seeker registered as user-level MCP servers.
git clone https://github.com/campbellcharlie/fiach.git ~/src/fiach && cd ~/src/fiach
./install.sh # idempotent: builds lorg from $LORG_SRC, installs ffuf/grpcurl + hooks
# ./install.sh --with-sast # white-box mode (adds semgrep + checkov)
# start lorg (proxy + MCP); ensure Serval + Seeker user-level MCP servers are up, then:
claude # launch Claude Code from the framework root
/pentest ACME-001 # create the engagement (Projects/ACME-001/ from the scope template)
# vim Projects/ACME-001/scope.yaml ← declare authorized scope
/pentest ACME-001 # run the pipeline · `status` / `resume` to check in · `/pentest` lists allSlash commands: pentest (orchestrator), pentest-autonomous (driver mode), pentest-switch (switch active engagement).
Fiach orchestrates a small set of MCP tools — data flow is Seeker → Serval → lorg. They are separate companion tools, not bundled: supply your own lorg checkout and register Serval/Seeker as user-level MCP servers.
| Tool | Role | Provided by |
|---|---|---|
| lorg | Intercepting proxy + traffic DB + ~60 MCP tools (tampering, smuggling, race conditions, JWT, GraphQL, scope enforcement, blind-callback OOB) | built by install.sh from a lorg checkout |
| Serval | WebKit-native (Safari TLS) browser MCP — auth flows, XSS/DOM verification, cross-session authz, anti-bot targets | registered at the Claude Code user level |
| Seeker | Asset discovery / recon ingestion | registered at the Claude Code user level |
| discovery, gemini | Project-scoped helper MCP servers under libs/ |
this repo |
Phase 0 Pre-flight — verify lorg/Serval, configure scope, sessions, optional SAST pre-scan
Phase 1 Recon — Serval wide browse + ffuf discovery + JS mining → surface map → lorg anomaly sweep
Phase 2 Vuln analysis — breadth sweep (sub-agents, one confirm-or-clear per input × class) before depth
Phase 3 Exploitation — mandatory escalation chains to maximum impact
Phase 4 Chaining — combine findings for compound impact
Phase 5 Reporting — executive summary, severity, remediation
| Evidence level | Meaning |
|---|---|
| 0 · Not Tested | Endpoint not examined for this class |
| 1 · Not Vulnerable | Exhaustion gate met, nothing found |
| 2 · Potential | Payload reached a sink; defense blocked — bypass needed (not a resting state) |
| 3 · Exploited | Confirmed, reproducible PoC |
| 4 · Critical | Real-world impact demonstrated in Serval (data exfil, privesc, RCE) |
Persistence — exhaustion gates (selected; full table in methodology/persistence.md)
Claude cannot declare "not vulnerable" without meeting per-class minimums:
| Class | Min payloads | Min bypass attempts |
|---|---|---|
| SQLi | 10 | 8 encoding/syntax variants |
| XSS (reflected) | 10 | 8 context/encoding variants |
| Command injection | 8 | 5 shell/encoding variants |
| SSRF | 8 | 5 protocol/redirect variants |
| SSTI | 8 | 5 engine-specific variants |
| IDOR | 5 | 3 param-manipulation patterns |
Escalation pushes every confirmed vuln to maximum demonstrated impact (detection alone is insufficient): SSTI → RCE, SQLi → auth bypass / extraction, XSS → alert() in a real browser, SSRF → internal service / metadata. Full chains per class in methodology/escalation-paths.md.
fiach/
CLAUDE.md # core doctrine — posture, tool routing, evidence levels
install.sh # dependency installer / lorg build
.mcp.json # project-scoped MCP servers (lorg, discovery, gemini)
.claude/
commands/ # /pentest · /pentest-autonomous · /pentest-switch
skills/ # phase 0–5, exploit-dev-web, payload-gen, verification, …
engagement-skills/ # per-vuln-class progressive-loading skills
methodology/ # phase flow, persona gates, severity calibration, persistence
hooks/ # scope enforcement, gates, lead manager, rate limiting (+ ise-closure.mjs)
templates/ # engagement / submission templates
libs/ # project MCP servers (discovery, gemini)
config/ # schemas, model routing, OOB config example
Projects/ # all engagement data (gitignored)
- Authorized, scoped testing only — per-project
scope.yaml, enforced at the proxy and via hooks. - Non-destructive — no
DROP/DELETE/TRUNCATE, no DoS, no state-modifying exploitation without explicit secondary approval. - Rate limits and exclusions honored; read-only exploitation (SQLi
SELECTonly; RCE limited toid/whoami/cat/ls). - Ambiguous scope → the framework stops and asks rather than guessing.
MIT © 2026 Charlie Campbell