AttackSim's CVE pipeline automatically resolves discovered services to known CVEs, generates PoC verification scripts (using builtin templates or a local LLM), executes them in a sandboxed subprocess, and surfaces confirmed vulnerabilities through an interactive triage interface. This uses a hybrid online+offline approach (NVD API with local cache fallback) and is opt-in.
# Look up CVEs for discovered services (banner → CPE → NVD feed):
python3 main.py 10.0.0.5:22,80,6379 --cve-lookup
# Also generate and execute harmless PoC scripts to confirm vulnerabilities:
python3 main.py 10.0.0.5:22,80,6379 --cve-lookup --cve-test --scope 10.0.0.5
# Increase plan cap and supply an NVD API key for higher rate limits:
python3 main.py 10.0.0.5:22,80,6379 --cve-lookup --cve-test --cve-max 20 --cve-api-key YOUR_KEYMaps product+version banners (from nmap-probe, port-probe, unauth-service-probe, etc.)
to CPE identifiers using a bundled 86-product alias table
(data/cve/cpe_aliases.json), then queries NVD or falls
back to the offline data/cve/feed.json cache.
- Internet-reachability pre-check (HTTP 200/400/403/429 all treated as "reachable")
- Retry logic: 3 attempts, 10-minute wait between retries
- Graceful fallback to offline feed when NVD is unreachable
Prioritises resolved CVEs by EPSS × CVSS score and assigns the safest viable test strategy:
| Strategy | Condition | Confirmation needed? |
|---|---|---|
nuclei_template |
Web CVE with known template CWE (path traversal, SSRF, XXE…) | No — auto-executable |
curl_poc |
HTTP auth-bypass / info-disclosure CWE | No — single read-only request |
banner_match |
DoS CWE class (CWE-400/770) or HIGH attack complexity, no PoC | No — version presence only |
script_poc |
Known PoC URL available | Yes — --yes or interactive |
llm_generated |
LLM available (--llm), no other option |
Yes — operator review |
Plans are capped by --cve-max (default: 10).
Generates and executes verification scripts per plan:
- Nuclei templates are auto-generated YAML with read-only detection matchers only
- Python PoC scripts run in a subprocess sandbox with strict timeout
- All generated scripts are logged to
data/cve/audit_log/
- Generated scripts NEVER perform destructive actions (no writes, no DoS)
- Nuclei templates use read-only detection matchers (no exploitation payloads)
- Non-nuclei strategies require operator confirmation (
--yesor interactive) - All script executions are rate-limited, sandboxed, and audited
Separately from the --cve-lookup pipeline, cve-enrich is an always-on post-pass
(disable with --no-cve-enrich) that correlates discovered service versions with the
bundled offline CVE feed + EPSS scores + ATT&CK technique tags. This requires no
network access and adds CVE/EPSS/ATT&CK references to the originating findings.
data/cve/feed.json ships 101 CVE records across 32 product families, including all
major named vulnerabilities by design:
| Product family | Count | Notable records |
|---|---|---|
| OpenSSH | 10 | regreSSHion (CVE-2024-6387), Terrapin (CVE-2023-48795) |
| Bash | 6 | Shellshock (CVE-2014-6271/7169/6277/6278), heap overflow |
| Linux kernel | 9 | Dirty Pipe/copy-fail (CVE-2022-0847), Dirty COW, StackRot, nf_tables UAF |
| Windows / SMB / RDP | 10 | EternalBlue, BlueKeep, Zerologon, PrintNightmare, Follina |
| WiFi 802.11 | 2 | FragAttacks/dirty-frag (CVE-2020-24588/24587) |
| macOS / WebKit | 7 | IOSurface 0-days, kernel UAF, TriangleDB-adjacent |
| Apache HTTPD | 8 | CVE-2021-41773/42013 path traversal RCE, mod_proxy SSRF |
| Nginx | 8 | DNS resolver OOB (CVE-2021-23017), mp4 UAF, HTTP/2 DoS |
| OpenSSL | 5 | Heartbleed, DROWN, FREAK, BN_mod_sqrt loop |
| polkit / sudo / Redis | 5 | PwnKit (CVE-2021-4034), Baron Samedit (CVE-2021-3156) |
| Log4j | 2 | Log4Shell (CVE-2021-44228), incomplete-fix bypass (CVE-2021-45046) |
| Spring | 2 | Spring4Shell (CVE-2022-22965), Spring Cloud Function RCE (CVE-2022-22963) |
| Confluence | 3 | Auth bypass (CVE-2023-22518), privilege escalation, OGNL RCE (CVE-2022-26134) |
| Jenkins | 2 | Arbitrary file read/RCE (CVE-2024-23897), Java deserialization (CVE-2017-1000353) |
| GitLab | 2 | Account takeover (CVE-2023-7028), ExifTool unauthenticated RCE (CVE-2021-22205) |
| Docker / runc | 2 | Leaky Vessels container escape (CVE-2024-21626), runc overwrite (CVE-2019-5736) |
| Kubernetes | 3 | Node proxy bypass (CVE-2022-3294), imagePolicyWebhook bypass, host-network bypass |
| Elasticsearch | 2 | StackOverflow DoS (CVE-2023-31419), credential leak in audit log |
| Exim | 2 | 21Nails heap overflow RCE (CVE-2021-38371), dnsdb OOB read |
| Apache Tomcat | 3 | Request smuggling (CVE-2022-25762), partial PUT race, JSESSIONID exposure |
| IIS | 2 | http.sys wormable RCE (CVE-2021-31166), WebDAV overflow (CVE-2017-7269) |
| Jira | 2 | SSTI RCE (CVE-2019-11581), SSRF (CVE-2022-26135) |
| Grafana | 2 | Path traversal (CVE-2021-43798), OAuth token race (CVE-2022-39328) |
| Keycloak | 2 | Reflected XSS, scope validation bypass |
Each record carries an aliases field listing well-known vulnerability names
(e.g. ["regreSSHion"], ["Shellshock"], ["Dirty Pipe", "copy-fail"]). These aliases
surface in finding titles, tags, and evidence strings so queries on the common name work.
Version matching uses introduced ≤ V < fixed tuple comparison. Records with empty
ranges (e.g. WiFi protocol flaws) are informational and do not match via version.
The feed is replaceable: point CVE_FEED_DIR at a full OSV/NVD mirror using the same
record shape for production-scale coverage.
Data files:
data/cve/feed.json— 101-record offline CVE feed (replaceable)data/cve/epss.json— offline EPSS exploit-probability scoresdata/cve/attack_map.json— category→ATT&CK technique mappingdata/cve/cpe_aliases.json— 86-product CPE alias table
In addition to the enrichment post-pass, two active modules perform live feed lookups during the scan itself:
ssh-probe— parses the OpenSSH version string from the SSH identification banner (e.g.SSH-2.0-OpenSSH_9.7p1) and emits a CVE finding for every matching feed record immediately, before the post-pass runs.http-probe(intrusive+) — parses theServer:/X-Powered-By:header value, matches the embedded product+version against all web-server product families in the feed (apache, nginx, openssl, redis), and emits CVE findings inline.
This means CVE findings appear in the primary findings list of those modules, not only in the enrichment summary, enabling richer attack-chain correlation.
After a scan, use triage.py to replay saved CVE findings interactively without
re-running the full scan. It loads any JSON report produced by --json, presents each
CVE finding with impact analysis, and optionally re-verifies detection against the live target.
# Walk through every CVE finding in a saved report:
python3 triage.py scan_results.json
# Limit to HIGH and above, auto-prompt re-verify for each:
python3 triage.py scan_results.json --severity HIGH --re-verify
# Include all exploited findings (not only CVE-tagged ones):
python3 triage.py scan_results.json --allPer-finding menu:
| Key | Action |
|---|---|
e |
Show full detail, evidence, and all references |
i |
Re-display CWE impact: what the attacker can do and what data is at risk |
ra |
Re-run detection automatically; streams live evidence output to the terminal |
ri |
Interactive: show the PoC script, complete/improve it via LLM or edit in $EDITOR, run with live streaming, optionally ask the LLM to interpret the output, record verdict + notes; after confirmed/partial opens the exploitation menu |
a |
Accept — confirm as a real finding requiring remediation |
f |
False-positive — dismiss with a note |
w |
Waive — accept risk with a justification note |
s |
Skip — move on without recording a decision |
q |
Quit and save all decisions |
Impact analysis is derived from the CVE's CWE — for example, CWE-502 (Deserialization)
shows "exploit Java/PHP/.NET gadget chains for RCE — all data accessible to the service
account" and CWE-22 (Path Traversal) shows "read /etc/passwd, SSH private keys, .env,
database connection strings." 26 CWE classes are mapped.
Re-verification (ra) reconstructs the CveTestPlan from the offline feed and calls
exploit_generator.execute_plans() interactively. Safe-mode invariants remain in effect:
DoS CVEs use banner_match only; script_poc/llm_generated require confirmation.
[ri] runs the PoC script interactively, then — after a confirmed or partial verdict —
opens an exploitation menu tailored to the finding's CWE family and tags:
LLM script completion: if the generated script is a stub (contains manual analysis required, # TODO, etc., or has fewer than 8 code lines), [ri] automatically prompts
to complete it via the local LLM (Ollama) before showing it to the operator. When a
CveTestPlan is available, exploit_generator.generate_llm_poc is used (full CVE
metadata as context); otherwise the LLM is asked to complete the stub script directly.
LLM output summary: after the script runs, the operator is offered a one-line [y/N]
to ask the LLM to summarise the output: does it confirm the vulnerability, what evidence
is present, what is the likely impact?
Script options (shown before run):
[y]— open in$EDITORfor manual editing[l]— ask the LLM to improve/complete the script (shows updated version, then offers a follow-up$EDITORedit before running)[N]— run as-is
Confirmation gate: every live action in the exploitation menu requires the operator
to type the word yes in full before anything fires. Pressing Enter, y, no, or
Ctrl-C all cancel silently. The gate shows exactly what will happen and what evidence
it will leave on the target.
DoS findings (CWE-400/770/834, or tags: slowloris, dos, connection-exhaustion):
| Option | Action |
|---|---|
[d] demonstrate |
Runs a bounded live DoS probe (slowloris or connection-flood), then checks service availability — requires yes |
[m] module re-run |
Re-runs the specific exploit module (e.g. slowloris-probe) — requires yes |
[t] TCP session |
Opens a raw line-mode TCP session for manual service inspection |
RCE findings (CWE-77/78/94/502/787/1336, or tags: rce, log4shell, struts, eternalblue, activemq, shellshock, cmd-injection, foothold, …):
| Option | Action |
|---|---|
[rs] reverse shell |
Prompts for LHOST/LPORT, displays payloads for bash/python3/php/perl/nc/powershell, opens a raw PTY listener — requires yes |
[pe] post-exploit |
Opens the post-exploitation toolkit (follow-up module suggestions, custom PoC editor, reverse shell, raw TCP) |
[m] module re-run |
Re-runs the specific exploit module with OOB canary for definitive proof — requires yes |
[t] TCP session |
Opens a raw line-mode TCP session; type raw for full-duplex PTY mode (Ctrl-] to detach) |
The finding's tags automatically map to the module that produced it (log4shell → log4shell-probe,
eternalblue → ms17010-probe, activemq → activemq-rce-probe, etc.) so [m] always
re-runs the right module without manual selection.
Post-exploitation toolkit (opened via [pe] or for non-RCE/non-DoS confirmed findings):
- Numbered list of CWE-appropriate follow-up modules (e.g.
linux-privesc,container-escape-detector,k8s-probe) [mod <name>]— run any registered module against the target[list]— list allhostport-compatible modules[c]— write a custom follow-up PoC script in$EDITOR[rs]— start a reverse shell listener[t]— open a raw TCP session- Intrusive/proof/fuzz modules gated by the same
yesconfirmation
Triage decisions are saved as <report>.triage.json alongside the original report:
{
"generated_at": "2026-06-30T12:01:00+0000",
"source_report": "/path/to/scan_results.json",
"decisions": {
"cve-autopwn|CVE-2021-44228|10.0.0.5:8080": {
"disposition": "accepted",
"cve": "CVE-2021-44228",
"severity": "CRITICAL",
"ts": "2026-06-30T12:01:00+0000",
"note": ""
}
}
}Disposition values: accepted, false-positive, waived.
cve-enrich and the --cve-lookup resolver chain are not registered in the module
registry — they are orchestrator-level post-passes invoked from main.py after the primary
scan completes.
The cve-autopwn module is registered (intensity intrusive, supports hostport)
and acts as the bridge from CVE discovery to exploit verification within the normal module
pipeline:
- Banner-grabs the target to identify product and version.
- Resolves matching CVEs from the offline feed + any NVD cache from a prior
--cve-lookup. - Prioritises them with
exploit_plannerand executes checks withexploit_generator. - Returns an
ExploitResultwith a fingerprint finding and per-CVE verification findings.