PentestGPT Documentation

Automated Penetration Testing Agentic Framework Powered by Large Language Models

16,079 stars Python Python 4 files ยท ~7,909 tokens #large-language-models#llm#penetration-testing#python
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy PentestGPT on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name pentestgpt --restart always pentestgpt:latest
Configured Services & Ports
โš™๏ธ pentestgpt
image: pentestgpt:latest
docker-compose.yml
yaml (docker-compose.yml)
services:
  pentestgpt:
    container_name: pentestgpt
    image: pentestgpt:latest
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
      # Mount workspace for file operations
      - ./workspace:/workspace
      # Persist Claude Code login/config across container restarts (set up via `make docker-login`)
      - claude-config:/home/pentester/.claude
      # Persist Codex login/config across container restarts
      - codex-config:/home/pentester/.codex
      # Persist CCR configuration
      - ccr-config:/home/pentester/.claude-code-router
    stdin_open: true
    tty: true
    # Required for OpenVPN (HackTheBox/TryHackMe connectivity)
    cap_add:
      - NET_ADMIN
    devices:
      - /dev/net/tun:/dev/net/tun
    # Use host network for easy access to benchmark containers
    extra_hosts:
      - "host.docker.internal:host-gateway"
    # Resource allocation - adjust based on your system
    # More CPUs and memory improve performance for complex tasks
    deploy:
      resources:
        limits:
          cpus: '4'        # Max 4 CPU cores (adjust higher if available)
          memory: 8G       # Max 8GB RAM
        reservations:
          cpus: '2'        # Guarantee 2 CPU cores
          memory: 4G       # Guarantee 4GB RAM
    environment:
      # Terminal settings
      - TERM=xterm-256color
      # Python settings
      - PYTHONUNBUFFERED=1
      # Auth mode: "openrouter", "anthropic", or "manual"
      - PENTESTGPT_AUTH_MODE=${PENTESTGPT_AUTH_MODE:-manual}
      # API keys (set based on auth mode via .env.auth)
      - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
      - OPENROUTER_API_KEY=${OPENROUTER_API_KEY:-}

volumes:
  # Explicit names so Docker login/status/shell commands and compose share the
  # same persistent login volumes regardless of the compose project name.
  claude-config:
    name: pentestgpt-claude
  codex-config:
    name: pentestgpt-codex
  # Named volume for CCR config persistence
  ccr-config:

File: docs/architecture.md

PentestGPT architecture

Status: 2026-07-12

This is the internal source of truth for the current repository shape. The root README.md is the
public project page and is intentionally being revised separately.

Repository family

text
PentestGPT_Project/
โ”œโ”€โ”€ PentestGPT/          # framework, legacy interactive client, and tool image
โ”œโ”€โ”€ UnifedAgentWrapper/  # canonical unified-agent package
โ””โ”€โ”€ xbow-benchmark/      # reference-only benchmark harness and historical results

The three directories are independent Git repositories. The XBOW checkout is retained as a
reference corpus only; the product CLI, runtime, and CI do not depend on it. Benchmark logic and
result archives must not be added here.

Maintained runtime

pentestgpt_agent/ is the autonomous framework. It is a nested uv project with its own lockfile and
environment. The loop deliberately has only two LLM roles:

text
RunSnapshot -> Supervisor -> compile_plan -> one TaskLease
                                             |
TraceStore <- EpisodeRunner <- Executor <----+
     |                              |
     +---- compile_execution -------+
                    |
               MemoryKernel
  • The Supervisor chooses one task or proposes completion.
  • The Executor performs one leased task and returns a typed result.
  • Both roles use fresh provider sessions and FULL_ACCESS. The deployment environment is the
    isolation boundary; PentestGPT does not maintain a second tool or filesystem sandbox.
  • Deterministic code owns scope validation, leases, evidence provenance, retries, revisions, and
    canonical state.
  • SQLite is canonical memory. Provider transcripts are diagnostic traces, not memory.
  • There is no always-on judge, RAG service, speculative backlog, or parallel scheduler.

