coverme-security-scanner 3.7.4 → 3.7.7

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.
@@ -1,6 +1,6 @@
1
1
  # Security Assessment
2
2
 
3
- Run a security scan and generate a PDF report. Execute automatically without asking questions.
3
+ Run an enterprise-grade security assessment combining 4 review types into a unified report. Execute automatically without asking questions.
4
4
 
5
5
  ## Step 1: Setup
6
6
  ```bash
@@ -8,12 +8,283 @@ mkdir -p .coverme
8
8
  ```
9
9
 
10
10
  ## Step 2: Run Security Scan
11
- Use ONE Task agent with subagent_type="general-purpose" to perform the full security assessment:
11
+ Use ONE Task agent with subagent_type="general-purpose" to perform a COMPREHENSIVE assessment:
12
12
 
13
- prompt: "Perform a comprehensive security assessment of this codebase. Analyze: 1) Architecture and tech stack 2) API endpoints and attack surface 3) Security vulnerabilities (secrets, injection, XSS, auth issues) 4) Infrastructure (Docker, CI/CD, dependencies). When done, use the Write tool to create .coverme/scan.json with this structure: {\"project\":\"<name>\",\"date\":\"2026-02-19\",\"executiveSummary\":\"<summary>\",\"summary\":{\"critical\":0,\"high\":0,\"medium\":0,\"low\":0,\"total\":0},\"overallRiskLevel\":\"low|medium|high|critical\",\"findings\":[{\"id\":\"VULN-01\",\"title\":\"\",\"severity\":\"critical|high|medium|low\",\"file\":\"\",\"line\":0,\"issue\":\"\",\"why\":\"\",\"fix\":\"\",\"cwe\":\"\"}],\"architecture\":{\"overview\":\"\",\"components\":[]},\"positiveObservations\":[{\"title\":\"\",\"description\":\"\"}]}"
13
+ prompt: |
14
+ Perform a COMPREHENSIVE security assessment combining:
15
+ 1. Security Review (STRIDE vulnerabilities)
16
+ 2. Threat Model (DREAD scoring)
17
+ 3. Code Quality Review (dead code, DRY violations)
18
+ 4. Privacy Analysis (LINDDUN)
14
19
 
