# Aegis Pentest

> AI-driven pentest orchestration that hands Claude the full PTES methodology over real MCP tool calls. 80+ tools, 33 verification probes, scope guard on every request. Python orchestrator + React/Ink TUI.

- **Type:** MCP server
- **Install:** `agentstack add mcp-glorybnat-aegis-pentest`
- **Verified:** Pending review
- **Seller:** [glorybnat](https://agentstack.voostack.com/s/glorybnat)
- **Installs:** 0
- **Category:** [AI & ML](https://agentstack.voostack.com/c/ai-and-ml)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [glorybnat](https://github.com/glorybnat)
- **Source:** https://github.com/glorybnat/aegis-pentest
- **Website:** https://aegis-pentest.vercel.app

## Install

```sh
agentstack add mcp-glorybnat-aegis-pentest
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# aegis · v0.12.0

**Adaptive Engagement & Generic Inspection Scanner**

An autonomous, AI-orchestrated web penetration testing agent. Aegis handles reconnaissance, fingerprinting, vulnerability discovery, verification, and reporting so the human pentester focuses on what actually requires human judgment.

---

## What it is

Aegis runs structured, methodology-driven engagements against web targets. It profiles the host environment, fingerprints the target stack, selects relevant tools and tests from the PTES + OWASP WSTG v4.2 playbook, executes them concurrently, and produces a verified findings report with remediation guidance.

It is not a Burp Suite replacement. It is the autonomous recon and vuln-discovery layer that feeds the human pentester, eliminating roughly 70% of routine busywork.

**Hard constraints built into the runtime:**

- Every engagement requires a signed `scope.yaml` before any network egress.
- Every outbound request is matched against in-scope and out-of-scope rules before the socket opens.
- Scope violations abort the current task and are written to the audit log.
- Destructive tools (`sqlmap`, `wpscan`, `commix`, `kerbrute`, `crackmapexec`, …) refuse to run without operator approval unless `scope.yaml` explicitly enables them.
- There is no `--force` flag that bypasses scope.

---

## Installation

### Option A — Docker (recommended, all tools pre-installed)

```bash
# Pull pre-built image (~4 GB) or build locally (~15-30 min)
aegis docker pull                          # from GitHub Container Registry
# OR
aegis docker build                         # build locally from Dockerfile

# Run an engagement
export ANTHROPIC_API_KEY=sk-ant-...
aegis docker run engagements/2026-acme

# Interactive shell with every tool on PATH
aegis docker shell

# Check image status and tool inventory
aegis docker status
```

The Docker image is based on **Kali rolling** and includes every tool in the catalog.

### Option B — PyPI

```bash
pip install aegis-pentest
# or
pipx install aegis-pentest
```

### Option C — Arch (AUR)

```bash
yay -S aegis-pentest
# or
paru -S aegis-pentest
```

Optdepends cover the full tool surface; install only what you need.

### Option D — Native install script (one-liner)

```bash
# Auto-detects Arch, Kali, Ubuntu/Debian, Fedora, macOS
curl -fsSL https://raw.githubusercontent.com/glorybnat/aegis-pentest/main/scripts/install.sh | bash

# Or from the repo
bash scripts/install.sh

# Build Docker image instead
bash scripts/install.sh --docker
```

### Option E — From source

```bash
git clone https://github.com/glorybnat/aegis-pentest.git
cd aegis-pentest
pip install -e .
cd tui && npm install && npm run build
```

After installing AEGIS, detect what's already on the host and fill in the rest:

```bash
aegis init                          # detect what's installed
aegis env tools --missing           # show what's missing + install commands
aegis env install --missing         # install everything (no-sudo tools)
aegis env install --missing --dry-run   # preview first
```

**Requirements:**

- Python 3.12+
- `ANTHROPIC_API_KEY` in environment
- Docker (Option A) or pentest toolchain (Option B–E)

---

## Quickstart

```bash
# Docker quickstart (zero host setup)
export ANTHROPIC_API_KEY=sk-ant-...
aegis docker build                          # or: aegis docker pull
aegis docker run engagements/2026-acme

# Native quickstart
# First run: profiles host, lists missing tools
aegis init

# Sync the knowledge base (NVD, GHSA, nuclei-templates, CISA KEV, FIRST EPSS)
aegis kb sync

# Create a new engagement
aegis engagement new --client "Acme Corp" --domain "acme.com"

# Fill in the authorization details
vim engagements/2026-05-acme/scope.yaml

# Optional: seed endpoints from an existing API spec or proxy trace
aegis ingest openapi engagements/2026-05-acme/spec.yaml --engagement engagements/2026-05-acme
aegis ingest postman engagements/2026-05-acme/collection.json --engagement engagements/2026-05-acme
aegis ingest har     engagements/2026-05-acme/burp.har       --engagement engagements/2026-05-acme

# Run
aegis run engagements/2026-05-acme

# Resume from the last completed phase after a crash or Ctrl+C
aegis run engagements/2026-05-acme   # picks up state.json automatically

# Generate report — md/html/json/sarif/h1/bugcrowd, or "all"
aegis report engagements/2026-05-acme --format html
aegis report engagements/2026-05-acme --format sarif    # GitHub/GitLab code scanning
aegis report engagements/2026-05-acme --format h1       # HackerOne JSON, one per finding
aegis report engagements/2026-05-acme --format bugcrowd # Bugcrowd VRT bundle
```

---

## scope.yaml

Aegis refuses to run without this file. No exceptions.

```yaml
engagement_id: "BL-2026-007"
client: "Acme Corp"
operator: "Majd Bnat "
authorization:
  document_ref: "SOW-2026-007.pdf"
  signed_date: "2026-05-12"
  expiry: "2026-06-12"
in_scope:
  domains:
    - "*.acme.com"
    - "api-staging.acme.io"
  ips:
    - "203.0.113.0/24"
out_of_scope:
  - "admin.acme.com"
  - "*.internal.acme.com"
rules_of_engagement:
  rate_limit_rps: 10
  business_hours_only: false
  destructive_tests: false
  no_credential_stuffing: true
  no_dos_tests: true
  confirm_before:                  # per-engagement gate for destructive tools
    - sqlmap
    - hydra
    - commix
```

---

## Architecture

```
                          aegis CLI
                              |
                      Engagement Manager
           (scope validation, lifecycle, audit log)
                              |
            +-----------------+-----------------+
            |                 |                 |
        Environment         Target          Methodology
         Profiler          Profiler           Engine
       (host info)      (fingerprint)      (PTES phases)
            |                 |                 |
            +--------+--------+--------+--------+
                              |
                       LLM Orchestrator
                   (Haiku / Sonnet / Opus)
                              |
         +----------+---------+----------+----------+
         |          |         |          |          |
        Tool    Knowledge  Findings    PTT       PoC
      Registry    Base       DB      Graph    Generator
     (173 tools) (NVD/GHSA  (SQLite) (aiosqlite) (14 types)
                +KEV/EPSS)
         |                              |
   Tool Executor               Hallucination Guard
  (async, sandboxed,          (output verification)
   destructive-gated)
         |
      Reporter
    (md/html/json/sarif/h1/bugcrowd)
```

The orchestrator runs a bounded loop per phase:

```
plan(phase_context) -> execute(action) -> observe(result) -> update(state)
  ^                                                               |
  +---------------------------------------------------------------+
                   until phase complete OR budget exceeded
```

Three independent budgets bound each phase: token budget, wall-clock time, and action count. Whichever trips first ends the phase and triggers finalize mode.

State is persisted to `/state.json` after every phase advance via atomic `tmp + os.replace`. Re-running `aegis run` against the same directory resumes at the last saved phase.

---

## Reasoning engine

v0.12 repositions AEGIS from "tool dispatcher" to "brilliant bug-hunting partner". The agent reads observations, opens a structured theory, dispatches probes to test it, and writes a self-critique before advancing. The OOHA loop is the spine:

| Step | Meaning |
|---|---|
| **OBSERVE** | Read the new observations, the Open hypotheses block, and the Suggested-next block. What's actually new? |
| **ORIENT** | Where in the kill chain am I? What's the highest-impact primitive within reach? |
| **HYPOTHESISE** | Before dispatching a tool, `propose_hypothesis` with a one-paragraph rationale. If an open hypothesis matches, `update_hypothesis` with new evidence instead. |
| **ACT** | Dispatch `run_tool` / `aegis_verify` in **batches** — independent calls run in parallel. |
| **CRITIQUE** | Once per phase, `self_critique` — what assumption am I making that I haven't tested? Which open hypotheses are dead ends? |

Four reasoning verbs land in `PLAN_TOOLS` and bypass the per-phase enum filter (the agent reasons at every phase, not just `VULN_ANALYSIS`):

| Verb | Use |
|---|---|
| `propose_hypothesis(target, vuln_class, rationale)` | Open a structured theory before dispatching tools. Dedupes on `(target, vuln_class)` so repeated calls return the existing row. |
| `update_hypothesis(id, status, evidence_for, evidence_against)` | Append evidence; transitions to `CONFIRMED` auto-write a `Finding` (with severity inferred from `vuln_class`) so chain detection fires immediately. |
| `mark_dead_end(id, reason)` | Retire a theory permanently — keeps the suggester from re-surfacing it. The reason lands as `evidence_against` on the row. |
| `self_critique(reflection)` | Free-form reasoning persisted as a `reasoning_trace` audit event. The sanctioned "scratchpad" — no DB side-effect beyond the log. |

The Hypothesis lifecycle is `PROPOSED → TESTING → CONFIRMED | REFUTED | DEAD_END`. Open hypotheses are injected back into the observation summary every turn so the agent sees its own working theory across turns.

**Parallel dispatch.** Non-control tool calls in a single turn now run concurrently via `asyncio.gather`, capped by a per-runner semaphore (defaults to `executor.max_parallel_tools`, falls back to 4). Control verbs — `advance_phase`, `change_phase`, `abort` — stay serial so the orchestrator can short-circuit. One crashing dispatch never kills the rest of the batch.

**Structured failure signals.** `_recent_calls` was `dict[(tool, target), int]` carrying "failed N times". It's now `dict[(tool, target), FailureSignal]` with an 8-kind classifier (`TIMEOUT`, `RATE_LIMITED`, `PERMISSION_DENIED`, `AUTH_REQUIRED`, `OUT_OF_SCOPE`, `BINARY_MISSING`, `ZERO_RESULTS`, `EXCEPTION`) and an attacker-flavoured pivot hint per kind:

- `rate_limited` → use `aegis_verify` in-process; it's not rate-limited
- `auth_required` → ingest the captured Burp/ZAP HAR with cookies via `aegis ingest har --replay`
- `binary_missing` → `aegis env install --missing`, or `aegis_tool_list_help ` for equivalents

The `STUCK SIGNALS` block in the observation summary renders kind + count + pivot, most-recent-first, capped at 5.

---

## Attack chain detection

Findings carry structured tags. The chain detector matches on tag sets, not title substrings. 25 chains ship out of the box — 7 legacy web chains, 10 modern web/API chains, 5 Active Directory chains, and 3 v0.12 high-ROI gaps (host header, web cache deception, parameter pollution):

| Chain | Severity | Predicate (tag groups) |
|---|---|---|
| Account takeover via CORS + JWT | critical | `cors_wildcard` + jwt-family |
| Stored XSS + CSRF = session hijack | critical | `xss_stored` + `csrf` |
| SQL injection + weak crypto | critical | `sqli` + `weak_crypto` |
| SSRF + internal service exposure | high | `ssrf` + cloud/internal |
| SSRF + cloud metadata v1 | critical | `ssrf` + `cloud_metadata_v1` |
| Mass assignment + admin endpoint | critical | `mass_assignment` + `admin_endpoint` |
| Open bucket + reachable Lambda | high | `bucket_open` + `lambda_invoke` |
| Request smuggling → auth header bypass | critical | `request_smuggling` + `auth_header` |
| Cache poisoning → auth bypass | critical | `cache_poisoning` + `auth_cookie` |
| Prototype pollution → RCE sink | critical | `prototype_pollution` + `dangerous_sink` |
| JWT alg-confusion → privilege escalation | critical | `jwt_alg_confusion` + `privileged_endpoint` |
| Exposed `.git` → source code disclosure | high | `git_exposure` |
| Open registration + IDOR | high | `open_registration` + `idor` |
| Race condition → auth bypass | high | `race_condition` + auth |
| Kerberoasting → service account compromise | high | `ad_kerberoast` + `ad_spn` + weak/service |
| AS-REP roasting | high | `ad_no_preauth` + weak/user |
| DCSync → full domain compromise | critical | `ad_dcsync` + any AD creds |
| AdminSDHolder ACL backdoor | critical | `ad_adminsdholder` + any AD creds |
| Unconstrained delegation → ticket forge | critical | `ad_unconstrained` + any AD creds |
| Host Header Injection → Cache Poisoning | critical | `host_header_injection` + `cache_poisoning`/`redirect_open` |
| Web Cache Deception → Auth Token Leak | high | `web_cache_deception` + `auth_cookie`/`auth_header` |
| HTTP Parameter Pollution → Auth Bypass | high | `http_parameter_pollution` + `auth_bypass`/`idor`/`mass_assignment` |

For engagements predating the tag rollout, a substring fallback still fires the legacy 7 rules against finding titles.

---

## Guided hunting

Chains are post-hoc detection — they fire when findings are already in the DB. Playbooks are the proactive counterpart: 28 entries in `src/aegis/analysis/vuln_playbooks.py` say "when you suspect X, run these probes; when you confirm X, hunt Y next".

| Field | Meaning |
|---|---|
| `vuln_class` | one of the `TAG_*` constants from `chains.py` |
| `severity_floor` | `critical` / `high` / `medium` / `low` / `info` |
| `preconditions` | state predicates (`has_params`, `has_login`, `has_jwt`, …) |
| `probes` | concrete `(tool_name, args_template, rationale)` tuples |
| `confirm_chain` | the `ChainRule.name` this playbook ultimately feeds, if any |
| `follow_ups` | other vuln classes to hunt next when this one fires |

Initial set (one playbook per chain tag):

`sqli`, `nosqli`, `cmdi`, `ssti`, `xxe`, `xss_stored`, `xss_reflected`, `ssrf`, `lfi`, `cloud_metadata_v1`, `bucket_open`, `request_smuggling`, `cache_poisoning`, `prototype_pollution`, `jwt_alg_confusion`, `jwt_weak_secret`, `csrf`, `idor`, `race_condition`, `mass_assignment`, `git_exposure`, `cors_wildcard`, `ad_kerberoast`, `ad_no_preauth`, `ad_dcsync`, `host_header_injection`, `web_cache_deception`, `http_parameter_pollution`.

After every phase tick, `EngagementRunner._suggested_next` builds an escalation state from confirmed findings (tags + endpoints + tech stack) and runs `adaptive.escalate`. The top three actions are injected into the next observation summary as a `Suggested next probes` block; the model can act on them or ignore. Either way the recommendation is logged to `audit_event` with `event_type='escalation_suggested'` so `aegis stats` can answer "how often did the model take the suggestion?".

Tag inference (`src/aegis/analysis/tag_inference.py`) runs at the persistence boundary inside `FindingsDB.add_finding`. Findings get tags from a tool-base map (e.g. `impacket_get_userspns` → `[ad_kerberoast, ad_spn]`) plus a 31-rule substring matcher over the title + evidence text (distinguishing `jwt_alg_confusion` from `jwt_weak_secret`, `xss_stored` from `xss_reflected`, IMDSv1 in payloads tagging `cloud_metadata_v1`). Explicit tags from the caller are preserved.

**Lateral pivots (v0.12).** `src/aegis/reasoning/lateral.py` encodes the post-confirmation question every brilliant bug hunter asks: "given primitive X, what NEW classes does it unlock?" 10 hand-curated rows cover the highest-leverage chains — SSRF → IMDS → IAM → S3 → credential pivot; SQLi → file read via INTO OUTFILE → log poisoning → RCE; .git exposure → source review → JWT secret extraction → forge any token. Every confirmed primitive auto-proposes one hypothesis per unlocked class (`proposed_by="lateral:"`) so the agent sees concrete next probes already framed as "given X, hunt Y because…".

**Partial-chain primers (v0.12).** Most chains need 2–3 required tag groups. When one group matches but at least one is missing, `chains.partial_matches()` returns the near-miss; the orchestrator surfaces them in the obs summary as `PARTIAL CHAINS (one probe away)` with what we have and what's missing — the agent sees concrete one-probe-away opportunities without an LLM planning call.

---

## Token model

Aegis is designed to complete a full medium-scope e

…

## Source & license

This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [glorybnat](https://github.com/glorybnat)
- **Source:** [glorybnat/aegis-pentest](https://github.com/glorybnat/aegis-pentest)
- **License:** MIT
- **Homepage:** https://aegis-pentest.vercel.app

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: flagged — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/mcp-glorybnat-aegis-pentest
- Seller: https://agentstack.voostack.com/s/glorybnat
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