pentestgpt_legacy/ is the maintained human-driven implementation of the USENIX 2024 workflow. It
has its own lightweight provider clients and does not use unified_agent.

Why unified-agent remains useful

The external UnifedAgentWrapper is a real seam with two production adapters: Claude Code and
Codex. PentestGPT depends on its small interface for:

  • provider selection, model, effort, workspace, and permission configuration;
  • structured-output invocation;
  • normalized command, tool, file, session, usage, cost, and terminal events;
  • shared task rendering and provider error handling.

Removing that module would duplicate provider SDK churn inside pentestgpt_agent.trace and
pentestgpt_agent.trial. It therefore earns its place as a deep module. PentestGPT policy must stay
outside it: task kinds, memory, evidence, scope, scheduling, and completion belong to this repo.

The dependency is pinned to a commit of the public package in pentestgpt_agent/pyproject.toml, and
tests/test_dependency.py verifies that the nested project imports the installed dependency rather
than the repository-root copy.

Root unified_agent copy

The root unified_agent/ is an older, drifted compatibility copy. No maintained PentestGPT runtime
imports it:

  • pentestgpt_agent uses the external package;
  • pentestgpt_legacy uses its own provider clients;
  • only root packaging, its duplicate tests, and the current tool-image health check retain it.

Do not develop features in this copy. Removing it is desirable, but it is a separate public-package
cleanup because the root wheel currently exports the package and the Docker image copies it. That
cleanup must update the root package metadata, Docker health tests, lockfile, and public README in
one deliberate change.

Deep modules

Module Interface Hidden implementation
PentestLoop run(RunSpec) -> RunSnapshot recovery ordering, retries, episode identity, failure settlement
MemoryKernel create/open/snapshot and atomic commits SQLite schema, transactions, revisions, leases, dependency liveness
compile_plan decision + snapshot -> valid plan scope, dependency, phase, completion, and size validation
compile_execution result + lease + trace -> valid execution exact receipt matching, evidence fallback, identity, recovery rules
EpisodeRunner one typed episode -> normalized result provider invocation and durable append-only trace files
external UnifiedAgent one task over Claude or Codex SDK differences, native options, event normalization

These interfaces are the preferred test surfaces. New provider behavior belongs behind
UnifiedAgent; new canonical-state behavior belongs behind the Memory Kernel or compilers.

Memory and retrieval

Stored state is complete and retrieval is bounded. The Supervisor receives the open working set,
recent closed work, required basis/dependency context, selected observations, history counts, and
recent diagnostics. The Executor receives one task, explicit basis, same-task evidence, and a retry
diagnostic. A future retriever may select canonical IDs, but it must not replace SQLite or turn
summaries into evidence.

The current controller weakness is convergence, not database capacity: long runs can lose compact
coverage information and revisit completed surfaces. The next design slice should improve the
deterministic strategy projection and duplicate/branch policy before adding another agent or RAG.

Runtime and benchmark ownership

  • Local framework development runs from pentestgpt_agent/.
  • The root Docker image supplies pentest tools, provider CLIs, legacy code, and persisted auth. It
    does not currently bake in the maintained framework.
  • The sibling xbow-benchmark checkout is a historical/reference artifact, not a supported runtime
    or verification path. PentestGPT owns no XBOW runner.
  • HTB execution happens only on the authorized remote attack box described in the parent project
    guide, never directly from the development Mac.

Current design priorities

  1. Preserve the two-role loop and deterministic memory authority.
  2. Improve Supervisor coverage retrieval and convergence using saved-trace replay tests.
  3. Keep both roles fully enabled inside a restricted deployment environment.
  4. Remove the root unified_agent compatibility copy in a coordinated public-package cleanup.
  5. Add a goal-specific verifier only when non-CTF completion semantics require it.

File: docs/docker-dev-plan.md

Docker runtime status

Status: 2026-07-12

