This release includes 3 security fixes for security teams reviewing exposed deployments.
Topics
+12 more
Affected surfaces
Summary
AI summaryUpdates Added — Agent-loop foundation, Added — SPA-aware probes, and new across a mixed release.
Full changelog
Major release. New offensive-security probes, CVE intelligence, agent-loop scaffold, plus the launch-prep work staged on May 2.
Added — SPA-aware probes (14 deterministic checks)
-
JWT alg=none acceptance (
agents/web/spa_probes.py:probe_jwt_alg_none). Two-step: anonymous GET, then GET with an unsigned JWT. If the second succeeds, the validator is honouringalg=none. On Juice Shop 19.2.1 this catches 8 separate critical bypasses across/api/Users,/api/SecurityAnswers,/api/PrivacyRequests,/api/BasketItems,/api/Complaints,/rest/admin/application-configuration,/rest/user/whoami,/api/Challenges. -
JWT alg variants (
probe_jwt_alg_variants). Tests case + whitespace + array + missing-alg variants. Reports only on endpoints where canonical lowercase'none'was rejected, so the count is not inflated. -
SQLi auth bypass on login (
probe_login_sqli_bypass). POSTs a tautology payload in the email field. Detects the canonical Sequelize-bug shape that returns 200 + a token-shaped response. -
GET-method SQLi on search (
probe_search_sqli_get). Two-step response-size diff: baseline?q=applevs UNION payload. 3.0x size ratio with HTTP 200 = critical. -
Path-filter bypass via poison null byte (
probe_ftp_leak). Two-stage: direct GET to/ftp/<file>vs URL-encoded NUL bypass/ftp/<file>%2500.md. Catches the canonical Expressserve-indexfilter defect. Pulls dependency manifests (package.json.bak) and other backup files. -
Authenticated pivot (
probe_authenticated_pivot). Captures an admin JWT from the SQLi login bypass, then re-tests every 401-anon endpoint with the captured token. The autonomous-agent move: a finding becomes the input to the next probe. On Juice Shop unlocks 9 protected endpoints. -
Open redirect (
probe_open_redirect). 10 redirect paths × 12 parameter names. Sentinel host with substring match on theLocationheader. -
REST resource enumeration (
probe_user_enum,probe_unauth_rest_leak). User-shape detection plus generic 200+JSON-without-auth detection across 19 Sequelize/Express scaffold paths. -
Source-map disclosure, directory listing, dev/admin interface leak (probes 4 to 6).
Added — CVE intelligence
engine/cve_db.py: osv.dev batch API wrapper. Parses npmpackage.jsonandpackage-lock.json(v1, v2, v3 lockfiles) into(name, version)tuples and looks them up against the live osv.dev advisory database. When a leaked manifest comes throughprobe_ftp_leak, the engine auto-correlates and emits per-packageVulnerable dependencyfindings tagged with their GHSA identifiers.
Added — Agent-loop foundation (v0.11 autonomous-agent rebuild, phase 1 + 2)
-
engine/working_memory.py: per-engagement state object. Coverage matrix tracks(endpoint, bug-class)pairs the loop has tried. Captured-auth store for in-memory tokens. Pattern export refuses without explicitcross_engagement_shareopt-in. Privacy-by-design enforced by tests. -
engine/agent_loop.py: Action / Observation / LLMAgent protocol, handler registry,run_agent_loopdriver. LoopConfig pins safety: max_iterations, coverage_threshold, min_iterations_before_finish. -
engine/agents/anthropic_agent.py: LLMAgent backed by the Anthropic Messages API. Renders state + handler list, parses Claude's JSON action response, falls back tofinishon malformed output. -
engine/agents/handlers/web_probes.py: three SPA probes wrapped as agent-loop handlers (probe.jwt_alg_none,probe.sqli_login,probe.ftp_leak). Imported on agent-mode dispatch, registers automatically. -
ptai start --agent-mode(cli/main.py). New flag routes the engagement through the agent loop instead of the legacy fixed pipeline. Default behaviour unchanged.
Added — earlier launch-prep work (May 2 staging)
-
PTAI_PRICE_LIMIThard budget cap (engine/llm/cost.py,engine/orchestrator.py). SetPTAI_PRICE_LIMIT=5.00(or any float in USD) and the orchestrator raisesCostLimitErrormid-run as soon as accumulated LLM spend crosses the threshold. The cap is enforced insideCostTracker.add()so it fires even on cached responses. If no limit is set the engine runs uncapped as before. -
Process registry with
ptai psandptai kill(engine/process_registry.py,cli/main.py,mcp_server/server.py). Every tool process spawned throughToolRunneris registered in an in-memory table keyed on PID with command, start time, and engagement context.ptai psprints a formatted table.ptai kill <pid>terminates the process and removes it from the registry. Also exposed aslist_processesandkill_processMCP tools so MCP clients can manage long-running scans from the tool-use layer. -
SelectionAgentheuristic router (agents/selection/selection_agent.py,cli/main.py,mcp_server/server.py). Routes a target string to the best-fit agent without an LLM call. Heuristics run in order: intent keyword matching → URL/path pattern → file extension → cloud service indicators → AD/Kerberos keywords → IP/CIDR/domain regex → fallback to WebAgent. Returns{"target", "agent", "reason", "confidence"}. Exposed asptai route <target> [--intent <hint>] [--json]and as theselect_agentMCP tool. -
Public legal documentation suite (
docs/legal/). New or strengthened markdown that mirrors the live pages atpentestai.xyz/{privacy,terms,aup,cookies,subprocessors,security}:PRIVACY.md— GDPR Article 6 legal bases, 72-hour breach notification SLA, CCPA/CPRA disclosures, 2021 EU SCCs Module 2 with UK Addendum and Swiss FDPIC supplements.TERMS.md— liability cap, indemnification, dispute resolution options, sanctions and export controls, beta features clause.AUP.md(new) — shifts authorization-to-test responsibility to the user; defines prohibited targets and conduct; abuse-handling SLA and indemnification position.DPA.md(new) — GDPR Article 28 template with Annex I, II, III.SUBPROCESSORS.md(new) — vendor table with 30-day change-notice mechanism.COOKIES.md(new) — cookie inventory, banner consent flow, and GPC signal compliance.RESPONSIBLE_DISCLOSURE.md(new) — public security policy with safe harbor.
Security
-
ProcessRegistry.kill()refuses unregistered PIDs. The original implementation fell through toos.kill(pid, signal.SIGTERM)for any live PID, even one not spawned by ptai. An attacker who could write a valid integer to the registry endpoint could have sent SIGTERM to arbitrary processes. Fixed by returningFalseimmediately whenregistry.get(pid)isNone. Testtest_kill_refuses_unregistered_live_pidspawns a realsleep 30without registering it and asserts both thatkill()returnsFalseand the process is still alive after the call. -
Chain noise filter. The exploit chainer used to fabricate chains from any list of findings, including nikto error strings. Fixed:
agents/exploit_chain/chain_agent.pynow drops scanner-noise findings before chain generation and refuses to fire on fewer than 2 medium-or-higher findings. -
Evidence-gated chain validation.
agents/poc_validator/poc_agent.pynow updatesfindings.poc_statusandattack_chains.statusbased on whether each chain step has corroborating evidence on the finding row.
Changed
-
--no-llmis now an explicit opt-in.ptai startused to silently fall back to deterministic mode when no LLM provider was configured. Now non-interactive runs without--no-llmAND without an LLM provider exit with code 3 and a clear message. ptai is LLM-driven by default; the deterministic path is opt-in. -
Tagline corrected on
cli/main.py,docs/index.html,docs/index.md. The previous "Most autonomous pentesting AI on the market" claim was not defensible against CAI's HackTheBox CTF wins or HexStrike's adoption numbers. Replaced with concrete capability copy. -
CostLimitExceeded→CostLimitErrorto comply withruffrule N818 (exception class names must end inError). Renamed acrossengine/llm/cost.py,engine/orchestrator.py, andtests/test_cost_tracker.py. Any code that caughtCostLimitExceededby name must be updated toCostLimitError.
Breaking Changes
- --no-llm is now an explicit opt‑in; runs without LLM provider or the flag exit with code 3
- CostLimitExceeded exception renamed to CostLimitError
Security Fixes
- ProcessRegistry.kill() now refuses to terminate unregistered PIDs preventing arbitrary process termination
- `agents/exploit_chain/chain_agent.py` drops scanner‑noise findings before chain generation
- `agents/poc_validator/poc_agent.py` gates chain validation on corroborating evidence
Weekly OSS security release digest.
The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.
No spam, unsubscribe anytime.
Share this release
About pentest-ai
Offensive-security MCP server with 205 wrapped tools, 17 specialist agents, and 60 SPA-aware probes for OWASP Top 10. CLI + MCP, BYO LLM. No API key needed on MCP path.
Related context
Related tools
Beta — feedback welcome: [email protected]