15
- ## Step 3: Wait for agent to complete
16
- Use AgentOutputTool to wait for the agent.
20
+ YOU MUST produce findings at the quality level of a professional security audit firm.
21
+ Target: 25-35 findings for a medium codebase, 40+ for large.
22
+
23
+ ## PHASE 1: Codebase Metrics
24
+
25
+ First, gather precise metrics:
26
+ ```
27
+ - Count total files: find . -type f \( -name "*.ts" -o -name "*.js" -o -name "*.tsx" -o -name "*.py" \) | wc -l
28
+ - Count lines: find . -type f \( -name "*.ts" -o -name "*.js" -o -name "*.tsx" -o -name "*.py" \) -exec wc -l {} + | tail -1
29
+ - List components (frontend/, backend/, api/, etc.)
30
+ - Map technology stack (React, Express, Postgres, etc.)
31
+ - Read .gitignore to know what's excluded
32
+ ```
33
+
34
+ ## PHASE 2: Architecture Analysis
35
+
36
+ Map the system:
37
+ - Identify all components with their technology
38
+ - Define trust boundaries (TB1-Browser, TB2-BFF, TB3-API, TB4-Database, TB5-External)
39
+ - Document entry points with auth method
40
+ - List critical assets (keys, tokens, PII, credentials)
41
+
42
+ ## PHASE 3: Security Vulnerabilities (STRIDE)
43
+
44
+ For EACH finding, you MUST include ALL of these:
45
+
46
+ **Required Fields:**
47
+ - **ID**: Use prefixes based on source:
48
+ - `T-FE-N`: Frontend threats
49
+ - `T-BE-N`: Backend threats
50
+ - `T-DB-N`: Database threats
51
+ - `T-ENC-N`: Encryption/enclave threats
52
+ - `CR-N`: Code review findings
53
+ - `SR-N`: Security review findings
54
+ - `QR-N`: Quality review items
55
+
56
+ - **Title**: Specific, not generic. Good: "Attestation Fallback Accepts Unverified Keys". Bad: "Security Issue"
57
+
58
+ - **File + Line Range**: Exact location with range. Example: `frontend/lib/e2e-encryption.ts:51-91`
59
+
60
+ - **Code References**: Include actual function/variable names inline:
61
+ - Good: "When unavailable, `fetchEnclaveInfo()` falls back and stores keys with `keysVerified: false`"
62
+ - Bad: "The function has a fallback"
63
+
64
+ - **DREAD Score**: Calculate each component (1-10):
65
+ - Damage: How bad if exploited?
66
+ - Reproducibility: How easy to reproduce?
67
+ - Exploitability: How easy to exploit?
68
+ - Affected Users: How many affected?
69
+ - Discoverability: How easy to find?
70
+ - Final: (D+R+E+A+D) / 5
71
+
72
+ - **Description**: 2-3 sentences explaining WHAT the code does wrong with inline `code references`
73
+
74
+ - **Recommendation**: Specific actionable fix, not generic advice
75
+
76
+ - **Status**: `open` | `partial` | `mitigated` | `accepted`
77
+
78
+ - **CWE**: Include CWE identifier (e.g., "CWE-295: Improper Certificate Validation")
79
+
80
+ - **relatedFindings**: Link to related findings when issues are connected
81
+
82
+ ### Vulnerability Categories to Check:
83
+
84
+ **Silent Fallbacks (CRITICAL priority)**:
85
+ - try/catch blocks that swallow errors and continue execution
86
+ - `||` operators providing insecure defaults (e.g., `password || 'default123'`)
87
+ - Authentication that defaults to "allow" on error
88
+ - Crypto operations falling back to weaker algorithms
89
+ - if/else branches that silently skip security checks
90
+ - Graceful degradation that removes security controls
91
+
92
+ **Hardcoded Credentials**:
93
+ - Default passwords in code (not just comments)
94
+ - API keys in source (not from env vars)
95
+ - Fallback credentials like `amqp://user:pass123@localhost`
96
+ - Secrets in Helm values, Docker configs, CI files
97
+
98
+ **Input Validation Gaps**:
99
+ - User input used in SQL/shell/eval without sanitization
100
+ - Missing regex validation on IDs, names, paths
101
+ - Unbounded arrays that could cause DoS
102
+ - Path traversal vulnerabilities
103
+
104
+ **Error Information Leaks**:
105
+ - `error.message` or `error.stack` returned to clients
106
+ - Internal hostnames/IPs in error responses
107
+ - Database errors exposed to users
108
+ - Debug info in production responses
109
+
110
+ **Authentication/Authorization**:
111
+ - Missing auth on sensitive endpoints
112
+ - Token validation issues
113
+ - Session management flaws
114
+ - Privilege escalation paths
115
+
116
+ **Cryptographic Issues**:
117
+ - Weak algorithms (MD5, SHA1 for security)
118
+ - Hardcoded IVs or keys
119
+ - Missing signature verification
120
+ - Key management flaws
121
+
122
+ ## PHASE 4: Code Quality Review
123
+
124
+ Find issues with LINE COUNTS:
125
+
126
+ **Dead Code (estimate removable lines)**:
127
+ - Functions defined but never called (trace call graph)
128
+ - Routes defined but not mounted
129
+ - Commented-out code blocks
130
+ - Example: "processMessage() - likely dead non-streaming path (~240 lines)"
131
+
132
+ **DRY Violations (estimate duplicated lines)**:
133
+ - Near-identical code blocks in multiple files
134
+ - Copy-pasted logic with minor variations
135
+ - Example: "CSV + Excel Handler process/prepareForStreaming nearly identical (~470 lines)"
136
+
137
+ **Deprecated Patterns**:
138
+ - Old API usage
139
+ - Legacy code paths
140
+ - Outdated dependencies
141
+
142
+ ## PHASE 5: Privacy Analysis (LINDDUN)
143
+
144
+ Analyze for privacy threats:
145
+ - **L**inkability: Can actions be linked to users?
146
+ - **I**dentifiability: Can users be identified?
147
+ - **N**on-repudiation: Can users deny actions?
148
+ - **D**etectability: Can user presence be detected?
149
+ - **D**isclosure: Is data disclosed inappropriately?
150
+ - **U**nawareness: Are users unaware of data collection?
151
+ - **N**on-compliance: Are regulations violated?
152
+
153
+ ## PHASE 6: Cross-Reference & Merge
154
+
155
+ **Merge duplicate findings**:
156
+ - When same issue found in multiple analyses, combine them
157
+ - Use format: "CR-02 / T-EKS-3: Hardcoded Tracker API Keys"
158
+
159
+ **Link related findings**:
160
+ - Add `relatedFindings: ["T-FE-2"]` when issues are connected
161
+ - Build attack chains showing how findings combine
162
+
163
+ ## PHASE 7: Identify Resolved Issues
164
+
165
+ Look for issues that WERE present but are NOW fixed:
166
+ - Commented code showing old vulnerable patterns
167
+ - Security controls that are properly implemented
168
+ - Previous findings that have been addressed
169
+
170
+ Document these in `resolvedIssues` with:
171
+ - What was the original issue
172
+ - How it was resolved
173
+ - Current security status
174
+
175
+ ## OUTPUT FORMAT
176
+
177
+ Create `.coverme/scan.json` with this EXACT structure:
178
+
179
+ ```json
180
+ {
181
+ "project": "<project-name>",
182
+ "date": "2026-02-19",
183
+ "branch": "main",
184
+ "scope": "<X> files, ~<Y> lines - Full platform assessment",
185
+ "components": ["Frontend (Next.js)", "Backend (Express)", "Database (Postgres)"],
186
+ "methodology": "STRIDE + DREAD-D + LINDDUN",
187
+ "reviewType": "Security + Threat Model + Code Quality + Privacy",
188
+ "author": "Claude Code",
189
+
190
+ "executiveSummary": "<3-4 paragraphs: 1) System overview 2) Security architecture 3) Key findings summary 4) Critical remaining issues>",
191
+ "overallRiskLevel": "low|medium|high|critical",
192
+
193
+ "summary": { "critical": 0, "high": 0, "medium": 0, "low": 0, "total": 0 },
194
+
195
+ "topPriorities": [
196
+ { "finding": "T-FE-1", "severity": "high", "action": "Block attestation fallback" }
197
+ ],
198
+
199
+ "architecture": {
200
+ "overview": "<1-2 sentences about system architecture>",
201
+ "components": [
202
+ {"name": "Frontend", "technology": "Next.js BFF", "description": "PKCE OAuth, session management"}
203
+ ],
204
+ "trustBoundaries": [
205
+ {"id": "TB1", "boundary": "Browser", "trustLevel": "untrusted", "description": "User browser environment"},
206
+ {"id": "TB2", "boundary": "API Gateway", "trustLevel": "semi-trusted", "description": "Holds OAuth tokens"}
207
+ ]
208
+ },
209
+
210
+ "findings": [
211
+ {
212
+ "id": "T-FE-1",
213
+ "title": "Attestation Fallback Accepts Unverified Keys",
214
+ "severity": "high",
215
+ "status": "open",
216
+ "file": "frontend/lib/e2e-encryption.ts",
217
+ "line": "51-91",
218
+ "dreadScore": 6.3,
219
+ "cwe": "CWE-295: Improper Certificate Validation",
220
+ "issue": "When the attestation bundle endpoint is unavailable, `fetchEnclaveInfo()` falls back to the legacy `/api/v1/enclave` endpoint and stores keys with `keysVerified: false`. The browser silently proceeds to encrypt messages with unverified public keys.",
221
+ "why": "This enables a man-in-the-middle attack by a compromised gateway. An attacker who controls the gateway can substitute their own keys and decrypt all messages.",
222
+ "fix": "Block the request or display a prominent security warning when attestation fails. Do not silently proceed with unverified keys. Consider: `if (!keysVerified) throw new AttestationError('Cannot proceed without verified keys')`",
223
+ "relatedFindings": ["T-FE-2", "CR-07"]
224
+ }
225
+ ],
226
+
227
+ "threatModel": [
228
+ {"id": "T-FE-1", "severity": "high", "dread": 6.3, "status": "partial", "finding": "Attestation fallback accepts unverified keys"},
229
+ {"id": "T-ENC-2", "severity": "low", "dread": 2.0, "status": "mitigated", "finding": "Session key zeroization implemented"}
230
+ ],
231
+
232
+ "qualityReview": {
233
+ "deadCode": [
234
+ {"type": "dead-code", "action": "DELETE", "file": "src/old-handler.js", "line": 1, "description": "processMessage() - likely dead non-streaming path (~240 lines)"}
235
+ ],
236
+ "dryViolations": [
237
+ {"type": "dry-violation", "action": "MERGE", "file": "src/handlers/csv.js", "description": "CSV + Excel Handler process/prepareForStreaming nearly identical (~470 lines)", "relatedFiles": ["src/handlers/excel.js"]}
238
+ ]
239
+ },
240
+
241
+ "positiveObservations": [
242
+ {"title": "Zero-Knowledge Architecture", "description": "API gateway genuinely never sees plaintext. Encrypted payloads flow through without decryption."},
243
+ {"title": "Atomic Credit Operations", "description": "Lua scripts for token burning prevent cross-pod race conditions."},
244
+ {"title": "Post-Quantum Cryptography", "description": "XWing (ML-KEM-768 + X25519) hybrid KEM with Ed25519 signing."}
245
+ ],
246
+
247
+ "resolvedIssues": [
248
+ {"id": "RES-01", "title": "SQL Injection in DuckDB", "severity": "critical", "resolution": "Resolved: enable_external_access=false sandbox mode + SQL validation blocklist."},
249
+ {"id": "RES-02", "title": "Admin API Fail-Open", "severity": "high", "resolution": "Resolved: Binds to 127.0.0.1 by default. Fail-closed when no ADMIN_ALLOWED_IPS configured."}
250
+ ],
251
+
252
+ "privacyAnalysis": [
253
+ {"category": "Linkability", "risk": "medium", "description": "User actions can be linked via hashed KRN in metrics", "mitigation": "SHA-256 hashing provides pseudonymization"},
254
+ {"category": "Identifiability", "risk": "low", "description": "KRN logged in some paths enables identification", "mitigation": "Replace with getUserHash() in all logs"}
255
+ ],
256
+
257
+ "remediation": {
258
+ "p0": [{"action": "Remove hardcoded secrets from Helm values. Move to Secrets Manager. Rotate keys.", "finding": "CR-02", "owner": "DevOps"}],
259
+ "p1": [{"action": "Block attestation fallback or show prominent warning", "finding": "T-FE-1", "owner": "Frontend"}],
260
+ "p2": [{"action": "Extract Redis metrics to shared module (~160 lines)", "finding": "QR-16", "owner": "Backend"}]
261
+ }
262
+ }
263
+ ```
264
+
265
+ ## QUALITY REQUIREMENTS
266
+
267
+ **Minimum Thresholds:**
268
+ - 25+ findings for medium codebase (5k-50k lines)
269
+ - 40+ findings for large codebase (50k+ lines)
270
+ - Every HIGH/CRITICAL finding MUST have exact file:line
271
+ - Every finding MUST have DREAD score
272
+ - Every finding MUST have CWE identifier
273
+ - Include at least 5 positive observations
274
+ - Include code quality items with line counts
275
+ - Cross-reference related findings
276
+ - Include at least 3 resolved issues (if any exist)
277
+ - Include LINDDUN privacy analysis
278
+
279
+ **Quality Checks:**
280
+ - NO generic findings like "Consider adding validation"
281
+ - NO findings without file locations
282
+ - NO DREAD scores without calculation
283
+ - ALL code references must use actual function/variable names from the code
284
+ - ALL recommendations must be actionable, not vague
285
+
286
+ ## Step 3: Wait for agent
287
+ Use AgentOutputTool to wait for completion.
17
288
 