This document describes the repository as it exists now. It replaces the original implementation
plan, whose phase matrix and in-repo benchmark paths are obsolete.

Current image responsibility

pentestgpt:latest is a disposable pentest-tool and provider-CLI environment. It contains:

  • Ubuntu 24.04, Python 3.12, Node 20, uv, Claude Code, and Codex;
  • common network/pentest tools such as nmap, gobuster, dirb, netcat, curl, DNS utilities, jq, and
    ripgrep;
  • the root pentestgpt_legacy package;
  • the old root unified_agent compatibility copy;
  • persistent Claude and Codex authentication helpers.

It deliberately excludes benchmark fixtures/results, credentials, workspaces, and run artifacts.

The maintained pentestgpt_agent nested project is not baked into this image. Consequently,
make docker-run deliberately fails fast with a wiring diagnostic instead of invoking an absent
CLI. There is no product-owned benchmark workaround; framework-image wiring remains an independent
deployment task.

Repository ownership

text
PentestGPT/          image, auth helpers, framework source, legacy client
UnifedAgentWrapper/  canonical provider-wrapper package
xbow-benchmark/      reference-only benchmark harness and historical results

The product does not support or invoke the sibling benchmark harness. Keep result JSONL, target
orchestration, and benchmark-specific adapters out of this repository.

Persistent provider login

Authentication state lives in named volumes and is never copied into image layers:

text
pentestgpt-claude -> /home/pentester/.claude
pentestgpt-codex  -> /home/pentester/.codex

The providers require different setup paths:

  • Claude uses a long-lived setup-token, stored as .claude/oauth_token and exported as
    CLAUDE_CODE_OAUTH_TOKEN by the entrypoint.
  • Codex performs its own in-container OAuth login. Its callback is forwarded through a socat hop;
    host auth.json must not be copied because ChatGPT refresh tokens rotate.

Useful commands:

bash
make docker-build
make docker-login
make docker-auth-status
ROUNDTRIP=1 make docker-auth-status   # spends a minimal provider call
make docker-shell
make docker-down                      # keeps auth volumes
make docker-nuke                      # deliberately removes auth volumes

The auth-status check is advisory by default. Named volumes are credentials and must be protected
like a logged-in workstation.

Isolation contract

Both PentestGPT roles use provider FULL_ACCESS. The container or dedicated attack box is therefore
the blast radius and security boundary. A deployment must:

  • contain only authorized target routes;
  • avoid mounting unrelated source, home directories, tokens, or host sockets;
  • mount run state only when persistence is required;
  • treat traces and SQLite state as sensitive;
  • tear down the environment after the assessment.

The tool image runs as pentester, which has passwordless sudo. It is isolation from the developer
host only when mounts, capabilities, devices, and networking are deliberately constrained.

Framework-image decision still open

There are two reasonable future shapes:

  1. Build framework and unified-agent wheels outside Docker, then copy them into a dedicated runtime
    image. This matches the proven qualification runner and preserves exact package hashes.
  2. Publish both packages and install pinned releases during the Docker build.

Do not copy the root unified_agent/ directory into the maintained framework. It is version 0.1-era
compatibility code; the agent requires the pinned external 0.3 package.

Whichever shape is selected must make these checks true in a fresh container:

bash
pentestgpt-agent --help
python -c "import pentestgpt_agent, unified_agent; print(unified_agent.__version__)"

Only after that should make docker-run be advertised as supported.

Build cleanup opportunities

These are independent of framework design:

  • remove apt-get upgrade for faster, more reproducible builds;
  • install socat in the main apt layer;
  • combine global npm installs;
  • use BuildKit cache mounts for apt, npm, and uv;
  • install from lockfiles/wheels before copying frequently changing source;
  • remove the root unified_agent copy and its SDK dependencies when the public-package cleanup is
    performed.

External benchmark reference

The sibling xbow-benchmark repository is retained only for historical reference. The product
Makefile, CLI, CI, and Docker runtime do not invoke it. If a future evaluation reuses that corpus,
design the adapter in an external evaluation repository rather than restoring a benchmark runner
inside PentestGPT.


