@intentsolutionsio/penetration-tester 2.0.0 → 3.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/.claude-plugin/plugin.json +8 -3
  2. package/README.md +8 -0
  3. package/commands/pentest.md +5 -0
  4. package/package.json +8 -3
  5. package/skills/analyzing-tls-config/SKILL.md +221 -0
  6. package/skills/analyzing-tls-config/references/AUTHORIZATION.md +133 -0
  7. package/skills/analyzing-tls-config/references/PLAYBOOK.md +267 -0
  8. package/skills/analyzing-tls-config/references/THEORY.md +128 -0
  9. package/skills/analyzing-tls-config/scripts/analyze_tls.py +415 -0
  10. package/skills/auditing-cors-policy/SKILL.md +186 -0
  11. package/skills/auditing-cors-policy/references/PLAYBOOK.md +220 -0
  12. package/skills/auditing-cors-policy/references/THEORY.md +142 -0
  13. package/skills/auditing-cors-policy/scripts/audit_cors.py +350 -0
  14. package/skills/auditing-npm-dependencies/SKILL.md +254 -0
  15. package/skills/auditing-npm-dependencies/references/PLAYBOOK.md +175 -0
  16. package/skills/auditing-npm-dependencies/references/THEORY.md +122 -0
  17. package/skills/auditing-npm-dependencies/scripts/audit_npm.py +408 -0
  18. package/skills/auditing-python-dependencies/SKILL.md +251 -0
  19. package/skills/auditing-python-dependencies/references/PLAYBOOK.md +193 -0
  20. package/skills/auditing-python-dependencies/references/THEORY.md +122 -0
  21. package/skills/auditing-python-dependencies/scripts/audit_python.py +459 -0
  22. package/skills/checking-http-security-headers/SKILL.md +176 -0
  23. package/skills/checking-http-security-headers/references/PLAYBOOK.md +212 -0
  24. package/skills/checking-http-security-headers/references/THEORY.md +137 -0
  25. package/skills/checking-http-security-headers/scripts/check_headers.py +362 -0
  26. package/skills/checking-license-compliance/SKILL.md +225 -0
  27. package/skills/checking-license-compliance/references/PLAYBOOK.md +161 -0
  28. package/skills/checking-license-compliance/references/THEORY.md +152 -0
  29. package/skills/checking-license-compliance/scripts/check_licenses.py +461 -0
  30. package/skills/composing-vulnerability-report/SKILL.md +212 -0
  31. package/skills/composing-vulnerability-report/references/PLAYBOOK.md +180 -0
  32. package/skills/composing-vulnerability-report/references/THEORY.md +178 -0
  33. package/skills/composing-vulnerability-report/scripts/compose_report.py +396 -0
  34. package/skills/confirming-pentest-authorization/SKILL.md +247 -0
  35. package/skills/confirming-pentest-authorization/references/PLAYBOOK.md +189 -0
  36. package/skills/confirming-pentest-authorization/references/THEORY.md +167 -0
  37. package/skills/confirming-pentest-authorization/scripts/check_authorization.py +457 -0
  38. package/skills/defining-pentest-scope/SKILL.md +227 -0
  39. package/skills/defining-pentest-scope/references/PLAYBOOK.md +238 -0
  40. package/skills/defining-pentest-scope/references/THEORY.md +170 -0
  41. package/skills/defining-pentest-scope/scripts/define_scope.py +472 -0
  42. package/skills/detecting-command-injection-patterns/SKILL.md +144 -0
  43. package/skills/detecting-command-injection-patterns/references/PLAYBOOK.md +302 -0
  44. package/skills/detecting-command-injection-patterns/references/THEORY.md +206 -0
  45. package/skills/detecting-command-injection-patterns/scripts/scan_cmdi.py +290 -0
  46. package/skills/detecting-debug-endpoints/SKILL.md +207 -0
  47. package/skills/detecting-debug-endpoints/references/PLAYBOOK.md +402 -0
  48. package/skills/detecting-debug-endpoints/references/THEORY.md +218 -0
  49. package/skills/detecting-debug-endpoints/scripts/probe_debug.py +518 -0
  50. package/skills/detecting-directory-listing/SKILL.md +206 -0
  51. package/skills/detecting-directory-listing/references/PLAYBOOK.md +277 -0
  52. package/skills/detecting-directory-listing/references/THEORY.md +203 -0
  53. package/skills/detecting-directory-listing/scripts/probe_directory_listing.py +180 -0
  54. package/skills/detecting-eval-exec-usage/SKILL.md +128 -0
  55. package/skills/detecting-eval-exec-usage/references/PLAYBOOK.md +306 -0
  56. package/skills/detecting-eval-exec-usage/references/THEORY.md +159 -0
  57. package/skills/detecting-eval-exec-usage/scripts/scan_eval.py +223 -0
  58. package/skills/detecting-exposed-secrets-files/SKILL.md +179 -0
  59. package/skills/detecting-exposed-secrets-files/references/PLAYBOOK.md +274 -0
  60. package/skills/detecting-exposed-secrets-files/references/THEORY.md +174 -0
  61. package/skills/detecting-exposed-secrets-files/scripts/probe_secrets.py +207 -0
  62. package/skills/detecting-insecure-deserialization/SKILL.md +148 -0
  63. package/skills/detecting-insecure-deserialization/references/PLAYBOOK.md +333 -0
  64. package/skills/detecting-insecure-deserialization/references/THEORY.md +199 -0
  65. package/skills/detecting-insecure-deserialization/scripts/scan_deserialization.py +250 -0
  66. package/skills/detecting-sql-injection-patterns/SKILL.md +161 -0
  67. package/skills/detecting-sql-injection-patterns/references/PLAYBOOK.md +317 -0
  68. package/skills/detecting-sql-injection-patterns/references/THEORY.md +261 -0
  69. package/skills/detecting-sql-injection-patterns/scripts/scan_sqli.py +354 -0
  70. package/skills/detecting-ssl-cert-issues/SKILL.md +182 -0
  71. package/skills/detecting-ssl-cert-issues/references/PLAYBOOK.md +203 -0
  72. package/skills/detecting-ssl-cert-issues/references/THEORY.md +133 -0
  73. package/skills/detecting-ssl-cert-issues/scripts/check_cert_chain.py +481 -0
  74. package/skills/detecting-weak-cryptography/SKILL.md +147 -0
  75. package/skills/detecting-weak-cryptography/references/PLAYBOOK.md +466 -0
  76. package/skills/detecting-weak-cryptography/references/THEORY.md +194 -0
  77. package/skills/detecting-weak-cryptography/scripts/scan_weak_crypto.py +417 -0
  78. package/skills/fingerprinting-server-software/SKILL.md +191 -0
  79. package/skills/fingerprinting-server-software/references/PLAYBOOK.md +337 -0
  80. package/skills/fingerprinting-server-software/references/THEORY.md +183 -0
  81. package/skills/fingerprinting-server-software/scripts/fingerprint_server.py +347 -0
  82. package/skills/generating-executive-summary/SKILL.md +261 -0
  83. package/skills/generating-executive-summary/references/PLAYBOOK.md +201 -0
  84. package/skills/generating-executive-summary/references/THEORY.md +195 -0
  85. package/skills/generating-executive-summary/scripts/exec_summary.py +538 -0
  86. package/skills/mapping-findings-to-owasp-top10/SKILL.md +235 -0
  87. package/skills/mapping-findings-to-owasp-top10/references/PLAYBOOK.md +193 -0
  88. package/skills/mapping-findings-to-owasp-top10/references/THEORY.md +160 -0
  89. package/skills/mapping-findings-to-owasp-top10/scripts/map_owasp.py +540 -0
  90. package/skills/performing-penetration-testing/SKILL.md +282 -190
  91. package/skills/performing-penetration-testing/references/OWASP_TOP_10.md +22 -0
  92. package/skills/performing-penetration-testing/references/REMEDIATION_PLAYBOOK.md +46 -0
  93. package/skills/performing-penetration-testing/references/SECURITY_HEADERS.md +41 -0
  94. package/skills/performing-penetration-testing/scripts/code_security_scanner.py +144 -79
  95. package/skills/performing-penetration-testing/scripts/dependency_auditor.py +116 -93
  96. package/skills/performing-penetration-testing/scripts/security_scanner.py +574 -446
  97. package/skills/probing-dangerous-http-methods/SKILL.md +182 -0
  98. package/skills/probing-dangerous-http-methods/references/PLAYBOOK.md +234 -0
  99. package/skills/probing-dangerous-http-methods/references/THEORY.md +145 -0
  100. package/skills/probing-dangerous-http-methods/scripts/probe_methods.py +263 -0
  101. package/skills/recording-pentest-engagement/SKILL.md +253 -0
  102. package/skills/recording-pentest-engagement/references/PLAYBOOK.md +203 -0
  103. package/skills/recording-pentest-engagement/references/THEORY.md +195 -0
  104. package/skills/recording-pentest-engagement/scripts/record_engagement.py +461 -0
  105. package/skills/scanning-for-hardcoded-secrets/SKILL.md +215 -0
  106. package/skills/scanning-for-hardcoded-secrets/references/PLAYBOOK.md +325 -0
  107. package/skills/scanning-for-hardcoded-secrets/references/THEORY.md +175 -0
  108. package/skills/scanning-for-hardcoded-secrets/scripts/scan_secrets.py +395 -0
  109. package/skills/tracing-transitive-vulnerabilities/SKILL.md +235 -0
  110. package/skills/tracing-transitive-vulnerabilities/references/PLAYBOOK.md +233 -0
  111. package/skills/tracing-transitive-vulnerabilities/references/THEORY.md +138 -0
  112. package/skills/tracing-transitive-vulnerabilities/scripts/trace_vulns.py +484 -0