18
289
  ## Step 4: Generate PDF
19
290
  ```bash
@@ -402,9 +402,7 @@ export class PDFGenerator {
402
402
  this.y = this.doc.y + spacing.paragraph;
403
403
  }
404
404
  if (report.architecture?.components?.length) {
405
- // Start components table on new page to keep it together
406
- this.newPage();
407
- this.y = spacing.page.top;
405
+ this.checkPageBreak(150);
408
406
  this.subTitle('Components');
409
407
  this.renderSimpleTable(['Component', 'Technology', 'Description'], report.architecture.components.map(c => [c.name, c.technology, c.description]), [100, 150, 245]);
410
408
  }
@@ -616,46 +614,78 @@ export class PDFGenerator {
616
614
  const boxPadding = 12;
617
615
  const boxInnerWidth = layout.content.width - (boxPadding * 2);
618
616
  const style = colors.severity[finding.severity];
619
- // ID in severity color, title in black - allow wrapping for long titles
620
- const titleText = `[${finding.id}] ${finding.title}`;
621
- const titleHeight = this.doc
617
+ // Finding ID in accent color
618
+ this.doc
622
619
  .font(fonts.weights.bold)
623
620
  .fontSize(fonts.sizes.body)
624
- .heightOfString(titleText, { width: layout.content.width });
621
+ .fillColor(colors.accent)
622
+ .text(finding.id, spacing.page.margin, this.y);
623
+ this.y += 18;
624
+ // Title - large and prominent
625
625
  this.doc
626
626
  .font(fonts.weights.bold)
627
- .fontSize(fonts.sizes.body)
628
- .fillColor(style.text)
629
- .text(`[${finding.id}]`, spacing.page.margin, this.y, { continued: true })
627
+ .fontSize(fonts.sizes.h3)
630
628
  .fillColor(colors.text.primary)
631
- .text(` ${finding.title}`, { width: layout.content.width - 60 });
632
- this.y = this.doc.y + 4;
633
- // Cross-references and DREAD score line
634
- const hasRefs = finding.relatedFindings?.length || finding.dreadScore || finding.cwe;
635
- if (hasRefs) {
636
- const parts = [];
637
- if (finding.dreadScore)
638
- parts.push(`DREAD: ${finding.dreadScore.toFixed(1)}`);
639
- if (finding.cwe)
640
- parts.push(finding.cwe);
641
- if (finding.relatedFindings?.length) {
642
- parts.push(`Related: ${finding.relatedFindings.join(', ')}`);
643
- }
629
+ .text(finding.title, spacing.page.margin, this.y, { width: layout.content.width });
630
+ this.y = this.doc.y + 6;
631
+ // Severity badge (small pill)
632
+ const badgeHeight = 16;
633
+ const severityText = finding.severity.toUpperCase();
634
+ const severityWidth = this.doc.font(fonts.weights.bold).fontSize(7).widthOfString(severityText) + 12;
635
+ this.doc
636
+ .roundedRect(spacing.page.margin, this.y, severityWidth, badgeHeight, 3)
637
+ .fill(style.bg);
638
+ this.doc
639
+ .font(fonts.weights.bold)
640
+ .fontSize(7)
641
+ .fillColor(style.text)
642
+ .text(severityText, spacing.page.margin + 6, this.y + 4);
643
+ let xOffset = spacing.page.margin + severityWidth + 6;
644
+ // Status badge (if present) - small colored text, no box
645
+ if (finding.status) {
646
+ const statusColors = {
647
+ open: '#DC2626',
648
+ partial: '#D97706',
649
+ mitigated: '#059669',
650
+ accepted: '#4F46E5',
651
+ resolved: '#059669',
652
+ };
653
+ const statusColor = statusColors[finding.status] || statusColors.open;
654
+ const statusText = finding.status.charAt(0).toUpperCase() + finding.status.slice(1);
644
655
  this.doc
645
- .font(fonts.weights.normal)
646
- .fontSize(fonts.sizes.small)
647
- .fillColor(colors.text.muted)
648
- .text(parts.join(' | '), spacing.page.margin, this.y);
649
- this.y += 14;
656
+ .font(fonts.weights.bold)
657
+ .fontSize(9)
658
+ .fillColor(statusColor)
659
+ .text(statusText, xOffset, this.y + 3);
650
660
  }
651
- // File reference (if present)
661
+ this.y += badgeHeight + 8;
662
+ // File reference with line numbers (if present)
652
663
  if (finding.file) {
653
664
  this.doc
654
665
  .font(fonts.mono)
655
666
  .fontSize(fonts.sizes.small)
656
667
  .fillColor(colors.accent)
657
668
  .text(`${finding.file}${finding.line ? `:${finding.line}` : ''}`, spacing.page.margin, this.y);
658
- this.y += 18;
669
+ this.y += 16;
670
+ }
671
+ // DREAD/CVSS score and metadata line
672
+ const metaParts = [];
673
+ if (finding.dreadScore)
674
+ metaParts.push(`DREAD: ${finding.dreadScore.toFixed(1)}`);
675
+ if (finding.cvssScore)
676
+ metaParts.push(`CVSS: ${finding.cvssScore.toFixed(1)}`);
677
+ if (finding.cwe)
678
+ metaParts.push(finding.cwe);
679
+ if (finding.relatedFindings?.length) {
680
+ metaParts.push(`Related: ${finding.relatedFindings.join(', ')}`);
681
+ }
682
+ if (metaParts.length > 0) {
683
+ this.doc
684
+ .font(fonts.weights.normal)
685
+ .fontSize(fonts.sizes.small)
686
+ .fillColor(colors.text.muted)
687
+ .text(metaParts.join(' | '), spacing.page.margin, this.y);
688
+ this.y += 16;
659
689
  }
660
690
  // ─────────────────────────────────────────────────────────────
661
691
  // Check for structured format (issue/why/fix) vs legacy format
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coverme-security-scanner",
3
- "version": "3.7.4",
3
+ "version": "3.7.7",
4
4
  "description": "AI-powered security assessment reports with beautiful PDF output",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,7 +18,8 @@
18
18
  },
19
19
  "scripts": {
20
20
  "build": "tsc",
21
- "prepublishOnly": "npm run build"
21
+ "prepublishOnly": "npm run build",
22
+ "postinstall": "node bin/install-command.js --global || true"
22
23
  },
23
24
  "files": [
24
25
  "dist",