A single orchestrator (HuntBrain) delegates to specialist agents β Recon, Scan, Exploit, Chain-Planner, Report, plus unlimited dynamic specialists spawned on demand β that drive real security tools through MCP, validate their own findings before calling anything "confirmed," and write back what they learn after every engagement.
New to bug bounty? Skip to Quick Start and run one command against a legal test target. Here for the architecture? Jump to Architecture for the full agent/data-flow diagram.
Important
For authorized security testing only. Every engagement is bound to an engagement.yaml
scope file β read Scope & Authorization before pointing this at anything.
Most agentic pentest tooling picks one of two extremes: a fixed scan-and-report pipeline with no real judgment, or a single do-everything LLM loop with no guardrails. HuntMCP sits in between, on three deliberate decisions:
|
π¬ A validator, not a self-grader Scan-agent output is always a candidate β nothing is "confirmed" until exploit-agent independently reproduces it. No hallucinated finding ever reaches a report. |
π Safety, structurally enforced Scope is validated once against |
π Gets better every engagement Confirmed findings and closed false positives both write back to a Lessons Registry β the next hunt on a similar stack starts smarter than the last one did. |
| π€ Multi-Level AI Orchestration | Level 1 HuntBrain delegates to Level 2 specialists (Recon, Scan, Exploit, Chain-Planner, Report). Not a fixed pipeline β the AI decides what to run next based on what recon actually finds. |
| π Dual Harness, Zero Lock-In | Run the exact same agent roster two ways: OpenCode (.opencode/agents/, any model provider) or native Claude Code subagents (.claude/agents/, .mcp.json). Same MCP servers, same knowledge layer, pick your harness. |
| π No Model Lock-In | model_gateway.py resolves a provider per agent role from an explicit override or an automatic fallback chain: Anthropic β OpenAI β DeepSeek β Groq β OpenRouter β local Ollama. Bring whichever API key you have. |
| π Scope-Gated by Design | Authorization is validated once per engagement against engagement.yaml, then every Tier-2 tool call runs a cheap, deterministic domain check via scripts/check-scope.sh before touching a host. No token spent re-verifying scope on every action; no way to silently drift out of scope either. |
| β‘ Reactive Rate Limiting | No blanket per-request delay. tool_resolver.run_tool() only reacts when it actually detects a block: a genuine rate limit gets one backoff-and-retry, a WAF/bot-detection block is surfaced to the agent to escalate with real bypass tooling instead of just sleeping. |
| π§ Three-Part Knowledge Layer | Writeup RAG (ChromaDB + sentence-transformers, learns from public writeups and on-demand NVD CVE lookups), Memory DB (SQLite, per-target hunt history), and a self-improving Lessons Registry β structured technique write-back after every confirmed finding and every closed false positive. |
| π Vulnerability Chaining | chainer-mcp runs a DAG-based planner across 15 chain templates (IDOR+XSSβATO, SSRF+cloudβcredential access, upload+LFIβRCEβ¦) and escalates severity when a chain lands. |
| π Authenticated Session Testing | browser-mcp seeds a real headless Chromium with cookies, Bearer tokens, or localStorage β test an SPA as a logged-in user, or diff the same page across two roles for an IDOR check. |
| π Automated IDOR/BOLA Sweeps | idor-mcp takes a URL template, a list of object IDs, and two identities' credentials, then classifies every pair (protected / leaked / ambiguous) in one pass instead of hand-crafting each curl comparison. |
| π Curated Payload Library | 11 hand-reviewed payload sets (knowledge/payloads/) and matching wordlists for when nuclei/sqlmap/dalfox's automated pass comes back clean and a human-style bypass is needed. |
| π Auto-Reporting | One file per finding (NN-<severity>-<slug>.md + a README.md index) β never one long combined report a reviewer has to scroll through. PoC, CVSS v3.1 vector, business impact, remediation. |
| π‘ Continuous Monitoring | watch-mcp diffs subdomains/endpoints over time and flags what's new. |
| π Hosted Backend (optional) | A Go + Postgres/pgvector backend (backend/) for teams that want the writeup RAG and hunt memory served centrally instead of local ChromaDB/SQLite. |
flowchart TB
HB["π§ <b>HuntBrain</b><br/><i>Level 1 β Orchestrator</i><br/>validates engagement.yaml once,<br/>delegates, merges, decides"]
subgraph L2["Level 2 β Specialists"]
direction LR
RECON["π Recon<br/>Agent"]
SCAN["π― Scan<br/>Agent"]
EXPLOIT["π₯ Exploit<br/>Agent"]
CHAIN["π Chain<br/>Planner"]
REPORT["π Report<br/>Agent"]
DYN["β‘ Dynamic<br/>Specialists"]
end
subgraph KL["Knowledge Layer"]
direction LR
RAG[("π Writeup RAG<br/>ChromaDB")]
MEM[("ποΈ Memory DB<br/>SQLite")]
LESSONS[("π Lessons<br/>Registry")]
end
HB --> RECON & SCAN & EXPLOIT & CHAIN & REPORT & DYN
RECON -.-> KL
SCAN -.-> KL
EXPLOIT -.-> KL
HB -.-> KL
classDef brain fill:#6366f1,stroke:#4338ca,color:#fff,font-weight:bold
classDef specialist fill:#8b5cf6,stroke:#6d28d9,color:#fff
classDef knowledge fill:#0ea5e9,stroke:#0369a1,color:#fff
class HB brain
class RECON,SCAN,EXPLOIT,CHAIN,REPORT,DYN specialist
class RAG,MEM,LESSONS knowledge
Dynamic specialists (GraphQL, JWT, OAuth, Cloudβ¦) spawn on demand when HuntBrain detects relevant technology β plain markdown files with locked-down tool access, not persistent processes. Both harnesses (OpenCode and Claude Code) drive the same MCP servers and knowledge layer underneath; only the orchestration layer on top differs.
Every Tier-2 tool call (anything that touches the live target) runs through the same deterministic gate, regardless of which specialist calls it:
flowchart LR
A["Tool call<br/>requested"] --> B{"check-scope.sh<br/>in engagement.yaml?"}
B -- "no" --> X["π« blocked<br/>no LLM reasoning"]
B -- "yes" --> C["run_tool()"]
C --> D{"classify_block()"}
D -- "rate limit" --> E["backoff + retry<br/>once"]
D -- "WAF / bot check" --> F["surface to agent<br/>for bypass escalation"]
D -- "clean" --> G["β
result returned"]
classDef ok fill:#22c55e,stroke:#15803d,color:#fff
classDef block fill:#ef4444,stroke:#b91c1c,color:#fff
classDef warn fill:#f59e0b,stroke:#b45309,color:#fff
class G ok
class X block
class E,F warn
See ARCHITECTURE.md for the full design, WSTG methodology mapping, and phase-by-phase build status.
1. Prerequisites
- Python 3.10+ (3.12 used in CI)
- Go tools:
subfinder,httpx,nuclei,katana,ffuf,dalfox, plusnmap - At least one model provider API key (Anthropic, OpenAI, DeepSeek, Groq, OpenRouter) β or a local Ollama install
- OpenCode v1.17+ or Claude Code β pick one harness, or install both
2. Install
git clone https://github.com/ankitsingh015/HuntMCP.git
cd HuntMCP
# Python deps β install per MCP server you plan to use, e.g.:
python3 -m venv .venv && source .venv/bin/activate
for req in mcp-servers/*/requirements.txt; do pip install -r "$req"; done
# Security tools (Go)
go install github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest
go install github.com/projectdiscovery/httpx/cmd/httpx@latest
go install github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
go install github.com/projectdiscovery/katana/cmd/katana@latest
go install github.com/ffuf/ffuf/v2@latest
go install github.com/hahwul/dalfox/v2@latest
go install github.com/projectdiscovery/interactsh/cmd/interactsh-client@latest
# nmap via your OS package manager (apt/brew/...)
# Obscura (optional) -- lighter/faster headless-browser alternative to
# browser-mcp's Playwright/Chromium, ships its own MCP server (`obscura
# mcp`). Grab a release binary from
# https://github.com/h4ckf0r0day/obscura/releases (verify its checksum)
# and put it on PATH, or: cargo install --git https://github.com/h4ckf0r0day/obscura
# Then: ./scripts/connect-obscura.sh -- personal --scope local registration,
# same reasoning as Burp below (see that section for the full "why not
# tracked config" rationale).
# Initialize local databases
./scripts/setup-db.sh3. Pick a model provider
export ANTHROPIC_API_KEY=sk-... # or OPENAI_API_KEY / DEEPSEEK_API_KEY / etc.
./scripts/select-model.sh4. Define your engagement β required before any agent touches a target
cp engagement.yaml.example engagement.yaml
$EDITOR engagement.yaml # set target, in_scope, program_url, authorized_on5. Run it
# Verify setup (OpenCode)
opencode run "HuntMCP audit testphp.vulnweb.com --quick"
# ...or verify with Claude Code
claude
> /audit testphp.vulnweb.comopencode run "HuntMCP audit example.com" # full autonomous audit
opencode run "HuntMCP audit example.com --quick" # recon + nuclei only
opencode run "HuntMCP watch example.com --interval 6h" # continuous monitoring
opencode run "HuntMCP report <scan-id>"
opencode run "HuntMCP chain <scan-id>" # vulnerability chaining analysis
opencode run "HuntMCP ingest <url> --class XSS --tech React"
opencode run "HuntMCP learn --query 'XSS in React apps'"Running multiple targets at once? source scripts/new-target-session.sh <target> in each
terminal before launching opencode gives that session its own isolated active-engagement
pointer β no target's state or narration bleeds into another's. scripts/switch-engagement.sh sessions lists a ready-to-copy command for every target you've already started.
claude
> /audit example.com # requires engagement.yaml to already match the targetHuntBrain and every Level 2 specialist are registered as native subagents
(.claude/agents/*.md) with locked-down tool allowlists β Claude Code will spawn them
automatically as the engagement progresses.
Warning
Nothing runs against a target without engagement.yaml (gitignored β this file names a real
target and stays local).
HuntBrain validates it once at the start of an engagement; every subsequent Tier-2 action
(recon/scan/exploit) then runs the cheap, deterministic scripts/check-scope.sh <host> before
touching that host β no LLM call, no per-action re-validation, no way to silently wander out of
scope either. See engagement.yaml.example for the format.
Multiple targets, one machine: scripts/switch-engagement.sh set <target> puts
engagement.yaml (and budget.json/work-registry.json/findings-seen.json) under
data/engagements/<slug>/ instead of the repo root β HuntBrain runs this automatically at
Phase 0. Pausing one target to start another is just set <other-target>; the paused target's
state sits untouched until you set back to it. For genuinely concurrent sessions across
separate terminals, see scripts/new-target-session.sh above β it isolates the active-pointer
itself, not just the on-disk state. scripts/switch-engagement.sh list shows every target with
state on disk.
flowchart TD
S1["1οΈβ£ TARGET IN<br/>parse target, validate<br/>engagement.yaml once"]
S2["2οΈβ£ LESSONS + MEMORY<br/>read_lessons() + query<br/>Memory DB for this target"]
S3["3οΈβ£ RAG QUERY<br/>what techniques work<br/>for this tech stack?"]
S4["4οΈβ£ RECON<br/>subfinder β httpx β<br/>katana β nmap"]
S5["5οΈβ£ SCAN<br/>nuclei β sqlmap β<br/>dalfox β ffuf"]
S6["6οΈβ£ VALIDATE<br/>exploit-agent independently<br/>re-runs each candidate"]
S7["7οΈβ£ CHAIN<br/>chain-planner detects<br/>exploitable combinations"]
S8["8οΈβ£ REPORT<br/>HackerOne/Bugcrowd-ready<br/>submission, one file per finding"]
S1 --> S2 --> S3 --> S4 --> S5 --> S6 --> S7 --> S8
classDef step fill:#1e1b4b,stroke:#8b5cf6,color:#e0e7ff
class S1,S2,S3,S4,S5,S6,S7,S8 step
Rate limiting and blocking are handled reactively inside tool_resolver.run_tool(), not as a
separate loop step β a detected rate limit gets one backoff-and-retry; a WAF/bot-detection
block is surfaced to the agent instead of just waiting it out.
No model fine-tuning. Retrieval-Augmented Generation instead:
| Method | Frequency | Source |
|---|---|---|
| Manual | On-demand | scripts/ingest-writeup.sh --url ... or /ingest command |
| Cron | Configurable | scripts/cron-fetch.sh β HackerOne Hacktivity, GitHub writeup repos, blogs |
| CVE lookup | On-demand, per fingerprinted product | scripts/fetch-cves.sh <keyword> or writeup-mcp's fetch_cves(keyword) tool β pulls from NVD, auto-embeds, idempotent |
Each writeup is chunked, embedded via sentence-transformers, and stored in ChromaDB. Agents
query this before testing any vulnerability class, retrieving proven techniques from similar
targets β plus whatever the Lessons Registry has learned from this project's own past
engagements.
| Level | Agent | Responsibility | Key MCP Tools |
|---|---|---|---|
| 1 | π§ HuntBrain | Orchestrator β delegates, merges, decides | memory-mcp, writeup-mcp, lessons-mcp |
| 2 | π Recon Agent | Asset discovery | subfinder-mcp, httpx-mcp, katana-mcp, nmap-mcp |
| 2 | π― Scan Agent | Vulnerability detection | nuclei-mcp, sqlmap-mcp, dalfox-mcp, ffuf-mcp |
| 2 | π₯ Exploit Agent | Validation + chaining | chainer-mcp, browser-mcp, idor-mcp, oob-mcp |
| 2 | π Chain Planner | DAG-based chain analysis | chainer-mcp, memory-mcp, writeup-mcp |
| 2 | π Report Agent | Report generation | writeup-mcp |
| 2 | β‘ Dynamic specialists | GraphQL, JWT, OAuth, Cloud, etc. | Spawned on demand, scoped per-task |
Burp Suite integration (Repeater/Collaborator validation) is an optional enhancement tier in
ARCHITECTURE.md, not a hard requirement β the built agents above run
entirely on the open-source tool chain. Out-of-band confirmation (blind SSRF/XXE/SQLi/RCE) is
already covered without Burp via oob-mcp (wraps interactsh-client).
If you do have Burp Suite, wiring it up as a live MCP integration (real proxy history, Repeater, Collaborator, Scanner issues β 27 tools total) takes one command:
# In Burp: Extensions tab > BApp Store > install "MCP Server" > start it.
./scripts/connect-burp.sh # registers the bridge, then restart your session
./scripts/connect-burp.sh --remove # undoThis is a personal --scope local MCP registration (your own ~/.claude.json), not
something the repo forces on every clone β it only works while Burp is open on your
machine with the extension running. This is separate from burp-import-mcp (always
available, no Burp needed β reads a manually-exported HTTP-history XML file).
Same pattern for Obscura (a lighter/faster
headless-browser alternative to browser-mcp's Playwright/Chromium β its own native
MCP server, ~32 tools):
./scripts/connect-obscura.sh # registers the bridge, then restart your session
./scripts/connect-obscura.sh --remove # undoAlso a personal --scope local registration, not tracked config β its own compiled
binary is its MCP server (nothing for this repo to wrap in a Python FastMCP server the
way every other tool-backed MCP server here is), so its calls don't pass through
tool_resolver.py's shared budget/audit logic the way a wrapped tool's would. Scope-gated
the same way browser-mcp/playwright-mcp are either way β see scripts/hooks/ scope_gate_hook.py's TIER2_MCP_SERVERS.
Set an explicit override (a provider name, not a model string β the gateway picks each provider's default model), or let the fallback chain pick automatically:
# Global override β every agent role uses this
export HUNTMCP_MODEL=deepseek
# Per-role override β only the exploit agent uses this
export HUNTMCP_MODEL_EXPLOIT=anthropic
# Local/self-hosted model via Ollama β including a fine-tuned one
export HUNTMCP_MODEL=ollama
export HUNTMCP_LOCAL_MODEL=my-qlora-finetune # defaults to whiterabbitneo if unset
# No override set β model_gateway.py walks the chain:
# Anthropic β OpenAI β DeepSeek β Groq β OpenRouter β local Ollama
./scripts/select-model.shClaude Code subagents pin their own model in each .claude/agents/*.md file's frontmatter
(model: sonnet / opus / inherit) since that harness always runs on Claude β the gateway
above applies to the OpenCode harness, where every provider is fair game.
HuntMCP tests 30+ vulnerability classes across the OWASP Web Security Testing Guide (WSTG) methodology, backed by 52 technique skills covering everything from low-hanging fruit to deep-cut, disclosed-report-derived edge cases:
| Category | Classes | Primary Tooling |
|---|---|---|
| π Injection | SQLi, XSS, SSTI, Command Injection, LDAP, XPath, XXE | sqlmap, dalfox, nuclei |
| π Authentication | Auth Bypass, JWT Attacks, OAuth Abuse, SAML, OTP Bypass, Session Fixation, Password Reset Poisoning | nuclei templates, curated payload library |
| πͺ Authorization | IDOR, Mass Assignment, Privilege Escalation, API Auth Bypass, CORS, GraphQL Bypass | idor-mcp, ffuf, curated payload library |
| βοΈ Business Logic | Race Conditions, Negative Values, Workflow Bypass, Coupon Abuse | manual verification, exploit-agent |
| π₯οΈ Server-Side | SSRF, LFI/RFI, File Upload, Deserialization, Prototype Pollution, HTTP Smuggling, Cache Poisoning | nuclei, curated payload library |
| βοΈ Infrastructure | Subdomain Takeover, S3/Cloud Buckets, Security Headers, CVE Scan, WAF Bypass, TLS/SSL | nuclei, subfinder, nmap |
| π Chained | Any combination the chain-planner's 15 DAG templates recognize | chainer-mcp |
Click to expand full directory layout
HuntMCP/
βββ mcp-servers/ 24 FastMCP servers (one per tool) + shared libs:
β βββ tool_resolver.py binary resolution + reactive rate-limit/WAF handling
β βββ scope_guard.py engagement.yaml scope checks (shared across harnesses)
β βββ budget_guard.py Tier-2 tool-call budget circuit-breaker
β βββ engagement_paths.py per-target state dirs -- multi-target hunting, no state mixing
β βββ model_gateway.py multi-provider model selection
β βββ audit_log.py per-call JSON audit trail
β βββ dedupe_check.py duplicate-finding check
β βββ case_store.py persistent case state -- hypotheses, evidence, finding lifecycle
β βββ bounty_scope.py aggregated bounty-program scope cache/lookup/diff
β βββ disclosed_reports.py disclosed-vulnerability-report cache/search
β βββ content_scanner.py OWASP Skill/MCP Top 10-style safety scan for new content
β βββ browser-mcp/ headless-Chromium JS/DOM confirmation + auth session seeding
β βββ idor-mcp/ automated cross-account IDOR/BOLA sweep
β βββ secrets-mcp/ gitleaks secret scan + JS-bundle endpoint inventory
β βββ oob-mcp/ interactsh-client wrapper (blind SSRF/XXE/SQLi/RCE)
βββ .opencode/
β βββ agents/ Multi-level agent files (OpenCode harness)
β βββ plugin/scope-gate.ts tool.execute.before hook -- structural scope enforcement
β βββ commands/ /ingest, /learn, /chain, /watch
βββ .claude/
β βββ agents/ Same agent roster, native Claude Code subagents
β βββ commands/ /audit
β βββ settings.json PreToolUse hook: structural scope + rm enforcement
βββ .mcp.json MCP server registration for Claude Code
βββ scripts/
β βββ hooks/scope_gate_hook.py shared scope/rm-block hook, both harnesses
β βββ new-target-session.sh isolate a session for true concurrent multi-target hunting
β βββ check-scope.sh, check-budget.sh, switch-engagement.sh, setup, ingestion, cron
βββ knowledge/
β βββ master-pentest-prompt.md Phase-mapped WSTG methodology reference
β βββ payloads/ Curated payload lists per vulnerability class
β βββ wordlists/ Directories, API endpoints, subdomains
βββ data/
β βββ chroma/ Vector DB (local, gitignored)
β βββ engagements/<slug>/ Per-target state -- scope, budget, findings, reports
β βββ writeups/ Raw writeup markdown (git-tracked)
βββ backend/ Optional Go + Postgres/pgvector hosted backend
βββ engagement.yaml.example Scope file format (real engagement.yaml is gitignored)
βββ opencode.jsonc MCP configuration + permissions (OpenCode)
βββ docker-compose.yml / Dockerfile
βββ CLAUDE.md / AGENTS.md Coding-agent guidance for this repo
βββ ARCHITECTURE.md Full system design + phase-by-phase build status
MIT β use freely, adapt for your project, no attribution required.
Built on MCP Β· Runs on OpenCode or Claude Code Β· For authorized security testing only