@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,201 @@
1
+ # PLAYBOOK — Audience Customizations and Delivery
2
+
3
+ ## Per-audience customizations
4
+
5
+ ### Board summary (default — quarterly board pack)
6
+
7
+ Risk score + top 3 priorities + OWASP coverage. The board reader
8
+ wants to know "should we be worried?" The exec summary as
9
+ emitted answers that.
10
+
11
+ ```bash
12
+ python3 ./scripts/exec_summary.py engagements/acme-2026-q2/
13
+ ```
14
+
15
+ ### C-suite (CISO / CTO) summary
16
+
17
+ Same content as the board summary, but the C-suite reader may
18
+ want lengthier remediation discussion. After running the default
19
+ summary, the operator can edit the markdown directly to expand
20
+ specific sections. The skill's output is intentionally treated as
21
+ a draft for editorial expansion.
22
+
23
+ ### Customer's security leadership summary
24
+
25
+ For the customer's own security leadership (Director of Security,
26
+ VP Engineering's security lead, etc.), the most useful expansion
27
+ is per-priority detail with cross-references to the vulnerability
28
+ report. The default output already includes the
29
+ `vulnerability-report.md#finding-XXX` cross-references — these
30
+ are clickable in most markdown viewers.
31
+
32
+ ### External auditor / insurer summary
33
+
34
+ For external parties (SOC2 auditor, cyber-insurance carrier),
35
+ extend the default with engagement-archive integrity statement:
36
+
37
+ ```markdown
38
+ ## Archive integrity
39
+
40
+ The engagement's findings, evidence, and configuration are
41
+ archived at <path> with a SHA-256 manifest signed by <key id>.
42
+ Verification command:
43
+
44
+ `sha256sum -c manifest.sha256 && gpg --verify manifest.sha256.asc manifest.sha256`
45
+ ```
46
+
47
+ Add this manually to the rendered summary before delivery.
48
+
49
+ ## Summary length guidelines
50
+
51
+ | Use | Target length |
52
+ |---|---|
53
+ | Board summary | 1 page (~60 lines markdown) |
54
+ | C-suite summary | 1.5 pages (~80 lines markdown) |
55
+ | Customer security leadership | 2 pages (~120 lines markdown) |
56
+ | External auditor (with archive section) | 2 pages |
57
+
58
+ The skill emits ~80-100 lines by default. Pad or trim by editing
59
+ the rendered markdown.
60
+
61
+ ## Common rewrite patterns
62
+
63
+ ### "Soften the risk-score band wording"
64
+
65
+ Some customers find "Critical" / "High" risk-band language
66
+ alarming when the underlying findings are routine. The
67
+ risk-band labels are documented in THEORY.md; if your customer
68
+ relationship makes the words land badly, rewrite the band
69
+ description without changing the numeric score.
70
+
71
+ Don't change the score itself to fit the rewrite — the score
72
+ remains the canonical number; the descriptive band is the
73
+ audience-facing label.
74
+
75
+ ### "Add a CFO-readable financial-impact section"
76
+
77
+ The skill doesn't compute financial impact (out of scope; too
78
+ many assumptions about asset value). For engagements that warrant
79
+ a CFO-readable section:
80
+
81
+ 1. Work with the customer's finance lead to assign rough cost
82
+ ranges to each top priority.
83
+ 2. Append a "Financial impact estimates" section to the rendered
84
+ summary with the agreed numbers.
85
+ 3. Annotate clearly: "Cost estimates provided by customer; not
86
+ computed from finding data."
87
+
88
+ ### "Add a regulatory-impact narrative"
89
+
90
+ For engagements in regulated industries (HIPAA, PCI, SOC2), the
91
+ exec audience cares about regulatory exposure. Append a
92
+ "Regulatory impact" section that cross-references the top
93
+ findings against specific regulations:
94
+
95
+ ```markdown
96
+ ## Regulatory impact
97
+
98
+ The top finding "Hardcoded AWS key in source" triggers HIPAA
99
+ §164.308(a)(1)(ii)(B) (Risk Management) reporting obligation.
100
+ Remediation timing should align with the breach-notification
101
+ window if data has been exposed.
102
+ ```
103
+
104
+ Don't include this section by default; add it when the engagement
105
+ has specific regulatory framing.
106
+
107
+ ## Integration with the composing + mapping skills
108
+
109
+ The exec-summary skill consumes:
110
+
111
+ 1. **Unified findings JSONL** (from `composing-vulnerability-report`
112
+ OR `mapping-findings-to-owasp-top10`)
113
+ 2. **OWASP coverage report** (from `mapping-findings-to-owasp-top10`)
114
+ 3. **ROE YAML** (from the engagement repository)
115
+
116
+ Run order:
117
+
118
+ ```bash
119
+ # 1. (Optional) Compose to produce the main vulnerability report first
120
+ python3 plugins/security/penetration-tester/skills/composing-vulnerability-report/scripts/compose_report.py \
121
+ engagements/acme-2026-q2/
122
+
123
+ # 2. Map to OWASP, producing the enriched JSONL and coverage report
124
+ python3 plugins/security/penetration-tester/skills/mapping-findings-to-owasp-top10/scripts/map_owasp.py \
125
+ engagements/acme-2026-q2/
126
+
127
+ # 3. Generate the exec summary
128
+ python3 ./scripts/exec_summary.py engagements/acme-2026-q2/
129
+ ```
130
+
131
+ ## Post-delivery follow-up cadence
132
+
133
+ The exec summary's "Suggested next steps" section starts a
134
+ remediation cadence. The pentester's role typically:
135
+
136
+ 1. **End-of-engagement** (week 0): deliver the summary + report.
137
+ 2. **Week 2**: optional check-in with the customer's security
138
+ lead to confirm remediation has been prioritized.
139
+ 3. **Week 6**: confirm the top priorities have been addressed.
140
+ 4. **Week 12**: re-test the top priorities to verify the fixes
141
+ hold. The re-test produces a follow-up summary using the same
142
+ skill against the same engagement directory.
143
+
144
+ Re-tests should produce a LOWER risk score after remediation. If
145
+ the score doesn't drop, either the fixes didn't take effect or
146
+ new findings emerged in the re-test scan.
147
+
148
+ ## Sample delivery package
149
+
150
+ The standard engagement closeout package contains:
151
+
152
+ ```
153
+ engagements/archives/acme-2026-q2.tar.gz
154
+ ├── engagement directory contents
155
+ ├── manifest.sha256 # SHA-256 of every file
156
+ ├── manifest.sha256.asc # GPG signature
157
+ └── reports/
158
+ ├── vulnerability-report.md # full technical detail
159
+ ├── owasp-coverage.md # OWASP Top 10 breakdown
160
+ └── executive-summary.md # this skill's output
161
+ ```
162
+
163
+ Plus separately:
164
+
165
+ - The exec summary as a standalone PDF (via `/whiteglove-pdf`).
166
+ - A receipt-signed copy of the archive's manifest.
167
+
168
+ ## Risk-score auditability
169
+
170
+ If a customer or third party questions the risk score, the
171
+ auditable response:
172
+
173
+ 1. Show the score-composition formula from THEORY.md.
174
+ 2. Show the severity counts that fed the formula.
175
+ 3. Show the OWASP-breadth count.
176
+ 4. Show the governance-bonus determination.
177
+ 5. Demonstrate that re-running the skill produces the same score.
178
+
179
+ The skill is deterministic by design so this audit is always
180
+ possible.
181
+
182
+ ## When the score and the findings disagree intuitively
183
+
184
+ Occasionally the algorithmic score doesn't match the operator's
185
+ gut feeling — usually because:
186
+
187
+ - A single very high-impact finding doesn't dominate enough
188
+ (the formula adds rather than maxing).
189
+ - Numerous low-severity findings produce a higher score than the
190
+ operator expected.
191
+ - The OWASP-breadth bonus elevates an otherwise-modest engagement.
192
+
193
+ Operator can:
194
+
195
+ - Document the divergence in the summary's "Suggested next steps"
196
+ section.
197
+ - Use `--priority-overrides` to set top-3 priorities that match
198
+ intuition.
199
+ - Refrain from re-engineering the formula for one engagement;
200
+ consistency across engagements is the formula's value
201
+ proposition.
@@ -0,0 +1,195 @@
1
+ # THEORY — Executive Summary as a Technical-Communication Discipline
2
+
3
+ ## What an exec summary actually is
4
+
5
+ An executive summary is not a shorter vulnerability report. It's
6
+ a different document for a different reader. The vulnerability
7
+ report says "here is every finding we identified." The exec
8
+ summary says "here is what the board / CEO / CISO needs to decide
9
+ on, and how big the decision is."
10
+
11
+ The summary's job is to compress without losing decision-relevant
12
+ information. Compressed too far, it becomes content-free chrome
13
+ ("the engagement found several issues; please refer to the full
14
+ report"). Compressed too little, it becomes a redundant technical
15
+ document.
16
+
17
+ The middle ground:
18
+
19
+ 1. A single number that establishes the engagement's bottom line
20
+ (risk score).
21
+ 2. Counts that contextualize the number (severity breakdown).
22
+ 3. Specific named priorities the reader can act on.
23
+ 4. Just enough scope/authz framing that the reader can validate
24
+ the summary against their own expectations.
25
+ 5. A clear pointer to the deep document.
26
+
27
+ ## Why a single risk score
28
+
29
+ The single-number summary is controversial in security circles —
30
+ it loses information, it can be gamed, it doesn't capture
31
+ exploitation likelihood. All true.
32
+
33
+ It's still the right primitive for the exec audience because:
34
+
35
+ - Execs are accustomed to making decisions on single numbers
36
+ (NPS, MAU, ARR, Lighthouse score). A pentest result without a
37
+ number doesn't fit the decision frame.
38
+ - The number's interpretation band ("Low / Moderate / Elevated /
39
+ High / Critical") is more decision-relevant than the precise
40
+ number anyway.
41
+ - Score-to-decision mapping is consistent across engagements;
42
+ the customer can compare year-over-year and customer-to-customer.
43
+
44
+ Critical caveats the summary writer should NOT lose:
45
+
46
+ - The score is HEURISTIC. A 65 isn't twice as bad as a 32.
47
+ - The score's composition formula is documented; the reader can
48
+ audit how it was computed.
49
+ - The score isn't a substitute for reading the finding list.
50
+
51
+ ## Risk score composition — design rationale
52
+
53
+ The chosen weights:
54
+
55
+ - 20 per CRITICAL — each critical finding has potential to be a
56
+ full-organization-impact event. Two criticals already pushes
57
+ the score into the elevated band.
58
+ - 10 per HIGH — high findings are material but typically scoped
59
+ to specific systems.
60
+ - 3 per MEDIUM — mediums accumulate to meaning; one isn't a
61
+ big deal, but ten is.
62
+ - 1 per LOW — low findings are noise individually; in bulk they
63
+ signal hygiene problems.
64
+ - 0 per INFO — informational findings don't move the score.
65
+
66
+ The OWASP-coverage breadth term adds points for engagements that
67
+ land findings in many categories. Reasoning: an engagement that
68
+ finds problems in 8 OWASP categories has surfaced a broader risk
69
+ surface than one that finds problems in 2. The breadth term
70
+ captures that.
71
+
72
+ The governance bonus (-10 when ROE is clean) is a deliberate
73
+ adjustment. A clean engagement with the same findings represents
74
+ LESS organizational risk than a chaotic engagement with the same
75
+ findings, because the customer has the operational rigor to
76
+ remediate effectively.
77
+
78
+ ## Score band interpretation
79
+
80
+ The 0-100 score maps to qualitative bands:
81
+
82
+ | Range | Band | Decision implication |
83
+ |---|---|---|
84
+ | 0-25 | Low | Continue current cadence; no special action |
85
+ | 26-50 | Moderate | Standard remediation planning |
86
+ | 51-75 | Elevated | Surface to security leadership; quarter-by-quarter tracking |
87
+ | 76-90 | High | Executive attention; structured remediation plan |
88
+ | 91-100 | Critical | Treat as incident; urgent remediation |
89
+
90
+ The bands were chosen to match how exec stakeholders naturally
91
+ discretize risk. Five bands beats three (too coarse) or ten (too
92
+ fine).
93
+
94
+ ## Deterministic priority selection — why not human-curated
95
+
96
+ The top-3 priorities are picked algorithmically by severity +
97
+ reachability + alphabetical tie-break. Reproducibility wins over
98
+ nuance:
99
+
100
+ - Same findings → same top-3, always.
101
+ - The skill can be re-run after remediation to confirm priorities
102
+ changed.
103
+ - Auditors and customers can verify the prioritization wasn't
104
+ selectively edited to match a narrative.
105
+
106
+ The `--priority-overrides` flag exists for legitimate operator
107
+ intervention (e.g. "this hardcoded AWS key is the single biggest
108
+ risk regardless of count") but the default is algorithmic.
109
+
110
+ ## CVSS vs DREAD vs STRIDE risk frameworks
111
+
112
+ Several risk-scoring frameworks compete:
113
+
114
+ | Framework | Used for | Strengths | Why not here |
115
+ |---|---|---|---|
116
+ | CVSS | Per-vulnerability scoring | Industry-standard, NVD-blessed | Per-vuln, not aggregate; no exec-summary primitive |
117
+ | DREAD | Threat-modeling risk | Captures Damage/Reproducibility/Exploitability/Affected users/Discoverability | Not pentest-natural; weights are subjective |
118
+ | STRIDE | Threat categorization | Maps to threat types | Categorical, not numeric |
119
+ | EPSS | Real-world exploitation likelihood | Predictive, data-driven | Per-CVE, not per-engagement |
120
+ | FAIR | Quantitative risk in dollars | Most precise | Expensive to compute; requires asset-value modeling |
121
+
122
+ The skill's risk score is a custom aggregate optimized for the
123
+ exec-summary use case. It's not a substitute for any of the
124
+ above; it composes with them.
125
+
126
+ ## Effort + impact estimates
127
+
128
+ Each priority gets a rough effort (Hours / Days / Weeks) and
129
+ impact (Limited / Significant / Material) tag. These are
130
+ HEURISTIC and based on the source skill + reach. The skill
131
+ deliberately doesn't try to predict dollar impact or hour count —
132
+ those are owned by the customer's engineering team, not the
133
+ pentester.
134
+
135
+ Effort heuristics:
136
+
137
+ - Dependency upgrade — Hours to Days
138
+ - Hardcoded secret rotation — Hours
139
+ - Config / header fix — Days
140
+ - Injection / deserialization fix — Weeks (requires code changes)
141
+ - License compliance — Weeks (requires legal + dep swap)
142
+
143
+ Impact heuristics:
144
+
145
+ - CRITICAL severity → Material
146
+ - HIGH severity + reach ≥ 3 → Material
147
+ - HIGH severity + reach < 3 → Significant
148
+ - MEDIUM severity + reach ≥ 5 → Significant
149
+ - Otherwise → Limited
150
+
151
+ The customer's engineering team will refine these; the skill
152
+ provides starting estimates.
153
+
154
+ ## Document length
155
+
156
+ Target: 1-2 pages when rendered as PDF. The skill's output is
157
+ typically 60-100 lines of markdown, which fits cleanly on 1-2
158
+ US Letter pages.
159
+
160
+ Longer = unread. Shorter = content-free. The sections (Risk
161
+ score, Engagement scope, Top priorities, OWASP coverage, Next
162
+ steps) are non-negotiable; everything else is compression
163
+ optimization.
164
+
165
+ ## Stable rendering
166
+
167
+ Same findings + same ROE + same coverage → same exec summary
168
+ except for the generation date. This is important because the
169
+ exec summary may go to the board, to insurers, to auditors —
170
+ parties who will compare the document against any
171
+ re-rendered version.
172
+
173
+ If the summary changes between renderings without a finding
174
+ change, something is wrong. Sources of non-stability to avoid:
175
+
176
+ - Random tie-breaks (use alphabetical sort)
177
+ - LLM-based phrasing
178
+ - Time-stamped section content beyond the header date
179
+ - Counts that depend on the iteration order of dicts
180
+
181
+ The current implementation is stable. Future modifications must
182
+ preserve this.
183
+
184
+ ## Format choices
185
+
186
+ - Markdown for portability and version-control friendliness.
187
+ - Numeric tables for severity counts (machine-parseable).
188
+ - Per-priority subsections rather than a single bullet list
189
+ (gives each priority enough room to be acted on).
190
+ - Pointer to vulnerability-report.md anchors so the reader can
191
+ jump to the deep detail when needed.
192
+
193
+ PDF rendering is downstream; the skill's output is the source
194
+ markdown that a separate pdf-generator (e.g. `/whiteglove-pdf`)
195
+ can render for handoff.