Pentest / OSINT Skill
You have real Bash, real filesystem, real process execution, and a fleet of pentest tools one wrapper call away. Use the wrappers — manual curl loops are a fallback, not a default.
Step 0 — Preflight (run first, every session)
python ${CLAUDE_PLUGIN_ROOT}/scripts/ht_preflight.py
Read the verdict and act:
ready → state the backend in one sentence (e.g. "Running native on macOS" / "Running via Docker on Windows" / "Running native in WSL Ubuntu") and start work.
partial → tell the user what's missing (use recommendations); offer to proceed with reduced coverage.
blocked → stop. Surface the recommendations and wait. Do not substitute manual curl / Invoke-WebRequest probes for a missing tool — that misleads the user about coverage.
Re-run preflight if the user installs something, starts Docker, or switches into WSL.
Tool-first defaults
When the ask is "audit / scan / find vulns", reach for:
| Ask |
Default chain |
| Subdomain enumeration |
subfinder -all → httpx -title -tech-detect |
| Web vuln scan |
nuclei -severity medium,high,critical |
| Port scan |
nmap -sV -sC (or naabu for fast SYN sweep) |
| Directory / API discovery |
ffuf -w wordlist -u https://target/FUZZ |
| Secret hunting |
trufflehog filesystem . or gitleaks detect |
| Username / email investigation |
holehe → sherlock → maigret |
| TLS audit |
nuclei -tags ssl,tls |
| Domain OSINT |
amass intel → theharvester |
Anti-patterns: for-looping curl across many paths instead of ffuf / nuclei; hand-parsing TLS output instead of nuclei -tags ssl; saying "I don't have nuclei" when preflight returned ready (you have it via Docker).
The execution model
Every tool runs through ht_run.py, which:
- Reads
ht_env.py to pick a backend — native on Linux/macOS, WSL on Windows with a real distro, Docker anywhere with Docker Desktop.
- Looks up a purpose-built Docker image for the tool if one exists (
instrumentisto/nmap, projectdiscovery/nuclei, caffix/amass, 20+ more). Falls back to kalilinux/kali-rolling.
- Executes the command. Auto-retries with
sudo -n on permission-denied (native/WSL).
- Returns JSON:
status, stdout, stderr, returncode, command.
Only one pre-block: tools flagged interactive. Bypass with --force + --command if you have non-interactive args.
Bundled scripts
All at ${CLAUDE_PLUGIN_ROOT}/scripts/. Emit JSON.
| Script |
Purpose |
ht_preflight.py |
Run first. Capability check + setup recommendations. |
ht_search.py |
Query the tool index (--q, --category, --tag, --capability, --os). |
ht_env.py |
Low-level env detect. (Preflight wraps this.) |
ht_run.py |
Execute. --command "..." to override, --args "..." to append, --network-host for LAN, --privileged for raw sockets, --force to bypass the interactive block. |
Golden path
- Preflight — handle verdict per Step 0.
- Read the ask — map to a workflow (
reference/workflows.md) and apply the defaults table.
- Find tool ids —
ht_search.py --q "<keyword>". Don't guess; ids are namespaced (e.g. web_attack.Nuclei).
- Execute —
ht_run.py <tool_id> --args "...", or --command "<full>" for tools where runnable=False. Add --network-host for LAN, --privileged for raw sockets.
- Parse status:
ok → summarize highlights; error → report stderr, decide whether to retry; fallback → see reference/runtime-fallbacks.md; timeout → raise --timeout or chunk the scan.
- Compose —
subfinder → httpx → nuclei, holehe → sherlock → maigret. Feed outputs forward.
Docker image overrides
ht_run.py maps common tools to purpose-built images (faster pulls, proper ENTRYPOINTs):
| Tool |
Image |
| NMAP |
instrumentisto/nmap |
| Nuclei |
projectdiscovery/nuclei |
| Subfinder / Httpx / Katana |
projectdiscovery/* |
| Amass |
caffix/amass |
| TheHarvester |
secsi/theharvester |
| Holehe / Maigret / SpiderFoot |
official images |
| TruffleHog / Gitleaks |
official images |
| Sqlmap |
paoloo/sqlmap |
| Impacket / NetExec |
rflathers/impacket, byt3bl33d3r/netexec |
Override with --docker-image my/image for one-offs.
Ad-hoc commands
Bash directly is fine for spot-checks: a single curl -I, arp -a, dig @8.8.8.8 example.com. Reach for ht_run.py whenever:
- The tool is in the index and you want auto image/backend selection.
- You're chaining multiple tools and want uniform JSON output.
- The task is enumeration / scanning / fuzzing at any scale (≥5 requests against a target).
If you're about to write a for loop hitting many paths with curl, stop — use ffuf / nuclei / gobuster instead.
References
${CLAUDE_PLUGIN_ROOT}/skills/pentest/reference/workflows.md — named playbooks
${CLAUDE_PLUGIN_ROOT}/skills/pentest/reference/runtime-fallbacks.md — templates per fallback reason
1---2name: pentest3description: Security testing and OSINT toolkit wrapping 183+ tools from Z4nzu/hackingtool (nmap, sherlock, amass, subfinder, nuclei, httpx, holehe, maigret, trufflehog, sqlmap, impacket, netexec, and more). Use whenever the user asks to recon a target, scan a network, enumerate subdomains, investigate a username or email, test a web app, check for leaked secrets, or any other pentest / OSINT task. Runs locally on any OS via native Bash, WSL, or purpose-built Docker images — the skill picks the right backend automatically.4---56# Pentest / OSINT Skill78You have real Bash, real filesystem, real process execution, and a fleet of pentest tools one wrapper call away. **Use the wrappers — manual `curl` loops are a fallback, not a default.**910## Step 0 — Preflight (run first, every session)1112```bash13python ${CLAUDE_PLUGIN_ROOT}/scripts/ht_preflight.py14```1516Read the `verdict` and act:1718- **`ready`** → state the backend in one sentence (e.g. "Running native on macOS" / "Running via Docker on Windows" / "Running native in WSL Ubuntu") and start work.19- **`partial`** → tell the user what's missing (use `recommendations`); offer to proceed with reduced coverage.20- **`blocked`** → stop. Surface the recommendations and wait. **Do not** substitute manual `curl` / `Invoke-WebRequest` probes for a missing tool — that misleads the user about coverage.2122Re-run preflight if the user installs something, starts Docker, or switches into WSL.2324## Tool-first defaults2526When the ask is "audit / scan / find vulns", reach for:2728| Ask | Default chain |29|-----|---------------|30| Subdomain enumeration | `subfinder -all` → `httpx -title -tech-detect` |31| Web vuln scan | `nuclei -severity medium,high,critical` |32| Port scan | `nmap -sV -sC` (or `naabu` for fast SYN sweep) |33| Directory / API discovery | `ffuf -w wordlist -u https://target/FUZZ` |34| Secret hunting | `trufflehog filesystem .` or `gitleaks detect` |35| Username / email investigation | `holehe` → `sherlock` → `maigret` |36| TLS audit | `nuclei -tags ssl,tls` |37| Domain OSINT | `amass intel` → `theharvester` |3839Anti-patterns: `for`-looping curl across many paths instead of `ffuf` / `nuclei`; hand-parsing TLS output instead of `nuclei -tags ssl`; saying "I don't have nuclei" when preflight returned `ready` (you have it via Docker).4041## The execution model4243Every tool runs through `ht_run.py`, which:44451. Reads `ht_env.py` to pick a backend — **native** on Linux/macOS, **WSL** on Windows with a real distro, **Docker** anywhere with Docker Desktop.462. Looks up a purpose-built Docker image for the tool if one exists (`instrumentisto/nmap`, `projectdiscovery/nuclei`, `caffix/amass`, 20+ more). Falls back to `kalilinux/kali-rolling`.473. Executes the command. Auto-retries with `sudo -n` on permission-denied (native/WSL).484. Returns JSON: `status`, `stdout`, `stderr`, `returncode`, `command`.4950Only one pre-block: tools flagged `interactive`. Bypass with `--force` + `--command` if you have non-interactive args.5152## Bundled scripts5354All at `${CLAUDE_PLUGIN_ROOT}/scripts/`. Emit JSON.5556| Script | Purpose |57|---|---|58| `ht_preflight.py` | **Run first.** Capability check + setup recommendations. |59| `ht_search.py` | Query the tool index (`--q`, `--category`, `--tag`, `--capability`, `--os`). |60| `ht_env.py` | Low-level env detect. (Preflight wraps this.) |61| `ht_run.py` | Execute. `--command "..."` to override, `--args "..."` to append, `--network-host` for LAN, `--privileged` for raw sockets, `--force` to bypass the interactive block. |6263## Golden path64651. **Preflight** — handle verdict per Step 0.662. **Read the ask** — map to a workflow (`reference/workflows.md`) and apply the defaults table.673. **Find tool ids** — `ht_search.py --q "<keyword>"`. Don't guess; ids are namespaced (e.g. `web_attack.Nuclei`).684. **Execute** — `ht_run.py <tool_id> --args "..."`, or `--command "<full>"` for tools where `runnable=False`. Add `--network-host` for LAN, `--privileged` for raw sockets.695. **Parse status:** `ok` → summarize highlights; `error` → report stderr, decide whether to retry; `fallback` → see `reference/runtime-fallbacks.md`; `timeout` → raise `--timeout` or chunk the scan.706. **Compose** — `subfinder → httpx → nuclei`, `holehe → sherlock → maigret`. Feed outputs forward.7172## Docker image overrides7374`ht_run.py` maps common tools to purpose-built images (faster pulls, proper ENTRYPOINTs):7576| Tool | Image |77|---|---|78| NMAP | `instrumentisto/nmap` |79| Nuclei | `projectdiscovery/nuclei` |80| Subfinder / Httpx / Katana | `projectdiscovery/*` |81| Amass | `caffix/amass` |82| TheHarvester | `secsi/theharvester` |83| Holehe / Maigret / SpiderFoot | official images |84| TruffleHog / Gitleaks | official images |85| Sqlmap | `paoloo/sqlmap` |86| Impacket / NetExec | `rflathers/impacket`, `byt3bl33d3r/netexec` |8788Override with `--docker-image my/image` for one-offs.8990## Ad-hoc commands9192Bash directly is fine for spot-checks: a single `curl -I`, `arp -a`, `dig @8.8.8.8 example.com`. Reach for `ht_run.py` whenever:9394- The tool is in the index and you want auto image/backend selection.95- You're chaining multiple tools and want uniform JSON output.96- The task is enumeration / scanning / fuzzing at any scale (**≥5 requests against a target**).9798If you're about to write a `for` loop hitting many paths with `curl`, **stop — use `ffuf` / `nuclei` / `gobuster` instead.**99100## References101102- `${CLAUDE_PLUGIN_ROOT}/skills/pentest/reference/workflows.md` — named playbooks103- `${CLAUDE_PLUGIN_ROOT}/skills/pentest/reference/runtime-fallbacks.md` — templates per fallback reason