@@ -0,0 +1,180 @@
1
+ # PLAYBOOK — Report Templates and Workflow
2
+
3
+ ## End-of-engagement workflow
4
+
5
+ ```bash
6
+ # 1. All cluster 1-4 scans have run; findings are in engagements/<id>/findings/
7
+
8
+ # 2. (Optional) Map findings to OWASP Top 10
9
+ python3 plugins/security/penetration-tester/skills/mapping-findings-to-owasp-top10/scripts/map_owasp.py \
10
+ engagements/acme-2026-q2/
11
+
12
+ # 3. Compose the vulnerability report
13
+ python3 ./scripts/compose_report.py engagements/acme-2026-q2/
14
+
15
+ # 4. Generate the executive summary
16
+ python3 plugins/security/penetration-tester/skills/generating-executive-summary/scripts/exec_summary.py \
17
+ engagements/acme-2026-q2/
18
+
19
+ # 5. Record the engagement (chain of custody)
20
+ python3 plugins/security/penetration-tester/skills/recording-pentest-engagement/scripts/record_engagement.py \
21
+ engagements/acme-2026-q2/ --sign --tar engagements/archives/acme-2026-q2.tar.gz
22
+ ```
23
+
24
+ ## Report-template variants per audience
25
+
26
+ ### Technical (default — what the skill emits)
27
+
28
+ Everything: per-finding detail, remediation steps, evidence,
29
+ references. Audience: customer's security engineer or external
30
+ auditor.
31
+
32
+ ### Manager-style (use `--min-severity high`)
33
+
34
+ Only HIGH and CRITICAL findings shown. Body of the report is the
35
+ same per-finding format but the customer's manager doesn't have
36
+ to scroll past medium / low findings.
37
+
38
+ ```bash
39
+ python3 ./scripts/compose_report.py engagements/acme-2026-q2/ \
40
+ --min-severity high \
41
+ --report-output engagements/acme-2026-q2/reports/manager-brief.md
42
+ ```
43
+
44
+ ### Compliance-evidence (use `--include-info`)
45
+
46
+ Includes the INFO-severity operational records (scan ran cleanly,
47
+ no findings in this target, etc.). Audience: SOC2 / ISO 27001
48
+ auditors who want documented evidence the scan ran even where
49
+ nothing was found.
50
+
51
+ ```bash
52
+ python3 ./scripts/compose_report.py engagements/acme-2026-q2/ \
53
+ --include-info \
54
+ --report-output engagements/acme-2026-q2/reports/compliance-evidence.md
55
+ ```
56
+
57
+ ## Per-finding remediation phrasing patterns
58
+
59
+ The skill emits each finding's `remediation` field verbatim from
60
+ the source. Cluster 1-4 skills construct these as numbered lists
61
+ with imperative voice:
62
+
63
+ ```
64
+ 1. Run `npm audit fix` in the project root.
65
+ 2. If the fix requires a semver-major bump, evaluate the breaking changes.
66
+ 3. Commit the updated package-lock.json.
67
+ ```
68
+
69
+ Patterns to maintain when authoring remediation:
70
+
71
+ - **Imperative voice.** "Run X" not "You should run X" not "It is recommended to run X."
72
+ - **Numbered list when there are >1 steps.** Bullets blur the order.
73
+ - **Concrete commands when possible.** "Apply security patch" is unactionable; "`apt-get update && apt-get upgrade libssl3`" is actionable.
74
+ - **Decision points called out.** "If X, do Y; otherwise do Z" makes the operator's choice explicit.
75
+
76
+ ## Evidence-redaction for distributed reports
77
+
78
+ A pentest report sometimes needs distribution beyond the immediate
79
+ customer — to their auditor, their insurance carrier, their board.
80
+ Some evidence shouldn't leave the original engagement: leaked
81
+ credentials, full request/response bodies containing PII, screenshots
82
+ showing customer data.
83
+
84
+ The skill doesn't auto-redact. The pattern for human-controlled
85
+ redaction:
86
+
87
+ 1. Generate the full report with this skill.
88
+ 2. Use a separate redaction pass to:
89
+ - Replace leaked-secret values with `[REDACTED]` while keeping
90
+ finding context.
91
+ - Blur or remove customer-data screenshots.
92
+ - Replace user-identifying URLs with `<USER>/path/...` placeholders.
93
+ 3. Distribute the redacted version. Keep the unredacted version in
94
+ the engagement archive.
95
+
96
+ The skill could be extended with a `--redact PATTERN` flag if this
97
+ becomes a frequent enough pattern.
98
+
99
+ ## Cross-reference protocol with OWASP-mapping + exec-summary
100
+
101
+ The next two cluster 6 skills consume this report's findings file
102
+ (JSON output of THIS skill's findings → not the rendered markdown).
103
+ The protocol:
104
+
105
+ 1. **Findings producer:** cluster 1-4 skills emit per-skill findings JSONLs
106
+ 2. **Vulnerability report composer (this skill):** composes a single
107
+ vulnerability-report.md AND can output a unified findings JSONL
108
+ 3. **OWASP mapping:** reads the unified JSONL, adds `owasp_category`
109
+ field to each finding, writes back
110
+ 4. **Exec summary:** reads the (potentially OWASP-enriched) unified
111
+ JSONL, produces the executive-summary.md
112
+
113
+ The order can be either:
114
+
115
+ - A: cluster-1-4 → OWASP → compose → exec-summary
116
+ - B: cluster-1-4 → compose → OWASP → re-compose → exec-summary
117
+
118
+ Pattern B regenerates the report after enrichment. Pattern A only
119
+ composes once. Both are valid; the choice depends on whether the
120
+ operator wants the OWASP tags visible in the report's per-finding
121
+ sections.
122
+
123
+ ## Common composition mistakes
124
+
125
+ | Mistake | Consequence | Fix |
126
+ |---|---|---|
127
+ | Findings without `target` field | Findings dropped from report; HIGH op-finding | Ensure all source skills emit `target` |
128
+ | Mixed findings + opfindings in source file | Report contains operational noise | Separate skill output and operational output |
129
+ | Identical findings with different IDs | Dedup fails | Ensure source skills use consistent `Finding.fingerprint()` |
130
+ | Re-running with new sources but old report path | Old report overwritten silently | Use timestamped `--report-output` paths for interim reports |
131
+
132
+ ## Per-engagement directory layout (canonical)
133
+
134
+ The skill assumes:
135
+
136
+ - `engagement/findings/*.json[l]` — source findings
137
+ - `engagement/reports/` — output reports (auto-created if missing)
138
+ - `engagement/roe.yaml` — has `engagement_id:` for header
139
+
140
+ Deviations are supported via flags:
141
+
142
+ - `--source FILE` — bypass auto-discovery
143
+ - `--report-output PATH` — write report anywhere
144
+ - `--engagement-id ID` — override ROE detection
145
+
146
+ ## Integration with cluster 1-4 skills
147
+
148
+ The cluster 1-4 scan skills all emit findings via `report.emit()`
149
+ (in `lib/report.py`) which can write JSON / JSONL / Markdown.
150
+ For composition workflow, each scan should run with
151
+ `--format jsonl --output engagement/findings/<skill>-<date>.jsonl`:
152
+
153
+ ```bash
154
+ python3 plugins/security/penetration-tester/skills/checking-http-security-headers/scripts/check_headers.py \
155
+ https://app.acme.example --format jsonl \
156
+ --output engagements/acme-2026-q2/findings/headers-$(date +%Y%m%d).jsonl
157
+ ```
158
+
159
+ The skill then picks up every file under `findings/` by default.
160
+
161
+ ## Stable-rendering verification
162
+
163
+ To verify the report is rendering stably (same input → same output
164
+ except timestamp):
165
+
166
+ ```bash
167
+ # Render twice
168
+ python3 ./scripts/compose_report.py engagements/acme-2026-q2/ \
169
+ --report-output /tmp/report-1.md
170
+ sleep 2
171
+ python3 ./scripts/compose_report.py engagements/acme-2026-q2/ \
172
+ --report-output /tmp/report-2.md
173
+
174
+ # Diff ignoring the timestamp line
175
+ diff <(grep -v "Generated by" /tmp/report-1.md) \
176
+ <(grep -v "Generated by" /tmp/report-2.md)
177
+ ```
178
+
179
+ The diff should be empty. If it isn't, file an issue — stable
180
+ rendering is a contract this skill maintains.
@@ -0,0 +1,178 @@
1
+ # THEORY — Vulnerability Report Structure
2
+
3
+ ## What a customer actually reads
4
+
5
+ A pentest vulnerability report is read by three different people
6
+ in three different ways:
7
+
8
+ 1. **The customer's security engineer** — reads end to end, in
9
+ order, looking for specific technical detail per finding.
10
+ 2. **The customer's manager** — reads the summary table, then
11
+ skims headlines of critical / high findings, then trusts the
12
+ security engineer's recommendation.
13
+ 3. **A future reader during compliance audit** — reads to verify
14
+ the finding existed and the remediation was documented.
15
+
16
+ The report has to serve all three audiences without trying too
17
+ hard. The structure this skill emits is the result of trial and
18
+ error against those three readers:
19
+
20
+ - Top: short header identifying engagement, generation time,
21
+ sources.
22
+ - Below: summary table — counts by severity.
23
+ - Then: severity-ordered finding sections, CRITICAL first.
24
+ - Each finding: title, severity, target, detail, remediation,
25
+ evidence, references — in that order. Always.
26
+
27
+ The shape is boring on purpose. Surprise in report structure is
28
+ not a feature; the reader should be able to predict where a piece
29
+ of information lives without searching.
30
+
31
+ ## Why CVSS v3.1 (not CVSS v4 or CWE-only)
32
+
33
+ CVSS v3.1 (June 2019) is the de facto industry standard severity
34
+ vector. NVD scores every CVE with CVSS v3.1. SOC2 / ISO 27001 /
35
+ PCI auditors expect to see CVSS scores.
36
+
37
+ CVSS v4.0 was published in November 2023. It addresses real
38
+ problems with v3.1 (better handling of supply-chain attacks,
39
+ clearer attack-vector semantics). Adoption has been slow because
40
+ the existing tooling chain is v3.1-shaped. As of 2026 the practical
41
+ choice is still v3.1.
42
+
43
+ CWE alone is a different axis — what KIND of weakness, not how
44
+ SEVERE. Reports include CWE as enrichment when available but use
45
+ CVSS for the severity decision.
46
+
47
+ ## CVSS vector composition (when the skill derives one)
48
+
49
+ When a finding arrives without a CVSS score, the skill does NOT
50
+ guess a precise numeric score (that would falsely imply NVD-level
51
+ authority). Instead it maps severity → severity band, retaining
52
+ the explicit "derived" label so the report's reader knows the score
53
+ isn't NVD-blessed.
54
+
55
+ | Severity | Implied CVSS band | Note |
56
+ |---|---|---|
57
+ | CRITICAL | 9.0 - 10.0 | implied by mapping; not authoritative |
58
+ | HIGH | 7.0 - 8.9 | implied |
59
+ | MEDIUM | 4.0 - 6.9 | implied |
60
+ | LOW | 0.1 - 3.9 | implied |
61
+ | INFO | n/a | no score emitted |
62
+
63
+ Findings that arrived WITH a CVSS score keep their original value
64
+ unchanged. This is important: a finding with `cvss_score: 7.5`
65
+ from `auditing-python-dependencies` (which extracts it from OSV)
66
+ must not be overwritten by this skill's heuristic.
67
+
68
+ ## Why fingerprint-based deduplication
69
+
70
+ `lib/finding.py` defines `Finding.fingerprint()` as a stable hash
71
+ of `(skill_id, title, target)`. Two findings with the same
72
+ fingerprint are the same finding from the same source about the
73
+ same target, regardless of which scan run produced them.
74
+
75
+ The alternative — title-based dedup — fails when:
76
+
77
+ - Same skill is run twice (the second invocation produces
78
+ identical findings)
79
+ - Two different skills produce findings with the same title but
80
+ different targets (legitimate distinct findings)
81
+ - A skill produces findings with parameterized titles (the
82
+ title varies but the substance is the same)
83
+
84
+ Fingerprint-based dedup is the right primitive. The trade-off:
85
+ fingerprints don't catch SEMANTICALLY-equivalent findings from
86
+ different skills. If `auditing-npm-dependencies` and an external
87
+ tool both surface the same CVE, the fingerprints differ (different
88
+ skill_id). Cross-tool semantic dedup is a separate problem — this
89
+ skill handles within-skill dedup correctly.
90
+
91
+ ## NIST SP 800-115 vs PTES vs OWASP Testing Guide
92
+
93
+ Three frameworks define what a pentest report should contain:
94
+
95
+ | Framework | Strengths | Weaknesses |
96
+ |---|---|---|
97
+ | NIST SP 800-115 (US gov-flavored) | Definitive, well-structured | Network-focused; app-pentest sections are thin |
98
+ | PTES | Defines the workflow end-to-end | Report structure is one of many topics; less prescriptive |
99
+ | OWASP Testing Guide (WSTG) | Best on web-app vulnerability classification | Doesn't prescribe report structure deeply |
100
+
101
+ The skill's output format is informed by all three but doesn't
102
+ claim conformance to any. The structure is pragmatic: what works
103
+ in real customer engagements as of 2026.
104
+
105
+ ## Severity-grouping rationale
106
+
107
+ The skill groups findings by severity, NOT by skill or by target.
108
+ Reasons:
109
+
110
+ - Customers care about severity first. A CRITICAL CVE in
111
+ dependency-vuln scan and a CRITICAL TLS misconfig and a
112
+ CRITICAL secret in source are all the same severity to the
113
+ reader; they should be co-located.
114
+ - Per-severity grouping makes remediation prioritization
115
+ trivially visual.
116
+ - Per-skill grouping would hide cross-skill patterns ("multiple
117
+ high findings in the same target" becomes invisible).
118
+
119
+ If the customer specifically wants per-skill grouping (some prefer
120
+ it), this skill's output is structured Markdown that a downstream
121
+ tool can re-group. The skill emits the canonical form; consumers
122
+ re-shape if needed.
123
+
124
+ ## Stable anchors for cross-reference
125
+
126
+ Each finding subsection in the report has a stable HTML anchor
127
+ based on the fingerprint:
128
+
129
+ ```html
130
+ <a id="finding-a1b2c3d4e5f6"></a>
131
+ ```
132
+
133
+ The executive-summary skill and the OWASP-mapping skill reference
134
+ findings by this anchor:
135
+
136
+ ```markdown
137
+ [See finding](vulnerability-report.md#finding-a1b2c3d4e5f6)
138
+ ```
139
+
140
+ The anchor is stable across regenerations of the report (because
141
+ the fingerprint is stable). If the report is regenerated after
142
+ adding new findings, existing finding anchors don't change —
143
+ only new anchors are added.
144
+
145
+ ## Required-field policy
146
+
147
+ The skill refuses to include findings missing any of `title`,
148
+ `severity`, `target`, `detail`, `remediation`. The dropped finding
149
+ becomes a HIGH operational finding from this skill itself,
150
+ surfacing the problem to the operator without silently swallowing
151
+ the broken record.
152
+
153
+ This is conservative on purpose. A pentest report that includes
154
+ malformed findings is unprofessional and undermines the engagement.
155
+ Better to surface the problem with a loud error than to ship
156
+ broken records.
157
+
158
+ ## Why include-info defaults to off
159
+
160
+ INFO-severity findings are operational chatter (no vulnerabilities
161
+ found, scanner ran cleanly, etc.). Customer reports should NOT
162
+ include them in the main severity sections — the customer cares
163
+ about findings, not about confirmation that the scan ran.
164
+
165
+ `--include-info` adds an INFO section at the bottom of the report
166
+ for operational transparency. Useful for SOC2 evidence packages
167
+ where auditors want to confirm every scan ran.
168
+
169
+ ## Generation timestamp + reproducibility
170
+
171
+ The header includes the generation timestamp in ISO-8601. The
172
+ report is reproducible from the same source findings: if you
173
+ re-run with the same inputs, the report content is byte-identical
174
+ except for the timestamp.
175
+
176
+ This matters for evidence: the customer's audit team needs to
177
+ verify "report-as-shipped" against "report-from-source-now."
178
+ Stable rendering = trustable comparison.