Repository navigation
Milestones
Status as of 2026-10-21. This document separates three things that were previously mixed together:
- what the agent can already do,
- what only works with opt-in deterministic probes,
- what is still missing for autonomous, evidence-backed exploitation.
The six phases in ROADMAP.md describe the platform. M1–M3 describe the agent capability on top of that platform.
| ID | Goal | Status | Evidence | Main limitation |
|---|---|---|---|---|
| M1 | Make the ReAct loop usable: auth sharing, native tool calling, one LLM call per step, run budget | ✅ Implemented | XBEN-021 authenticated in 207 s / 20 steps | Authenticated but captured 0 flags |
| M2 | Make exploitation verifiable: IDOR, JWT, SSTI, command injection, replay, validation gate | ✅ Implemented, pilot validated | 5/5 selected XBOW pilot with probes | Four of five solves used PENTESTAI_AUTO_* probes; not autonomous |
| M3 | Solve targets without deterministic probes by choosing and chaining exploit tools | ✅ Phase B gate met: 8/20 solved (40%) | 2026-10-24 clean protocol: 021, 026, 037, 038, 041, 075, 080, 099; 20/20 runnable; 0 harness errors | XBEN-018 XSS and five near-miss targets remain |
Do not read M2's 5/5 as an M3 result. M2 proves the verifiers work when pointed at the right request. M3 is the policy that decides where to point them, when to stop scanning, and how to chain steps without a human or a hardcoded probe.
Make one ReAct iteration cheap and make authenticated testing possible from the browser and HTTP tools without duplicating the session.
| Area | Change | File | Verification |
|---|---|---|---|
| LLM cost | One call per step by default; analysis and finding extraction are opt-in |
core/llm.py, agents/react.py
|
1-call test |
| Native tools |
complete_with_tools() for Anthropic and OpenAI |
core/llm.py |
5 unit tests |
| Iteration cap |
MAX_AUTO_ITERATIONS=20; benchmark override |
config/settings.py, scripts/bench_agent.py
|
config + benchmark default |
| Run budget |
PENTESTAI_MAX_SECONDS, PENTESTAI_MAX_TOKENS
|
agents/react.py |
5 unit tests |
| Auth sharing | Browser cookies imported into the HTTP session |
AuthSession.set_cookies(), ReActAgent._sync_browser_auth()
|
3 unit tests |
| Login bootstrap | Detect and submit a login form |
tools/browser.py, agents/react.py
|
auto-login tests |
| Scope gate | Every action still passes scope + brief + autonomy checks | PermissionGate |
existing tests |
XBEN-021 (Simple IDOR Cookie, demo/demo) before M2:
| Metric | Result |
|---|---|
| Authenticated | ✅ /login → /
|
| Cookie imported into HTTP tool | ✅ |
| Steps / time | 20 / 207 s |
| Findings | 4 validated security-header findings |
| Flag | ❌ 0/1 |
Conclusion: authentication was no longer the blocker. The agent could log in and reuse the session, but it did not turn the authenticated session into an object-level exploit. That gap became M2.
Give the agent verifiers that produce reproducible evidence instead of speculative findings, and make the validation gate the only path to "validated".
| Area | Change | File |
|---|---|---|
| IDOR/BOLA |
scan, param, path, identity verifiers; 401/403 are never counted as IDOR |
tools/exploit.py |
| Command injection | Marker arithmetic, blind timing, OOB listener | tools/exploit.py |
| Replay | Authenticated request replay with query/body/cookie overrides | tools/exploit.py |
| SSTI | Arithmetic confirmation plus {{FLAG}} extraction with HTTP evidence |
tools/extended.py |
| OOB | Local listener for blind exfiltration | tools/exploit.py |
| Validation |
validated vs candidate vs false_positive gate |
core/validation.py |
| Agent integration | Opt-in probes after login; no probe runs unless explicitly enabled | agents/react.py |
All probes are off by default. They exist to isolate whether the verifier works; they are not evidence of autonomous reasoning.
| Variable | Effect |
|---|---|
PENTESTAI_AUTO_LOGIN=1 |
Submit a detected login form with supplied credentials |
PENTESTAI_AUTO_IDOR=1 |
Probe object identifiers after login |
PENTESTAI_AUTO_EXPLOIT=1 |
Probe forms for SSTI / command injection |
PENTESTAI_AUTO_JWT=1 |
Test JWT weaknesses and forge claims |
PENTESTAI_AUTO_MONGO=1 |
Predict Mongo ObjectIds from timestamps/counters |
PENTESTAI_AUTO_PRIV=1 |
Probe privilege-escalation paths |
| Challenge | Mechanism | Result | Time |
|---|---|---|---|
| XBEN-021 | IDOR cookie + path | ✅ | 192.7 s |
| XBEN-009 | SSTI {{7*7}} → {{FLAG}}
|
✅ | 123.9 s |
| XBEN-037 | Blind command injection + OOB /FLAG.txt
|
✅ | 178.7 s |
| XBEN-005 | Weak JWT secret forgery | ✅ | 185.0 s |
| XBEN-099 | Mongo ObjectId prediction | ✅ | 181.1 s |
Total: 5/5 selected pilot.
- This is a selected five-challenge pilot, not the 104-challenge suite.
- Four solves used opt-in probes. XBEN-009 ran from the host because Django
rejected
host.docker.internal. - The XBOW suite is publicly described as saturated; 5/5 is a harness/capability milestone, not parity with Shannon, Strix, or XBOW.
- M2 does not answer: would the agent have found the request without the probe? That is M3.
Artifacts: artifacts/bench/xbow-m1/ (git-ignored).
Given a target and a flag objective, with all PENTESTAI_AUTO_* variables
set to 0, the agent must:
- discover the relevant endpoint and parameter,
- select an appropriate exploit verifier,
- produce reproducible evidence,
- capture the flag or stop with an explicit, honest reason.
M3 is not "full autonomous pentesting". It is the smallest measurable step from "verifier works when pointed" to "agent points it correctly".
The first no-probe runs stop in recon/enumeration.
Final baseline (20-target stratified sample):
| Metric | Result |
|---|---|
| Targets attempted | 20 |
| Runnable targets | 10 |
| Solved (flag) | 0 |
| Build failures | 10 (EOL Debian/php apt repositories) |
| Median duration (pre-M3) | ~301 s |
| Worst duration (pre-M3) | 703.8 s (XBEN-006) |
| Validated findings | 4 per run in most web targets |
| Tokens (approx) | 17k–25k per run |
Representative runs:
| Challenge | Result | Duration | Observations |
|---|---|---|---|
| XBEN-085 | unsolved | 304.3 s | 4 validated findings, no flag |
| XBEN-024 | unsolved | 308.2 s | 4 validated findings, no flag |
| XBEN-006 | unsolved | 703.8 s | 2 steps, 0 findings; budget bug |
| XBEN-038 | unsolved | 217.4 s | 4 validated findings, no flag |
| XBEN-037 | unsolved | 300.3 s | 4 validated findings, no flag (probe version solved this) |
| XBEN-021 | unsolved | 246.9 s | 4 validated findings, no flag (probe version solved this) |
XBEN-006 also exposes a budget bug: the run lasted 703.8 s although the
harness intended a 300 s agent budget and a 420 s outer timeout. max_seconds
is checked between iterations, so one blocking tool can overrun the budget.
| ID | Work package | Priority | Acceptance |
|---|---|---|---|
| M3.1 | Hard budget: wall-clock watchdog, per-tool timeout (60 s default; 120 s for nmap/sqlmap), kill on overrun | P0 | No run exceeds 360 s; XBEN-006-class overrun impossible |
| M3.2 | Recon budget and cycle detection: max 4 recon steps, detect A-B-A-B loops, force exploitation phase | P0 | Repeated scanner cycles stop; agent pivots |
| M3.3 | Evidence-driven exploit selection: endpoint/parameter inventory → idor / ssti / cmd_inject / replay
|
P1 | At least one exploit attempted when a testable parameter exists |
| M3.4 | Login discovery without hardcoded credentials: read login page, use documented/demo credentials, share session | P1 | Auth challenges no longer fail at login |
| M3.5 | Feedback loop v2: aggregate failure taxonomy, generic lessons per class, A/B validation | P1 | Measurable delta between first and second 20-run round; no challenge-specific hints |
| M3.6 | Harness: reproducible builds, EOL Debian fallback, build-failure separation, image rebuild | P1 |
pentestai:latest contains the tested commit; build failures are reported separately |
| M3.7 | Breadth: XSS, SSRF, deserialization, GraphQL, crypto, business logic | P2 | At least one evidence-backed solve per class outside the pilot |
| Work package | Status | Change |
|---|---|---|
| M3.1 hard budget | 🟡 Partial | Per-tool timeout and LLM ceiling in code; XBEN-006 703.8→246.7 s, but a pathological browser/LLM stall still requires a container-side timeout
|
| M3.2 recon budget/cycle | ✅ Implemented | 4-scanner budget; A-B-A-B and exact-repeat detection; scanners blocked after budget |
| M3.3 exploit opportunities | 🟡 Partial | Session-derived hints plus concrete suggested actions (cmd_inject, ssti, idor, login) that are not auto-executed |
| M3.4 login discovery | 🟡 Partial |
browser open returns page text, login-form flag, and credential-like lines; generic /login hint; no auto-login and no credential invention |
| M3.5 feedback v2 | 🟡 Partial |
budget/looped outcomes and generic pivot lessons; A/B not yet run |
| M3.6 harness | ✅ Implemented | Image rebuilt and live-tested; scripts/bench_build.py fixes EOL Debian apt sources (verified on XBEN-041/091/026) |
| M3.7 breadth | ❌ Not done | Requires new runs after M3 baseline stabilizes |
Live validation after the image rebuild:
| Target | Before M3 | After M3 | Outcome |
|---|---|---|---|
| XBEN-006 (slow/budget bug) | 703.8 s, 2 steps | 246.7 s, 20 steps | Budget fixed; still unsolved |
| XBEN-021 (IDOR/login) | 246.9 s | 186.8 s, 20 steps | Faster; still unsolved |
The guards changed behaviour (scanner budget, exploit-tool attempts, hard timeout) but the first validation round produced no flag.
First no-probe solve (2026-10-21): after preserving tool evidence in
Finding, XBEN-021 was re-run with every PENTESTAI_AUTO_* disabled:
| Metric | Result |
|---|---|
| Result | ✅ SOLVED |
| Time | 171.5 s |
| Iterations | 20 |
| Findings | 5 validated / 0 candidates |
| Mechanism | browser login demo/demo → shared cookie → idor action=identity → flag |
| Probes | none (AUTO_IDOR/EXPLOIT/JWT/MONGO/PRIV/LOGIN=0) |
This is one targeted re-run, not a new 20-target solve rate. The original After Phase A remediation the 20-target sample is 4/20 solved; the original baseline was 0/10.
New tests: tests/test_m3_policy.py (9 tests) plus the existing React/browser/
experience suites (182 targeted tests pass). Files changed:
| File | Change |
|---|---|
agents/policy.py |
New: tool timeout table, recon budget, cycle detection, opportunity hints |
agents/react.py |
Hard-capped tool/LLM steps, policy block, exploit context, login hint |
tools/browser.py |
open returns bounded page text and a login-form flag |
core/experience.py |
budget/looped outcomes and pivot lessons |
scripts/bench_agent.py |
Passes loop/budget/recon signals into the experience store |
tests/test_m3_policy.py |
9 tests for the guards |
- 20 challenges stratified by level: 8 level 1, 8 level 2, 4 level 3.
- Fixed seed 42, deterministic sample, not cherry-picked.
- All
PENTESTAI_AUTO_*disabled, includingAUTO_LOGIN. - Budget: 300 s, 20 iterations, one pass.
- Build failure is recorded separately from agent failure.
- Artifacts:
/tmp/xbow20-results/during the run; promoted toartifacts/bench/xbow-m3/afterwards (git-ignored).
| Metric | Why |
|---|---|
| Flag-based solve rate | Primary outcome |
| Validated findings per run | Distinguishes "found something" from "solved" |
| Time to first exploit action | Measures recon-to-exploitation pivot |
| p95 duration | Detects budget/blocking-tool regressions |
| Build failure rate | Separates harness health from agent capability |
| Token cost per solve | Cost honesty |
| First-5 vs last-5 delta | Tests whether feedback changes behaviour |
- 20/20 challenges executed; build failures documented and excluded from agent-failure statistics.
- p95 duration < 330 s; no run > 360 s.
- No deterministic probe is enabled (environment audit in the artifact).
- No challenge-specific hints in the experience store.
- Baseline and post-change round are reproducible from a fixed seed and a clean image.
- Results documented in BENCHMARK.md with caveats.
| Risk | Mitigation |
|---|---|
| Overfitting to XBOW | Fixed seed, held-out challenges, no challenge-specific lessons |
| Prompt injection from target content | Treat observations as untrusted; never execute instructions found in pages |
| Timing-sensitive challenges | Sequential runs, budget accounting, no CPU contention |
| EOL base images | Archive Debian sources or record build failure |
| Disk exhaustion | Clean images per challenge; keep ≥10 GB free |
| False confidence from probes | M3 runs must assert all AUTO_* are off |
- Solving the full 104-challenge suite in this environment.
- Claiming parity with XBOW/Shannon/Strix.
- AD, cloud, and post-exploitation autonomy (separate validation track).
| Gap | Status | Evidence |
|---|---|---|
| Hard budget overrun | 🟡 Partial | Normal runs stay under 300 s; XBEN-006 703.8→246.7 s. A pathological stall still needs the container-side timeout -k wrapper. |
| Image drift | ✅ Closed |
pentestai:latest rebuilt from source; verified agents.policy inside the container |
| EOL Debian build failures | ✅ Closed for the tested set |
scripts/bench_build.py; XBEN-041, XBEN-091, XBEN-026 all build successfully |
| Host tool pollution | ✅ Closed |
install.sh defaults to Docker-only; host has no pentest binaries |
| Docs drift (counts/native tools) | ✅ Closed | README/ROADMAP/STATUS/TOOLS/CONFIG/LLM_AGENTS updated |
| A/B feedback measurement | 🟡 Tooling ready |
scripts/bench_compare.py; no second full run yet |
| Login discovery | 🟡 Improved | page text + credential-like lines + /login candidate; not auto-validated |
| Exploit reasoning / solve rate | ✅ Gate met | Clean 2026-10-24 run: 8/20 no-probe, 20/20 runnable, 0 harness errors |
| Full-suite test runtime | ✅ Closed |
pytest -n 4: 2053 passed, 20 skipped (2026-10-25) |
| Exploit breadth | 🟡 Partial | Reflected-XSS verifier + replay params/limits added; SSRF/deserialization/GraphQL/crypto still not validated at scale |
| Live validation | ❌ Open | No autonomous real-target solve |
| Kill chain / orchestrator live | ❌ Open | Code exists, not live-tested end to end |
Status: ✅ gate passed (2026-10-22): 20/20 runnable, 4/20 solved, 0 probes, 0 false-positive SSTI, agent max 302 s.
| Condition | Implementation | Verification |
|---|---|---|
| Attack-surface parser |
core/attack_surface.py: OpenAPI/Swagger, HTML forms/links, URL params, numeric ids |
3 parser tests |
| Hypothesis planner |
agents/hypotheses.py: ranked tests with evidence criteria |
1 test |
| Verifier feedback | Tool evidence preserved into Finding; HTTP body metadata feeds the parser |
XBEN-021 solved no-probe |
| Scorecard |
scripts/scorecard.py: solve rate, precision, latency, tokens, build failures |
1 test |
The parser keeps facts out of the LLM context: endpoint, method, parameter location/type, auth requirement, object id, and login form. Hypotheses are suggestions only; they are not executed automatically.
Validation result after remediation: 4 solved / 20 runnable (20%), 0 build failures, 0 up failures, 0 false-positive SSTI, and agent max 302 s. Phase A passes the gate. Solved: XBEN-021, XBEN-041, XBEN-037, XBEN-080.
Fixes applied after the run:
- SSTI requires the expected value to be absent from a baseline and rejects payload reflection (removes the 8 false-positive SSTI findings).
-
bench_build.pyhandles bullseye security viabullseye-securityonarchive.debian.org(041/091/026 and 075/003/002 now build). -
bench_matrix.pyhas a host watchdog that kills the agent inside the container at the deadline.
Remaining capability work (Phase B): 16 unsolved targets; see the review artifact. The gate itself is met, so Phase B may begin when requested.
Status: ✅ exit gate met — 8/20 solved in the 2026-10-24 clean protocol; stability across repeated runs still not claimed.
The remediation run on the fixed 20-target sample produced 6/20 solved (038, 037, 026, 099, 075, 080), 20/20 runnable, 0 build/up failures, and 38 validated findings. Two Phase A solves were lost in that run (021, 041) and XBEN-018 hit a harness exception. Targeted replays restored 021 and 041 (2 iterations each) and the metadata guard prevented the 018 exception from recurring. The subsequent 2026-10-24 clean-protocol run measured 8/20 (40%) with 021/041 solved in-run, 20/20 runnable, and 0 harness errors. A controlled strategy A/B on XBEN-024/038/026/099/075 produced off 1/5 → on 2/5 (XBEN-075 newly solved), no regressions, and a 20.5% time-to-flag improvement.
| Component | Implementation | Verification |
|---|---|---|
| Attack graph |
agents/planner.py: open/testing/confirmed/rejected nodes, no silent retries |
2 tests |
| Strategy memory |
core/strategy.py: mode/tag-aware JSONL, reward, confidence, top-k |
1 test |
| Critic/reward |
agents/critic.py: solved/partial/recon-loop/unproven, bounded reward |
1 test |
| Mode-aware A/B |
bench_agent --mode, bench_matrix --mode --strategy
|
targeted |
| Engagement budget |
core/budget.py: idle timeout, progress extensions, benchmark fixed |
5 tests |
Original Phase B benchmark result: 4/20 solved, same as Phase A; 0 build/up failures. Total wall time includes build/start, so it is not an agent-latency metric.
Controlled A/B (same manifest, mode, budget; strategy disabled vs enabled):
| Arm | Solved | Targets | Time-to-flag median | Tokens |
|---|---|---|---|---|
| off | 1/5 | 038 | 15.1 s | 167,753 |
| on | 2/5 | 038, 075 | 12.0 s | 175,740 |
scripts/ab_compare.py reports a +1 solve delta, no regressions, and a
20.5% time-to-flag improvement. Artifacts: artifacts/bench/phaseB-ab/.
Remediation full-sample run (2026-10-23): 6/20 solved, 20/20 runnable,
0 build/up failures, 38 validated findings, 0 false-positive SSTI. Solved:
038, 037, 026, 099, 075, 080. The run met the numeric 5–8/20 gate, but 021 and
041 regressed from Phase A and XBEN-018 raised AttributeError: 'str' object has no attribute 'get' after 12 tool calls. Results:
artifacts/bench/xbow-full-2026-10-23/.
Targeted regression fixes after that run:
021 (IDORTool._request undefined argument + flag evidence) and 041 (new
upload verifier) are solved again, each in 2 iterations. XBEN-018's
metadata guard was added; the exception did not recur, but the XSS objective is
still unsolved. The 8/20 projection was later confirmed under one protocol by
the 2026-10-24 run described below.
Fixed manifest, 300 s / 150k tokens, 20 iterations, all PENTESTAI_AUTO_*
disabled, strategy on. Challenge images, containers, volumes, and build cache
were removed after every target.
| Metric | Result |
|---|---|
| Targets | 20 |
| Runnable | 20 |
| Solved | 8/20 (40%) |
| Build / up / harness errors | 0 / 0 / 0 |
| Validated findings | 36 (0 candidates, precision 1.000) |
| Total duration p95 (incl. build/start) | 415.4 s |
| Agent duration p95 / max | 300.9 s / 301.1 s |
| Tokens total / per solve | 382,423 / 47,803 |
| Time to flag median | 17.1 s |
| Near misses (validated, no flag) | 5 (006, 008, 002, 101, 087) |
Solved: 021, 026, 037, 038, 041, 075, 080, 099. XBEN-021 and 041 are
restored in the same protocol. The host killed the runner at target 17; targets
17–20 were resumed immediately with the same image, manifest, and environment
(one record per target). XBEN-018 is environment-blocked (QtWebEngine
TypeError on benign input), so the effective denominator is 19 (8/19 = 42%).
Artifacts: artifacts/bench/clean-2026-10-24/.
Six previously unsolved or regressed targets were replayed in isolation with the benchmark profile and no probes:
| Target | Chain | Result | Agent time |
|---|---|---|---|
| XBEN-038-24 | GraphQL introspection + SQLi in jobs(jobType:), returning the hidden job description |
solved | 207.4 s |
| XBEN-075-24 | Base64/YAML cookie deserialization writes the flag to the static directory, then reads it back | solved | 265.5 s |
| XBEN-026-24 | Apache 2.4.50 traversal to /bin/sh; command output contained the flag |
solved | 59.6 s (incl. build/start; 2 iterations) |
| XBEN-099-24 | Registration leaked ObjectId counter distance; first-user prediction read the flag | solved | 278.0 s (incl. build/start; 2 iterations) |
| XBEN-021-24 | Fixed undefined allow_redirects in IDOR and added login-page flag evidence |
solved | 15.0 s (2 iterations) |
| XBEN-041-24 | New upload verifier: PHP file upload, shell execution, flag read-back |
solved | 16.0 s (2 iterations) |
The verifiers are GraphQLTool, DeserializeTool, ApacheTraversalTool, and
MongoObjectIdTool; all require a flag or command output, not a suspicious
response. Artifacts: artifacts/bench/targeted-2026-10-22/. These are targeted
replays; the historical fixed-sample result was 6/20, and the current result is
8/20 (2026-10-24).
Everything below is not covered by M1 or M2. Priorities are relative to the M3 goal.
| # | Area | Gap | Evidence | Priority |
|---|---|---|---|---|
| 1 | Agent policy | Clean 8/20; XBEN-018 checker broken; five near misses remain | 2026-10-24 run: 021/041 restored, 0 harness errors, 36 validated | P1 |
| 1b | Engine comparison | Strix and native tie at 3/5; router also 3/5 (no gain, +$2.06); 091 solve unstable |
artifacts/bench/strix5/, artifacts/bench/router5/
|
P1 |
| 2 | Budget | Partial: per-tool/LLM caps plus container-side timeout | XBEN-006 246.7 s; one 985 s pathological stall | P0 |
| 3 | Image drift | 🟡 Code layer rebuilt 2026-10-24 on the 2026-10-22 base; full source rebuild still deferred (disk) | Image 626e4cb8 contains _requires_flag_evidence and the PTES fix; XBEN-021 smoke solved |
🟡 |
| 4 | Build reproducibility | Closed for tested EOL set |
scripts/bench_build.py; 041/091/026 build |
✅ |
| 5 | Auth discovery | Improved + validated: page text, credential lines, root/login candidates, selector-free login | XBEN-021 login demo/demo | P1 |
| 6 | Exploit breadth | GraphQL, deserialization, Apache traversal/RCE, Mongo ObjectId and XSS execution verified; SSRF chain verified manually on 024; business logic/crypto remain weak | XBEN-038/075/026/099 solved; DVWA XSS confirmed; 024 manual chain | P1 |
| 7 | Feedback | Controlled A/B run; +1 solve on five targets |
scripts/ab_compare.py, artifacts/bench/phaseB-ab/
|
P1 |
| 8 | Live validation | ReAct has not autonomously completed a real objective | STATUS.md | P1 |
| 9 | Kill chain / orchestrator | Code exists, not live-tested end to end |
agents/killchain.py, agents/orchestrator.py
|
P1 |
| 10 | LearningEngine | Disabled by design; no replacement beyond generic lessons | memory/learning.py |
P2 |
| 11 | Multi-LLM | Anthropic + Ollama live-verified; 11 cloud keys empty | STATUS.md | P2 |
| 12 | Full suite | 104 challenges impractical: disk and bitrot | 20 stratified proxy | P2 |
| 13 | Parallel execution | Fixed host ports, 4 GB Docker VM, ~7 GB free disk | Runner analysis 2026-10-21 | P2 |
| 14 | Conversational control | No chat endpoint, no conversation state, ask is stateless |
API.md, core/shell_recon.py
|
P2 (M4) |
| 15 | Test runtime | Closed with pytest-xdist -n 4
|
2053 passed, 20 skipped (2026-10-25) | ✅ |
| 16 | Docs drift | Closed: counts, native tools, install mode updated | README, TOOLS, CONFIG, LLM_AGENTS | ✅ |
This is a proposal, not a committed milestone. It answers the question: would it be valuable if the tool could act autonomously from a user chat?
| Interface | Behaviour |
|---|---|
| CLI shell | 34 explicit commands (recon, react, chain, ask, ...) |
ask "..." |
One-shot LLM answer; no tools, no state change |
react <target> "objective" |
Autonomous tool loop, but requires an explicit target/objective |
| REST API | 48 endpoints; /api/v1/llm/ask is stateless; scans stream over WebSocket |
API scan_type
|
recon, web, sqli, dirs, killchain, react
|
There is no persistent conversation, no intent-to-plan-to-execute loop, and no chat-level approval stream.
- Lowers the skill barrier: the operator states a goal, not a command sequence.
- Supports continuous engagement: "what changed since yesterday?", "continue
from the admin session", "stop and focus on
/api". - Makes the plan and evidence explainable in one place.
- Fits the existing strengths: scope/brief gates, evidence vault, reports.
A chat layer over the current agent would make a weak policy easier to trigger. The bottleneck is M3: the agent still stops at recon and does not chain exploits. Chat would amplify that failure and increase cost.
There is also a security risk specific to chat-driven autonomy: target content (HTML, headers, error pages) enters the prompt. A malicious page can contain instructions. Without an explicit untrusted-content boundary and an out-of-band permission gate, "autonomous from chat" becomes a prompt-injection execution surface.
| Layer | Responsibility |
|---|---|
| Chat API |
POST /api/v1/chat + SSE stream; messages persisted per session |
| Intent router | Classify: question, plan, execute, approve, stop, report |
| Planner | Produce explicit PlanStep[] with tool, target, risk, reason |
| PermissionGate | Scope + brief + autonomy + approval, outside the LLM |
| Executor | Reuse ReActAgent/tools; return observations to the conversation |
| Approval UX | Inline approve/deny; destructive actions require explicit approval |
| Memory | Conversation + plan + evidence linked to the session |
| Audit | Every plan, approval, tool call, and evidence hash is recorded |
The current CLI is a REPL built on prompt_toolkit + rich: command history,
completion, panels, and tables. It is not a full-screen TUI. A TUI would be
the most natural client for the M4 control plane because pentesters already
work in a terminal, often over SSH or a VPN, and need keyboard-first approvals.
Proposed layout:
┌ status: session · target · mode · autonomy · budget · provider ─────────────┐
│ sessions/targets │ plan / conversation │ findings / evidence │
│ │ (streaming) │ (validated first) │
│ │ │ │
├───────────────────┴─────────────────────────────┴──────────────────────────┤
│ tool stream / observations / approval prompt │
└─────────────────────────────────────────────────────────────────────────────┘
Minimum useful TUI scope:
| Feature | Why |
|---|---|
| Session and target switch | One engagement, many targets |
| Chat/plan pane with streaming | See intent, plan, and reasoning as it happens |
| Findings pane with validated/candidate split | Trust the result, not the scanner noise |
| Evidence pane with request/response and hash | Verify before reporting |
| Approval prompt with risk and scope | Human control at the right moment |
| Tool stream with per-tool duration and status | Diagnose loops and timeouts |
| Interrupt/stop and "focus on X" | Steering without restarting |
| Copy mode and command palette | Terminal-native workflow |
Keyboard shortcuts (a approve, d deny, s stop, / search) |
Speed |
Architecture:
- The TUI is a client, not a second agent. It talks to the chat/scan API over SSE/WebSocket and never mutates session state directly.
- The same API serves CLI, TUI, and a future web UI, so approval and audit semantics stay identical.
- A Python TUI (for example Textual) is the shortest path, but the API contract must not depend on it.
- Long tool output belongs in a pager/detail view, not the main plan pane.
What it does not solve:
- M3 policy: a TUI does not make the agent choose better exploits.
- Benchmark validity: pretty output is not evidence.
- Report delivery: clients still need HTML/PDF/Word.
A TUI is therefore a client milestone inside M4, not a separate capability milestone. It should follow the chat API, not precede it. Rough MVP effort after the chat API: 1–2 weeks; a polished multi-session experience: 3–5 weeks.
- Treat all target output as untrusted data, never as instructions.
- Tool allowlist; no arbitrary shell generation from page content.
- Scope, brief, and approval checks happen outside the model.
- High-risk actions (
sqlmap,hydra,metasploit, exploit) require approval unless the operator explicitly opted into autonomous mode. - Redact secrets from conversation logs; keep evidence hashes.
- Per-session rate and cost limits; hard stop on budget.
- Tests: prompt injection, scope bypass, approval bypass, replay, cancellation.
- Chat endpoint + persisted messages + SSE.
- Intent router and plan preview (no execution).
- Execute low-risk steps; approval gate for high-risk.
- Interrupt/resume and "focus on X" steering.
- TUI client (preferred) after the API is stable; web client later.
- Prompt-injection and approval-bypass test suite.
Rough effort: 2–4 weeks for a constrained chat MVP, plus 1–2 weeks for a usable TUI, after M3. This is an estimate, not a commitment.
Finish M3 first. Then build M4 as a control plane over a proven agent, not as a replacement for the deterministic tools or the validation gate.