Repository navigation
Reports
Report generation system documentation — HTML, Word (.docx), evidence vault, and compliance tagging.
PentestAI produces the following report formats from a single session:
| Format | Command | Target Audience |
|---|---|---|
| HTML | report |
Internal review, quick sharing |
| Word (.docx) | report docx |
Client, management, compliance |
| HTML (without AI) | report quick |
Internal review, fast, no LLM |
| SARIF 2.1.0 | report sarif |
CI, code scanning, DevSecOps |
report pdf |
Client delivery, archival | |
| All formats | report all |
Complete package |
SARIF exports validated findings only by default. Use report sarif all
to include candidates; each result carries validationStatus in its
properties. PDF rendering uses headless Chromium (Playwright).
Generator reports/generate_docx.js (Node.js) + ReportGenerator.generate_docx() (Python wrapper).
Contents of the Word report:
- Cover page — target, date, CONFIDENTIAL classification
- Executive summary — summary in CFO language with a risk table per severity
- Per-finding sections — colored severity badge, evidence, PoC curl commands, OWASP/CWE tags
- Appendix A — scope expansion log (if there are expansion requests)
- Appendix B — raw evidence with SHA-256 hashes
from reports.generator import ReportGenerator
gen = ReportGenerator(session)
path = gen.generate_docx() # returns Path to the .docx file
path = gen.generate_docx(ai_content={"executive_summary": "..."}) # with AI summaryRequirement: Node.js (for generate_docx.js)
node --version # make sure it is installedgen = ReportGenerator(session)
paths = gen.generate()
# paths["html"] → Path to .html
# paths["markdown"] → Path to .mdreport # with AI enhancement (requires LLM)
report quick # without AI, directly from session dataAll evidence is attached to a specific finding, immutable with a SHA-256 hash.
# Attach evidence to a finding
h = session.attach_evidence(finding_id, "HTTP/1.1 200 OK\nroot:x:0:0", label="passwd_leak")
# → returns 16-char hash, e.g. "a3f8e2b1c9d4f7e0"
# Verify integrity
result = session.verify_evidence(finding_id)
# → {"status": "ok", "verified": 2, "files": [...]}
# → {"status": "tampered", "tampered": ["20241019_evidence.txt"]}
# Export all evidence as a ZIP bundle
bundle = session.export_evidence_bundle()
# → ZIP contains: session.json, all evidence files, INDEX.txt with hashesevidence attach <finding_id> [label] # paste content from stdin
evidence verify [finding_id] # verify hash integrity
evidence export # ZIP bundle of all evidence
evidence fp <finding_id> # mark as false positiveFields in Finding:
-
evidence_hashes: list[str]— SHA-256[:16] of each evidence item attached -
false_positive: bool— flagged as FP by the operator -
remediated: bool— already fixed by the client
reports/compliance.py — auto-tagging of every finding with standard frameworks.
from reports.compliance import tag_finding, ComplianceTags
tags = tag_finding("SQL Injection", severity="High")
# ComplianceTags(
# owasp=["A03:2021 - Injection"],
# cwe=[89],
# cvss_score=8.8,
# cvss_vector="AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N",
# epss_score=0.97,
# epss_percentile=99,
# )Supported frameworks:
- OWASP Top 10 2021 (A01–A10)
- CWE identifiers
- CVSS 4.0 base score + vector
- EPSS (Exploit Prediction Scoring System) score + percentile
agents/poc.py — capture HTTP request/response and produce reproduction steps.
from agents.poc import PoCRunner
runner = PoCRunner(session)
packages = runner.generate_all() # all findings
for pkg in packages:
print(pkg.reproduction_steps) # list of steps
for ev in pkg.evidence:
print(ev.to_curl()) # curl command that can be reproducedpoc # generate PoCs for all findings in the sessionPoCPackage output:
-
reproduction_steps: list[str]— steps to reproduce -
evidence: list[HTTPEvidence]— HTTP request/response captures -
curl_commands: list[str]— curl commands that can be run directly
When generate_docx() runs, it automatically:
- Collects all
PoCPackagefromPoCRunner - Collects evidence from
session.attach_evidence() - Attaches curl commands and response snippets to each finding section
- Includes the scope expansion log in Appendix A
- Includes raw evidence with hashes in Appendix B
Report format according to Penetration Testing Execution Standard.
from reports.ptes import PTESReportGenerator
gen = PTESReportGenerator(session)
json_path = gen.generate_json() # machine-readable
md_path = gen.generate_markdown() # human-readableptes # generate both from the shellContents of the PTES report:
- Executive summary with overall risk rating (CRITICAL/HIGH/MEDIUM/LOW)
- Per-finding with PTES phase mapping (Phase 2/4/5/6)
- Business impact per finding (non-technical language)
- Top recommendation for management
- Scope expansion log
Automatic PTES phase mapping based on tool:
| Tool | PTES Phase |
|---|---|
| nmap, http, subdomain, osint | Phase 2 — Intelligence Gathering |
| gobuster, nikto, waf_detect | Phase 4 — Vulnerability Analysis |
| sqlmap, metasploit, SSTI/XXE | Phase 5 — Exploitation |
| privesc, ad_enum, kerberoast | Phase 6 — Post Exploitation |
Export findings as a risk register according to ISO/IEC 27001:2022 Annex A.
from reports.ptes import ISO27001RiskRegister
gen = ISO27001RiskRegister(session)
path = gen.generate() # returns Path to the JSON fileiso27001 # generate from the shellJSON format:
{
"standard": "ISO/IEC 27001:2022 Annex A",
"risks": [
{
"risk_id": "R-a3f8",
"asset": "http://10.0.0.1/",
"vulnerability": "SQL Injection",
"likelihood": "4/5",
"impact": "4/5",
"risk_score": 16,
"iso_controls": ["A.14.2.5 Secure system engineering principles"],
"treatment": "Use parameterized queries",
"treatment_status": "open",
"residual_risk": "High"
}
]
}Risk scoring: likelihood × impact (1-5 scale), sorted descending.
ISO controls are mapped automatically from the finding's OWASP tags.
Residual risk is automatically "Low" when finding.remediated = True.