An AI-driven, local-first penetration testing & bug bounty research agent. All in One Web Interface!
Plan, reconnoiter, exploit, and report end to end against targets you own or are explicitly authorized to assess. An autonomous operator that thinks in kill-chains, not checklists: it scouts the surface, picks the attack, runs it, proves the outcome with evidence, and writes the report. Powered by Ollama LLMs, the Model Context Protocol, and a 140-skill advisory knowledge base. Lab-only, target-locked, fully audited.
Warning
Authorized use only. Run NetAttackAI solely against networks and systems you own or have explicit written authorization to test, on a throwaway operator box.
Attack mode ships as full_access: every action is auto-approved with
no command-content or scope inspection. The operator-box filesystem is
unrestricted (write_python_file / read_workspace_file reach any path).
The single remaining attack-path safety is the target-IP allowlist lock,
a destination guard that refuses off-target hosts. It is not authorization
proof, not a sandbox, and a statically-constructed or DNS-resolved
destination may evade it. Recon keeps its full scope-gated safety model.
See Safety model and docs/safety-model.md.
A coupled assessment engine, not an nmap wrapper with a chatbot on top:
- Assessment controller (
main.py/app.py): opens an MCP exploit session, dispatches tool calls, streams live events to a CLI or browser. - Defensive MCP server (
mcp_server.py): scope-gated Nmap, sanitized vulnerability search, NVD CVE lookup. Read-only by design. - Permissive exploit MCP server (
mcp_exploit_server.py, port 8001): terminal, Python write/run, searchsploit, Metasploit, msfvenom, impacket lateral movement, credential dumping, kerberoasting, web scanning, hash cracking. Gated by the target-IP allowlist lock at the tool layer. - Multi-agent swarm (
tools/swarm/): 6 specialist agents (recon, vuln, exploit, post-exploit, critic, reflection) with a shared blackboard. - Autonomous attack orchestrator (
tools/autonomous_orchestrator.py): persistent multi-phase campaigns with adaptive aggression, vuln chaining, and auto-retry. - Runtime skills system: 140 advisory
SKILL.mdfiles indexed, deterministically + semantically selected, injected into LLM context per phase. Advisory only, never grants execution authority. - Bundled WebUI (React + Vite + TypeScript) served by a loopback-only REST + WebSocket API daemon.
For the full architecture, Flow A/B split, and module map, see
docs/architecture.md and
docs/module-guide.md.
- Cloud-first, local-capable. Default model path is Ollama Cloud
(
glm-5.2:cloud, 976K context). Swapollama.hostto a local daemon and the same code path runs against it. Embeddings stay local vianomic-embed-text. - Multi-model war room. Ask Kimi K2.6, DeepSeek V4 Pro/Flash, GLM-5.2, and Minimax M3 for advisory ideas mid-run. Peers have no tool schemas and cannot execute commands.
- 140-skill advisory brain. Each
SKILL.mdcarries NIST CSF + MITRE ATT&CK metadata. Selected deterministically + semantically, re-selected mid-run as new services/CVEs surface, with cross-mission Bayesian feedback. - Hypothesis-driven outcome judgment. Every executed check produces
structured observations;
OutcomeJudgeevaluates them against task criteria and persists a terminalconfirmed/refuted/exhaustedverdict. Execution success ≠ evidential success. - Tamper-evident audit chain. Every target-touching action lands in
exploit_workspace/<ip>/exploit_audit.jsonlwith SHA256 of generated code. Chain validity is verified and surfaced in the WebUI. - Target-aware OPSEC. Pacing, UA rotation, DNS-over-HTTPS, and quiet-command hints auto-disable for private/local IPs and engage for public-routable targets. Advisory-only, never a gate.
- Domain targeting. Pass
--target example.com; the agent resolves it, expands subdomains (crt.sh + DNS bruteforce + subfinder/amass), and auto-authorizes each discovered host through the allowlist lock. - Long-session mode. Opt-in multi-hour runs send the model's real context window to Ollama, bound each LLM call with an httpx timeout, and checkpoint compacted state for crash recovery.
- Eval harness. Benchmark against target labs with JSON/Markdown/HTML
reports under
reports/eval/<run_id>/. - 179-test suite, all mocked. No live Nmap, no live network: every test mocks subprocess/network and runs offline.
- Python 3.11+ (the
--doctorcheck rejects 3.10) nmaponPATH(or setnmap.pathinconfig.yaml)- An Ollama endpoint: cloud is the default (
https://api.ollama.com, needsOLLAMA_API_KEY) or a local daemon (ollama.host: http://localhost:11434) - Optional, Linux full arsenal: Metasploit, searchsploit, impacket, tmux
- For the WebUI: Node.js + npm (only on first
--webrun) - ChatGPT provider (optional): bun ≥ 1.3.11 to run the
vendored
oauth/proxy from source (only whenmodels.provider: chatgpt). A local Ollama is still required for embeddings even under the ChatGPT provider. See docs/providers.md.
# Windows PowerShell (this repo's primary dev platform)
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -r requirements.txt# Linux / macOS
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
./scripts/setup-linux.sh # one-shot bootstrap: venv + deps + doctorLinux nmap -O/-sS need root: set nmap.sudo: true (uses sudo -n) or run
as root; otherwise nmap.priv_fallback (default true) auto-downgrades.
ChatGPT provider one-time setup (only if you'll set
models.provider: chatgpt):
cd openai-oauth && bun install && cd .. # bun@1.3.11; makes ./src/cli.ts runnableinstall.bat / install.sh / scripts/setup-linux.sh run this best-effort
when bun is on PATH; it never aborts the install if bun is missing, since
ChatGPT is opt-in. No global Codex CLI install is required.
The default cloud path requires OLLAMA_API_KEY or the doctor's Ollama
reachability check will 401. Keys are read from process environment
variables or secr.json; there is no .env auto-load. Set them with:
python main.py --setup-api-keys # prompts + writes secr.json (gitignored)| Var | Purpose |
|---|---|
OLLAMA_API_KEY |
Required for the default Ollama Cloud path |
NVD_API_KEY |
Raises NVD CVE lookup rate limit |
GITHUB_TOKEN |
Raises cve_to_poc GitHub Search API limit 60→5000/hr |
SERPAPI_API_KEY |
Optional fallback web research provider |
NETATTACKAI_API_TOKEN |
Override the auto-generated WebUI bearer token |
.env.example documents the same vars; copy it to .env for your own
shell-load workflow, but the app itself does not read .env.
ChatGPT provider (opt-in,
models.provider: chatgpt) does not use an env API key. It authenticates via a browser "Sign in with ChatGPT" OAuth flow whose tokens live in~/.codex/auth.json(managed by the vendoredoauth/proxy). They are never copied intoconfig.yamlor logged. Runpython main.py→ choose ChatGPT → Sign in with ChatGPT, or see docs/providers.md.
python main.py --doctor # env check (Python/nmap/Ollama/models/config; +ChatGPT when provider=chatgpt)
python main.py --self-test # safe localhost smoke test
python main.py # WebUI daemon (default no-args; opens browser)
python main.py --menu # terminal interactive menu (legacy)--doctor exits 0 when all checks pass. Cloud models are verified by running
a 1-token generation (the programmatic ollama run); local models report a
ollama pull <spec> hint if missing. When models.provider: chatgpt, the
doctor adds a ChatGPT block: openai-oauth source found, runtime (bun/node) on
PATH, OAuth login present, proxy running, and /v1/models reachable. It never
displays token contents.
| Interface | Start | Notes |
|---|---|---|
| WebUI | python main.py |
Default. Builds webui/dist/ on first run (needs Node/npm), opens http://127.0.0.1:8765 |
| CLI menu | python main.py --menu |
Guided questionary flow; no extra deps |
| CLI direct | python main.py --target <ip> --mode recon|attack |
Flags below |
| API only | python main.py --demon |
Daemon without the SPA |
WebUI: bearer token auto-generated into .webui_secret_key (gitignored) or
set NETATTACKAI_API_TOKEN. Loopback-only, one active run at a time (HTTP
409 on conflict). Docs at http://127.0.0.1:8765/docs. Full SPA reference in
docs/webui.md and docs/api.md.
The default is Ollama (cloud or local daemon). To use ChatGPT instead,
pick it in the interactive menu (python main.py --menu → Select AI
provider → ChatGPT → Sign in with ChatGPT) or the WebUI's System page, or
set models.provider: chatgpt in config.yaml. Both providers share the same
ModelClient/ModelRouter surface, so every run path (CLI, WebUI, swarm,
autonomous) works unchanged; embeddings always stay on Ollama. Full setup,
proxy lifecycle, and security notes in docs/providers.md.
# Recon against an allowed target (propose-only, safe)
python main.py --target 10.0.0.50 --mode recon --recon-first
# Attack with a preset goal
python main.py --target 10.0.0.50 --mode attack --goal backdoor
# Full-power swarm run
python main.py --target 10.0.0.50 --mode attack --swarm --critic \
--reflection --adaptive-exploits
# Multi-hour attack mode (raises context window, budgets, checkpoints)
python main.py --target 10.0.0.50 --mode attack --long-session
# Domain targeting — resolve, expand subdomains, attack the surface
python main.py --target example.com --mode attack
# Engine advisory MCP server (read-only surface for foreign AI assistants)
python mcp_engine_server.pyNotable flags: --model <alias>, --mcp-transport stdio|http,
--parallel-swarm, --multi-model-consult, --ultrathink, --skills on|off|hints|lookup,
--skills-list, --eval, --ctf (CTF autopilot with goal-completion detection),
--resume <run_id>, --yes (skip confirm gate).
Run python main.py --help for the full list.
python cli.py init-mission --config mission.yaml
python cli.py next-task
python cli.py run-task T-00001
python cli.py list-findings
python cli.py generate-report F-00001
python cli.py statusFlow B is the database-driven, scope-gated research loop. See
docs/runtime-flows.md.
This is a lab-only build. The attack path is unrestricted but target-locked.
| Context | Effective permission |
|---|---|
--mode recon |
Always read_only: gathers and proposes, no offensive execution |
--mode attack |
Uses exploit.permission from config.yaml |
| Shipped attack default | full_access: auto-approves every action, no content/scope inspection |
| Safer attack posture | approve_only: prints an approval banner per action |
The one attack-mode safety: the target-IP allowlist lock, enforced at the
MCP tool layer (tools/mcp_shared._allowed_target_list +
tools/mcp_tools/terminal._target_lock_block), not in policy. It unions
EXPLOIT_TARGET (the runtime --target) with exploit.allowed_targets,
plus EXPLOIT_TARGET_IP / EXPLOIT_TARGET_DOMAIN /
EXPLOIT_DISCOVERED_TARGETS for domain targeting. Every destination in every
command (URL authorities, /dev/tcp hosts, LHOST/RHOST, scanner verbs, bare
IPs, hostnames) is extracted and refused if not in the allowlist. Supports
domains + *.wildcard + CIDR. Interactive target entry persists to
exploit.allowed_targets; domain enumeration auto-authorizes discovered
hosts; callback/C2 hosts must be added explicitly.
What the lock is not: authorization proof, a sandbox, or a guarantee that
a dynamically-constructed or DNS-resolved destination is caught. It is a
destination guard. Recon keeps its full safety (post-session
SafetyReviewer, READ_ONLY propose-only path, goal-menu SAFE/GATED
narrowing, defensive scope-gated mcp_server.py).
Operational guards that remain regardless of mode: command timeouts (300s
terminal / 300s python / 600s msf), full JSONL audit trail
(exploit_workspace/<ip>/exploit_audit.jsonl) with SHA256 of generated code,
OS-aware tooling (Windows attacker = Python-only; Linux = full Kali arsenal).
OPSEC is advisory-only, never a gate. Pacing, UA rotation, DoH, and
quiet-command hints auto-disable for private/local target IPs and engage for
public-routable targets. is_quiet_blocked / noise_budget stay dormant.
Full layered model: docs/safety-model.md.
All runtime behavior lives in config.yaml. Key sections:
| Key | Purpose |
|---|---|
ollama |
host, model (glm-5.2:cloud), embed_host (local embeddings) |
models |
provider (ollama default | chatgpt), registry (kimi/deepseek/deepseek_flash/glm/minimax), default_alias |
chatgpt |
opt-in ChatGPT provider: base_url (loopback 127.0.0.1:10531), auto_start, local_repo, runtime, default_model, context_window, discovery/login/proxy timeouts |
exploit |
permission, attack_mode, timeouts, allowed_targets, require_explicit_allowlist, AD/Kerberos suite, MSF recipes, listeners |
opsec |
target-aware OPSEC (pacing, UA rotation, DoH, local_targets_off) |
cve_lookup |
NVD CVE lookup: rate limit, circuit breaker, epss_enabled/kev_enabled (EPSS + CISA KEV enrichment, lab default true, live out of the box), kev_cache_ttl_seconds/kev_cache_path, github.token_env (GITHUB_TOKEN, shared with threat_intel + github_dorks) |
threat_intel |
continuous OSV.dev + GitHub Security Advisories + CISA KEV feed ingestion (search_threat_intel MCP tool). Advisory-only, never touches the target. enabled (lab default true), cache_dir/cache_ttl_seconds, sources (osv/ghsa/kev/exploitdb_rss), max_results, github_token_env. Reuses cve_lookup's KEV catalog. GHSA degrades to osv+kev when GITHUB_TOKEN is unset |
swarm |
agents, parallel_enabled, per_phase_concurrency, negotiation_rounds (bounded critic↔exploit loop; 0 = legacy one-shot, 2 = lab default) |
witness |
advisory audit-stream watcher (enabled, log_path, poll_interval_seconds, escalate_to_event_broker): flags anomalies mid-run (allowlist breach, PoC escape, perm escalation, prompt injection, DoS drift), never blocks; lab default ON for telemetry |
autonomous |
persistence phase, checkpoint, adaptive_replan, max_cycles |
orchestrator |
semantic_memory (cross-mission lesson consumer for the autonomous orchestrator; lab default true, matching memory.semantic_enabled) |
recon |
extended enumerators, UDP top-ports, shodan_api_key (wired into the shodan_recon plugin: passive OSINT, advisory-only), domain resolution |
skills |
selection, re-selection, feedback, semantic matching, maybe_enabled (gates the skills/maybe/ opt-in pack; default false) |
outcome_judgment |
evidence-grounded verdicts (flow_a wires OutcomeJudge into Flow A; peer_review enables cross-model outcome grading) |
poc_verification |
self-healing PoC verification: cve_to_exploit_synth syntax-checks its PoC inline; verify_poc MCP tool compile-tests in isolated Docker (--network=none --read-only --memory=256m) |
replay_simulator |
pre-commit attack-plan critique (replay_simulate MCP tool: LLM critiques its own plan against saved ReconAssessment, with rule-based fallback) |
api |
WebUI daemon host/port/token/origins, graph_route (attack-path DAG), max_concurrent_runs (D3: N concurrent runs for wide-scope assessments; lab default 3; set 1 for legacy single-run 409), multi_operator (D4: user accounts + annotations; lab default true, loopback-only) |
ics |
D8: allow_write (lab default true: operator runs against owned PLCs; physical-damage risk). Write-side ICS modules are DESTRUCTIVE. Dual-gated: @require_allowlist on run_attack_module AND ics.allow_write: true. Set false for read-only ICS enum |
long_session |
multi-hour mode, request timeout, checkpoint |
plugins |
out-of-tree plugin enable/disable, search paths, entry points |
webhook_notify |
outbound Slack/Discord run-status notifications (url, event filter, retry/backoff) |
mitre |
MITRE ATT&CK Navigator export (technique map, output dir, skill tags) |
ticketing |
remediation ticket generation (Jira/GitHub, provider, base_url, token env) |
Mission scope (allowed/disallowed assets, forbidden actions, risk profiles)
for Flow B lives in mission.yaml. Three risk profiles:
low_noise_non_destructive, standard_authorized, high_authorized_testing.
Hard-blocked actions regardless of config: denial_of_service,
destructive_exploit, social_engineering, physical_attack, malware,
credential_theft (see scope_gate.py:_HARD_FORBIDDEN_ACTIONS).
python -m pytest tests/ -v # full suite (179 files)
python -m pytest tests/test_scope_gate.py -v # single file
python -m pytest tests/test_recon_pipeline.py::TestClass::test_method # one test
python -m pytest tests/ -v -k "scope" # by keyword
python -m pytest --cov=tools --cov=main.py --cov=cli.py # coverageAll tests mock subprocess/network: no live Nmap, no live network. pytest
config: asyncio_mode = "auto", testpaths = ["tests"].
CI runs on every push and pull request (concurrency-cancelled, no secrets required, nothing touches the network):
- Python tests on Python 3.11, 3.12, and 3.13 — the full mocked/offline
suite (
python -m pytest tests/ -v). - Coverage on Python 3.12: terminal report +
coverage.xmlartifact. - Ruff on the currently passing scope (safety core + intelligence +
providers):
app.py,scope_gate.py,tools/safety_reviewer.py,tools/validation_utils.py,tools/intelligence,tools/providers. Repository-wideruff check .still reports ~1800 pre-existing violations (mostly import sorting) that are out of scope here. - mypy on the currently passing typed core (
--follow-imports=skip):summarizer.py,planner.py,observer.py,target_graph.py,outcome_judge.py,db.py,mcp_exploit_server.py,tools/mcp_shared.py. The rest of the codebase is not yet type-clean. - Package build:
python -m build+python -m twine check dist/*. - WebUI:
npm ci,npm run build(tsc + vite),npm run test(vitest).
Security automation: CodeQL (Python + JavaScript/TypeScript) on push/PR/weekly, GitHub dependency review on pull requests, and Dependabot for pip / GitHub Actions / npm (weekly, grouped).
Before opening a PR, run the same checks locally:
python -m pip install -e ".[dev]"
python -m pytest tests/ -v
ruff check app.py scope_gate.py tools/safety_reviewer.py tools/validation_utils.py tools/intelligence tools/providers
mypy --follow-imports=skip summarizer.py planner.py observer.py target_graph.py outcome_judge.py db.py mcp_exploit_server.py tools/mcp_shared.py
cd webui && npm ci && npm run build && npm run testand verify README flags/config still match reality.
Out-of-tree extensions managed by tools/plugins.py (pure stdlib). A plugin
can contribute an attack module, MCP tools, a skills directory, and a config
section. Plugins are disabled by default; enable via config plugins.enabled.
A reference plugin lives at plugins/example_recon_report/. See
docs/plugin-development.md.
Shipped plugins (lab build: enabled by default; enabling requires both
plugins.enabled and the API key/token in config.yaml):
shodan_recon: passive Shodan OSINT (shodan_host_lookup,shodan_searchMCP tools). Advisory-only, never touches the target. Requiresrecon.shodan_api_key; MCP tool returnsBLOCKED:when unset. Pure stdlib (urllib).github_dorks: authorized-target code-leak discovery (search_github_dorksMCP tool). Runs curated dorks against a target org's public GitHub repos. RequiresGITHUB_TOKEN(cve_lookup.github.token_env); MCP tool returnsBLOCKED:when unset. Advisory-only.
Engineering docs in docs/:
Operators
- Getting Started: setup, common commands, dev loop
- Model Providers: Ollama (default) + ChatGPT (openai-oauth), proxy/login lifecycle
- Safety Model: scope, risk, permission, audit
- WebUI: the bundled React/Vite SPA
- WebUI API:
/api/v1REST + WebSocket reference
Integrators
- Runtime Skills: advisory skill pipeline
- Plugin Development: out-of-tree plugins
- Attack Modules: pre-packaged exploit logic
Contributors
- Architecture: system shape, entry points, persistence
- Runtime Flows: recon, execution, exploitation, swarm, MCP
- Module Guide: responsibilities of top-level modules
- Extension Guide: exact edit points for in-tree changes
- Testing Guide: test layout, focused commands
AGENTS.md: compact agent guide with non-obvious rulesCLAUDE.md: architecture/safety depth for AI coding agents
- Read
AGENTS.mdfirst: it lists the non-obvious rules you will otherwise break. - Run
python main.py --doctorandpython main.py --self-testafter safety-sensitive changes. - Run the CI checks locally before opening a PR — see CI (GitHub Actions) above.
- Do not edit Flow B safety files (
scope_gate.py,safety_reviewer.py, Flow B'sagent_loop.py/tool_router.py/risk_controller.py/mission.py/db.py): recon safety depends on them. - New exploit MCP tools must be registered twice:
@audit_toolintools/mcp_tools/<family>.py, then added to the tool list inmcp_exploit_server.py. Target-touching tools require a target IP and the@require_allowlist()gate. - When adding a CLI flag, MCP tool, or config key, update the relevant README section.
NetAttackAI, Copyright (c) 2026 NetAttackAI contributors.
Licensed under the GNU General Public License v3.0 only. See
LICENSE for the full text.
