---
name: pentest
description: "Runs authorised dynamic security testing of the project's OWN application (dev/staging or approved prod) — ZAP baseline/API scan, Nuclei, Schemathesis fuzzing, testssl.sh, nmap, manual auth/IDOR/GraphQL checks — with CVSS-scored findings in docs/security/pentest-<date>.md; scope is confirmed first. Use before a public launch or after /harden, for 'pentest staging', 'scan the API'."
argument-hint: "[target-url] [--scope dev|staging|prod] [--quick]"
user-invocable: true
allowed-tools: Read, Glob, Grep, Bash, Write, Task, AskUserQuestion
---

# Pentest (the project's own application)

Reply in the project conversation language (CLAUDE.md → Language); code, identifiers, paths and commit messages stay in English.

Templates `templates/pentest-report.md`, `findings.md`; reference `stack-reference/security-standards.md`. In the commands below, `<hooks>` is `.claude/hooks/` in copy mode and `${CLAUDE_PLUGIN_ROOT}/hooks/` in plugin mode. **The scope is fixed before the first request**: only the project's own hosts/domains from technical-preferences/deployment docs; production only with an explicit "yes" and in an agreed window. Targets outside the project are refused.

## Phase 1: Scope and confirmation
`AskUserQuestion`: target (URL), environment, window, accounts for authenticated checks, exclusions (payments, e-mails). Record the scope as the report's first section.

## Phase 2: Tools (whatever is installed; otherwise docker images with consent)
ZAP baseline → full/API scan (OpenAPI or GraphQL introspection on dev); Nuclei (web/misconfig templates); Schemathesis on OpenAPI / GraphQL fuzzing; `testssl.sh`; `nmap -sV` on the project's own host; manual checks: IDOR (two accounts), GraphQL field permissions, depth/batching limits, login rate limit, password reset, uploads, CSRF/CORS, headers.
`--quick` — ZAP baseline + headers + testssl only.
**Playwright MCP (optional).** When the Playwright MCP tools are available (`mcp__plugin_web-studio_playwright__*`; copy mode with a user-added server: `mcp__playwright__*`), drive the confirmed in-scope target through them for the manual checks — `browser_navigate` to the login, reset and upload pages, `browser_snapshot` for the rendered state (CSRF tokens, error texts, IDOR views under two accounts), `browser_console_messages` and `browser_network_requests` for leaked errors and third-party calls — and quote the tool output as the finding's evidence. The scope of Phase 1 binds the MCP session too: no navigation outside the confirmed hosts. Without the tools, the CLI path above is the test; nothing depends on the MCP.

## Phase 3: Findings
Severity/CVSS, steps, evidence (no secrets), fix (code/config), verification after the fix; "clean" areas listed.

## Phase 4: Write
1. Show the report in the chat, then "May I write `docs/security/pentest-<date>.md`?" — one `AskUserQuestion`: write (Recommended) · show the draft/diff first · not now. After the "write" answer: `touch .claude/.write-consent` (rule 7 — the consent-guard hook checks the marker).
2. For every Critical and High finding (and every Medium that needs a decision), one `AskUserQuestion`: record it in `production/findings.md` (template `findings.md`; id `SEC-NNN`, severity, area/feature, the decision needed, source column pointing at the pentest report) (Recommended) · story stubs now via `/create-stories` · report only. The "record" answer is the "May I write `production/findings.md`?" consent: `touch .claude/.write-consent` after it, then write the row. `/create-stories`, `/sprint-plan` and `/help` read `production/findings.md`, so a finding left only in the report never reaches planning. Record the gate before asking — `<hooks>session-state.sh set Gate "/pentest Phase 4: record SEC-NNN?"` — and clear it after the answer (`<hooks>session-state.sh set Gate "—"`).
3. A Critical or High finding that is neither recorded nor turned into a story is named as such in the verdict line.

## Phase 5: Commit (documents lane)
Right after the write (and the findings rows, when any were recorded), one commit gate (rule 7 (4), `.claude/docs/git-workflow.md` § Documents): `docs: pentest <date>`, staging exactly the written files — `docs/security/pentest-<date>.md`, `production/findings.md` when rows were added and `.claude/agent-memory/` when the run changed it (git-workflow § Agent memory). Record the gate before asking — `<hooks>session-state.sh set Gate "/pentest Phase 5: commit?"` — and clear it after the answer (`<hooks>session-state.sh set Gate "—"`).
- On the default branch when no story work is in progress: one `AskUserQuestion` — commit (Recommended) · leave uncommitted.
- When HEAD is a story branch, name it and ask one `AskUserQuestion`: switch to the default branch and commit there (Recommended — a pipeline-wide document) · commit here (the document belongs to this story) · leave uncommitted.
- Scan configs or scripts created for the run (a ZAP context, a Schemathesis hook, a compose fragment for the scanner images) are not documents: they never ride the `docs:` commit — name them and offer the chore lane (git-workflow.md § Chore / infra).

Nothing is committed without the answer.

Verdict: `PASS` | `FINDINGS (C/H/M/L)`. Next step — one `AskUserQuestion`: fixes, then `/pentest --quick` again (Recommended) · `/harden` · report only.