File: pentestgpt_agent/README.md

PentestGPT Agent

Small, durable penetration-testing loop built on the external
unified-agent package. It is the
maintained autonomous framework; the root pentestgpt_legacy package remains the human-driven
USEN-2024 workflow.

The supported deployment boundary is an isolated, disposable environment containing only
authorized targets and the required provider credentials.

Runtime shape

text
SQLite snapshot
  -> recover an active lease or invoke a fresh Supervisor
  -> validate one typed decision and atomically lease one task
  -> recover its trace or invoke a fresh Executor
  -> validate trace identity and exact receipt evidence
  -> atomically commit attempt, observation, and transition
  -> repeat, finish, safely retry, or fail closed
  • The Supervisor and Executor both receive all provider tools and FULL_ACCESS filesystem/process
    permissions. PentestGPT relies on deployment isolation rather than a second in-process sandbox.
  • The Supervisor proposes at most one new task and selects exactly one ready task or completion.
  • The Executor receives one leased task with an explicit task kind and bounded provider turn budget.
  • Every episode is fresh (resume = null); provider conversation history is not memory.
  • Deterministic code owns scope, dependencies, leases, receipt provenance, retries, completion
    bases, and canonical state transitions.
  • Provider actions and file writes are retained in traces and audit totals, but are allowed.
  • There is no speculative backlog, parallel scheduler, RAG service, or always-on judge.

See CONTEXT.md for the exact domain language and invariants, and
../docs/architecture.md for repository-level decisions.

Memory and traces

SQLite stores runs, typed tasks, attempts, bounded exact observations, and one transition per
revision. An observation must resolve to one exact contiguous slice of one eligible command or tool
receipt. Completed nonzero commands may ground negative findings; provider/tool transport failures
cannot. CRLF/LF normalization is the only accepted textual transport normalization.

An oversized receipt contributes at most an exact 4,000-character suffix and can commit only
progress. A no-action attempt may reuse exact evidence from an earlier attempt of the same task;
unsupported paraphrases degrade to progress and never create evidence.

The Supervisor receives a bounded projection: open work, four recent closed tasks, required
dependency/basis context, selected observations, aggregate history, and recent diagnostics. The
Executor receives one task, its explicit basis, up to two same-task observations, and one retry
diagnostic. Future retrieval may select canonical IDs, but SQLite remains authoritative.

Each episode directory contains:

text
input.json     exact role input, prompt/schema hashes, provider policy
events.jsonl   chronological normalized tool, command, file, and terminal events
output.json    normalized result, usage, cost, duration, and failure

Traces contain sensitive target output and provider session identifiers. They are mode-restricted,
not encrypted or tamper-evident.

Failure and restart behavior

  • Operational failures retry only when no external-action receipt exists.
  • Actionful failures are never replayed automatically.
  • Existing terminal traces are compiled and committed before any provider reinvocation.
  • A terminal event can reconstruct a missing output.json.
  • Supervisor decisions are recovered by state revision; invalid plans receive one bounded retry.
  • Attempt and decision budgets survive restart.
  • --resume requires an exact trial-config.json match, including goal, targets, provider, model,
    effort, prompt/schema hashes, budgets, both full-access role policies, environment, and
    unified-agent version.

Install and verify

Run from this directory so the repository-root compatibility copy cannot shadow the dependency.

bash
uv sync --extra claude       # or: codex / all
uv run python -m pytest -q
uv run ruff check src tests
uv run ruff format --check src tests
uv run mypy src
uv lock --check
uv build

The normal suite uses scripted provider adapters and a loopback target. The opt-in live smoke spends
provider tokens:

bash
PENTESTGPT_AGENT_LIVE=1 \
PENTESTGPT_AGENT_BACKEND=claude \
PENTESTGPT_AGENT_MODEL=claude-opus-4-8 \
uv run python -m pytest tests/live/test_local_model.py -q -s

Run and resume

bash
uv run pentestgpt-agent \
  --goal "Capture the flag from this authorized target." \
  --target http://127.0.0.1:8080 \
  --backend claude \
  --model claude-opus-4-8 \
  --effort xhigh \
  --run-id example

uv run pentestgpt-agent \
  --goal "Capture the flag from this authorized target." \
  --target http://127.0.0.1:8080 \
  --backend claude \
  --model claude-opus-4-8 \
  --effort xhigh \
  --run-id example \
  --resume

Audit a held-out oracle:

bash
uv run pentestgpt-agent-audit \
  --run-dir runs/example \
  --expected-flag 'FLAG{...}' \
  --output runs/example-audit.json

Audit schema 2 checks structural completion, canonical oracle evidence, settled leases/episodes,
exact receipt grounding, identity, dependency/basis integrity, current TEST provenance for EXPLOIT,
completion basis, revision continuity, and settled failures. Supervisor actions and provider-memory
writes are reported as diagnostics rather than failures.

UnifiedAgent dependency

unified-agent==0.3.0 is pinned to the merged inspector commit in pyproject.toml. It is the provider seam
for Claude Code and Codex: task invocation, model/effort configuration, structured output, and
normalized events. PentestGPT keeps task policy, memory, evidence, and completion outside that
dependency.

tests/test_dependency.py verifies that imports resolve to the installed external package, not the
obsolete repository-root unified_agent/ copy.

Live process inspector

UnifiedAgent 0.3 adds a read-only local web inspector. PentestGPT gives every monitored provider
episode a stable --<episode-id> identity and attaches the role, state revision,
task, and attempt as metadata. The framework's trace journal remains canonical; the inspector
database is an additional real-time diagnostic projection.

To inspect local wrapper changes before publishing a new immutable dependency revision, explicitly
opt into the sibling checkout:

bash
export PYTHONPATH="$(cd ../../UnifedAgentWrapper && pwd)"
export UNIFIED_AGENT_MONITOR_DB="$(pwd)/runs/inspector.sqlite3"
uv run --no-sync pentestgpt-agent \
  --goal "Assess this explicitly authorized target." \
  --target http://127.0.0.1:8080 \
  --backend codex \
  --model gpt-5.5 \
  --run-id inspector-example

# In another terminal, from ../../UnifedAgentWrapper:
PYTHONPATH=. .venv/bin/python -m unified_agent.monitor_web \
  --database "$(cd ../PentestGPT/pentestgpt_agent && pwd)/runs/inspector.sqlite3" \
  --open

The pinned 0.3 dependency provides the same monitor behavior in normal synchronized environments;
the sibling override is only for wrapper development.

External evaluation references

The sibling ../../xbow-benchmark checkout is retained only as a historical/reference corpus.
There is no supported XBOW command, runner, or CI path in pentestgpt-agent, and benchmark-specific
orchestration must stay outside this product repository. Historical engineering records may still
name earlier XBEN qualifications; they are not current regression guarantees.

The later HTB Enigma qualification did not solve the target; see
HTB_ENIGMA_QUALIFICATION_20260712.md.

Current limits

  • FULL_ACCESS is intentional. Either role may read or alter mounted state and credentials; the
    surrounding container/VM must be treated as the blast radius.
  • Provider max_turns is not a portable command/action limit, especially on Codex. It bounds the
    provider interaction where supported, not external side effects.
  • Controller convergence is the main demonstrated performance problem: older coverage can fall out
    of the Supervisor projection and trigger repeated discovery.
  • COMPLETED proves structural evidence citation, not arbitrary natural-language entailment. CTF
    audits use a held-out oracle; general goals need a goal-specific verifier.
  • SQLite has no versioned migration framework. Trace storage is sensitive and not power-loss or
    tamper hardened.
  • Structured findings, report generation, and a PentestGPT product UI remain future work. The
    wrapper-level process inspector is available for live diagnostics.