coverme-scanner 1.0.19 → 1.0.21

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.
@@ -4,7 +4,15 @@ The most comprehensive AI-powered code scanner. 10 specialized agents + 3 valida
4
4
 
5
5
  $ARGUMENTS
6
6
 
7
- ## IMPORTANT: Execute ALL phases automatically. Do NOT stop until the HTML report is open.
7
+ ## CRITICAL INSTRUCTIONS - READ FIRST!
8
+
9
+ 1. **DO NOT ASK ANY QUESTIONS** - Run the entire scan autonomously from start to finish
10
+ 2. **DO NOT STOP FOR CONFIRMATION** - Just keep going through all phases
11
+ 3. **DO NOT ASK ABOUT FILE CHANGES** - Automatically update/overwrite scan.json
12
+ 4. **DO NOT ASK TO OPEN REPORT** - Just open it automatically at the end
13
+ 5. **COMPLETE EVERYTHING IN ONE GO** - All 5 phases without interruption
14
+
15
+ Execute ALL phases automatically. Do NOT stop until the HTML report is open.
8
16
 
9
17
  ---
10
18
 
@@ -471,7 +479,9 @@ Combine all results:
471
479
 
472
480
  ## Phase 4: Generate Report
473
481
 
474
- Update the existing `.coverme/scan.json` file with the scan results. The file already exists with the correct structure - just fill in the values:
482
+ **DO NOT ASK - JUST OVERWRITE THE FILE!**
483
+
484
+ Update `.coverme/scan.json` with the scan results. Overwrite any existing content without asking:
475
485
 
476
486
  - **projectName**: from package.json or folder name
477
487
  - **scanDate**: today's date
@@ -480,13 +490,15 @@ Update the existing `.coverme/scan.json` file with the scan results. The file al
480
490
  - **scanDuration**: time taken in ms
481
491
  - **agentCount**: 7
482
492
 
483
- Use the Edit tool to update `.coverme/scan.json` with the results.
493
+ Use the Write tool to overwrite `.coverme/scan.json` with the results. Do not ask for confirmation.
484
494
 
485
495
  ---
486
496
 
487
497
  ## Phase 5: Generate HTML Report
488
498
 
489
- Generate the HTML report and open it:
499
+ **DO NOT ASK - JUST RUN THE COMMANDS!**
500
+
501
+ Generate the HTML report and open it automatically:
490
502
  ```bash
491
503
  TIMESTAMP=$(date +%Y-%m-%d_%H-%M-%S)
492
504
  npx coverme-scanner report .coverme/scan.json -f html -o ".coverme/report_$TIMESTAMP.html"
@@ -494,8 +506,12 @@ cp .coverme/scan.json ".coverme/scan_$TIMESTAMP.json"
494
506
  open ".coverme/report_$TIMESTAMP.html"
495
507
  ```
496
508
 
509
+ Run these commands without asking for permission.
510
+
497
511
  ---
498
512
 
499
513
  ## DONE
500
514
 
501
- Tell the user: "Scan complete! Report saved to .coverme/ and opened in browser. Found X issues across Y categories. All scan history is in .coverme/ folder."
515
+ Tell the user: "Scan complete! Report saved to .coverme/ and opened in browser."
516
+
517
+ **REMINDER: You should have completed all 5 phases without asking ANY questions or stopping for confirmation.**
@@ -223,4 +223,48 @@ Focus: Find what was MISSED
223
223
  - Don't ignore context from CLAUDE.md
224
224
  - Don't miss the forest for the trees
225
225
 
226
+ ## CRITICAL: Things That Are NOT False Positives
227
+
228
+ ### Command Injection from Config Files
229
+ **DO NOT dismiss as false positive!**
230
+ ```javascript
231
+ execSync(`pm2 start ${configValue}`) // STILL VULNERABLE!
232
+ ```
233
+ Even if the value comes from a config file (models.json, config.yaml), if that file is:
234
+ - Writable by users (admin panel, API)
235
+ - Not validated against a strict schema
236
+ - Could be modified by an attacker with file access
237
+
238
+ Then it IS a real command injection. The attack vector is just indirect.
239
+
240
+ **Only dismiss if:**
241
+ - Config file is hardcoded at build time (not runtime loaded)
242
+ - Config values are validated against strict regex/enum
243
+ - execFile() is used instead of execSync() with proper argument array
244
+
245
+ ### Secrets in Git History
246
+ **DO NOT dismiss just because file is now gitignored!**
247
+ If a secret file was EVER committed, it may still be in git history.
248
+ ```bash
249
+ git log --all --full-history -- "**/secrets*" "**/credentials*" "**/*.env"
250
+ ```
251
+ If this returns results, the secret is STILL EXPOSED even if currently gitignored.
252
+
253
+ ### CORS Without Whitelist
254
+ **DO NOT dismiss as "internal only"!**
255
+ ```javascript
256
+ res.header('Access-Control-Allow-Origin', req.headers.origin); // VULNERABLE
257
+ ```
258
+ This reflects ANY origin. Even if the server is "internal", browser-based attacks can still:
259
+ - Steal data via malicious website
260
+ - Perform CSRF-like attacks
261
+ - Exfiltrate to attacker-controlled domains
262
+
263
+ ### Missing Security Configuration
264
+ **These are real findings, not false positives:**
265
+ - `helmet()` without custom CSP configuration
266
+ - Missing `npm audit` in CI pipeline
267
+ - No Dependabot/Renovate for dependency updates
268
+ - Logs without rotation/retention policy
269
+
226
270
  START VALIDATION NOW. Be critical but fair.
@@ -178,6 +178,74 @@ The finding is incorrect:
178
178
  3. Is it localhost/development credentials only?
179
179
  4. Is there environment variable loading that overrides?
180
180
 
181
+ ### Race Condition / TOCTOU Findings (CRITICAL - Often False Positives)
182
+ **Check for atomic operations that FULLY mitigate the race:**
183
+
184
+ 1. **Redis Lua Scripts** = FULL MITIGATION
185
+ - `redis.call()` inside Lua script is atomic
186
+ - SETNX, GETSET, INCR are atomic
187
+ - Look for: `eval`, `evalsha`, `script load`
188
+ ```javascript
189
+ // This is ATOMIC - no race condition!
190
+ redis.eval(`
191
+ local current = redis.call('GET', key)
192
+ if current < limit then
193
+ redis.call('INCR', key)
194
+ return 1
195
+ end
196
+ return 0
197
+ `)
198
+ ```
199
+
200
+ 2. **Database Transactions** = FULL MITIGATION
201
+ - `BEGIN...COMMIT` with proper isolation
202
+ - `SELECT FOR UPDATE` locks rows
203
+ - Prisma `$transaction()`, TypeORM `transaction()`
204
+ - Look for: `transaction`, `FOR UPDATE`, `SERIALIZABLE`
205
+
206
+ 3. **Atomic Compare-and-Swap** = FULL MITIGATION
207
+ - `WATCH/MULTI/EXEC` in Redis
208
+ - `findOneAndUpdate` with conditions in MongoDB
209
+ - `UPDATE ... WHERE version = ?` (optimistic locking)
210
+
211
+ 4. **Mutex/Locking** = FULL MITIGATION
212
+ - `redis-lock`, `redlock`
213
+ - Database advisory locks
214
+ - File locks (flock)
215
+
216
+ **If ANY of these patterns exist, mark as MITIGATED, not "partial"!**
217
+
218
+ ### Intentional Design Decisions (Check Comments!)
219
+ **Before reporting, check if there are comments explaining WHY:**
220
+
221
+ 1. **Search for explanatory comments near the code:**
222
+ ```
223
+ grep -B5 -A5 "intentional|by design|deliberately|on purpose|security note" <file>
224
+ ```
225
+
226
+ 2. **Common patterns that are INTENTIONAL:**
227
+ - PKCE code reuse to prevent double-click race conditions
228
+ - Longer token expiry for better UX (with other mitigations)
229
+ - Allowing certain "unsafe" operations for admin users
230
+ - Development-only bypasses with environment checks
231
+
232
+ 3. **If comment explains the decision:**
233
+ ```json
234
+ {
235
+ "verdict": "false_positive",
236
+ "reason": "Intentional design decision documented in code",
237
+ "evidence": ["Comment at line 45: 'Intentionally allow reuse to prevent double-submit'"]
238
+ }
239
+ ```
240
+
241
+ ### Open Redirect Findings
242
+ 1. **Check for whitelist validation:**
243
+ ```
244
+ grep -r "isValidRedirect|allowedDomains|whitelist|validateUrl" <file>
245
+ ```
246
+ 2. If whitelist exists and covers the redirect parameter = MITIGATED
247
+ 3. Check if validation function is actually called before redirect
248
+
181
249
  ## Output Format
182
250
 
183
251
  ```json
@@ -158,6 +158,32 @@ CHECK FOR:
158
158
  - API versioning issues
159
159
  - Excessive data exposure in responses
160
160
 
161
+ **CORS MISCONFIGURATION** (MEDIUM):
162
+ Look for these vulnerable patterns:
163
+ ```javascript
164
+ // VULNERABLE - reflects ANY origin
165
+ res.header('Access-Control-Allow-Origin', req.headers.origin);
166
+ res.header('Access-Control-Allow-Origin', '*');
167
+
168
+ // VULNERABLE - no whitelist validation
169
+ app.use(cors({ origin: true }));
170
+ ```
171
+ Only mark as safe if there's explicit whitelist validation:
172
+ ```javascript
173
+ const allowedOrigins = ['https://app.example.com'];
174
+ if (allowedOrigins.includes(origin)) { ... }
175
+ ```
176
+
177
+ **HELMET MISCONFIGURATION** (MEDIUM):
178
+ ```javascript
179
+ app.use(helmet()); // Using defaults only - INSUFFICIENT!
180
+ ```
181
+ Check that helmet() includes:
182
+ - Custom `contentSecurityPolicy` with proper directives
183
+ - `hsts: { maxAge: 31536000, includeSubDomains: true, preload: true }`
184
+ - Proper `referrerPolicy`
185
+ Report as MEDIUM if using only defaults without customization.
186
+
161
187
  **FAIL-OPEN vs FAIL-CLOSED PATTERNS** (CRITICAL):
162
188
  - IP whitelist empty/missing = allow all (should deny all)
163
189
  - Auth middleware errors = request passes through (should block)
@@ -207,6 +233,14 @@ CHECK FOR:
207
233
  - Ansible vault passwords in plaintext
208
234
  - CI/CD pipeline secrets in yaml files (.github/workflows, .gitlab-ci.yml)
209
235
 
236
+ **SECRETS IN GIT HISTORY** (CRITICAL CHECK!):
237
+ Run these commands to check if secrets were EVER committed:
238
+ ```bash
239
+ git log --all --full-history -- "**/secrets*" "**/credentials*" "**/*.env"
240
+ git log --all -p -S "AWS_SECRET" -S "PRIVATE_KEY" --source
241
+ ```
242
+ If secrets appear in history, they are EXPOSED even if now gitignored!
243
+
210
244
  **PRIVILEGE ESCALATION RISKS**:
211
245
  - Containers/processes running as root
212
246
  - Missing securityContext in K8s (runAsNonRoot, readOnlyRootFilesystem)
@@ -220,6 +254,20 @@ CHECK FOR:
220
254
  - Missing config = silent fallback to insecure defaults
221
255
  - No validation of secret strength/format at startup
222
256
 
257
+ **DEPENDENCY SECURITY** (HIGH if missing):
258
+ Check for presence of:
259
+ - `npm audit` or `yarn audit` in CI pipeline
260
+ - Dependabot/Renovate configuration (.github/dependabot.yml, renovate.json)
261
+ - SBOM generation (cyclonedx, syft)
262
+ - Snyk/Trivy/Grype scanning
263
+ Report as HIGH if NONE of these exist - supply chain risk!
264
+
265
+ **LOGGING & MONITORING**:
266
+ - Log rotation configured? (maxFiles, maxsize in Winston/Pino)
267
+ - Log retention policy defined?
268
+ - Sensitive data redacted from logs?
269
+ Report as LOW if log rotation missing - disk exhaustion risk.
270
+
223
271
  For EACH finding, output the FULL JSON format.
224
272
 
225
273
  ---
@@ -577,63 +625,107 @@ Output as list of strings.
577
625
 
578
626
  ## PHASE 7: BUILD CONSENSUS & GENERATE OUTPUT
579
627
 
580
- 1. **Apply Mitigation Results** (from Phase 3):
581
- - Remove findings marked as `mitigated` or `false_positive`
582
- - Adjust severity for findings marked as `partial`
583
- - Add mitigation notes to confirmed findings
628
+ ### CRITICAL: Actually Remove False Positives!
584
629
 
585
- 2. Calculate confidence: (confirmations / total_validators) * 100
586
- 3. Remove findings with confidence < 50%
587
- 4. Add missed issues from Validator C
588
- 5. Sort: severity DESC, confidence DESC
630
+ The final report should ONLY contain findings that are:
631
+ 1. **Confirmed** by mitigation validation (no existing protection found)
632
+ 2. **Partial** mitigations (some protection but incomplete)
589
633
 
590
- ### Include Mitigation Summary
634
+ **DO NOT INCLUDE** findings that are:
635
+ - `mitigated` - full protection exists elsewhere
636
+ - `false_positive` - not actually a vulnerability
637
+ - Intentional design decisions with documented comments
638
+ - Race conditions protected by atomic operations (Lua, transactions)
591
639
 
592
- For each finding that passed validation, include:
593
- ```json
594
- {
595
- "id": "SEC-001",
596
- "mitigationStatus": "confirmed",
597
- "mitigationChecks": [
598
- "No input validation found between user input and SQL query",
599
- "No ORM - raw SQL used",
600
- "No middleware protection on this route"
601
- ]
602
- }
603
- ```
640
+ ### Step-by-Step Process:
604
641
 
605
- ### SAVE OUTPUT AS JSON
642
+ 1. **Start with all Phase 1 findings**
643
+
644
+ 2. **Apply Mitigation Validator results (Phase 3):**
645
+ - `mitigated` → REMOVE from findings, add to `mitigatedFindings` array
646
+ - `false_positive` → REMOVE from findings, add to `falsePositives` array
647
+ - `partial` → KEEP but downgrade severity if specified
648
+ - `confirmed` → KEEP with original severity
649
+
650
+ 3. **Apply Cross-Validator results (Phase 4):**
651
+ - Additional false positives → REMOVE from findings
652
+ - Duplicates → Merge into single finding
653
+
654
+ 4. **Calculate final counts AFTER removals:**
655
+ - Only count findings that remain in the `findings` array
656
+ - Do NOT count mitigated or false positive findings
657
+
658
+ 5. **Add missed issues from Validator C**
659
+
660
+ 6. **Sort remaining findings:** severity DESC, confidence DESC
661
+
662
+ ### Final JSON Structure
606
663
 
607
664
  ```json
608
665
  {
609
666
  "projectName": "project-name",
610
667
  "scanDate": "{{SCAN_DATE}}",
611
668
  "summary": {
612
- "total": 0,
613
- "critical": 0,
614
- "high": 0,
615
- "medium": 0,
616
- "low": 0,
617
- "info": 0
669
+ "total": 10,
670
+ "critical": 1,
671
+ "high": 3,
672
+ "medium": 4,
673
+ "low": 2,
674
+ "info": 0,
675
+ "mitigatedCount": 5,
676
+ "falsePositiveCount": 3
618
677
  },
619
678
  "findings": [
620
- "all findings with full fields including mitigationStatus"
679
+ "ONLY confirmed and partial findings - NOT mitigated or false positives!"
621
680
  ],
622
681
  "mitigatedFindings": [
623
- {"id": "SEC-005", "reason": "Protected by Zod schema validation", "originalSeverity": "high"}
682
+ {
683
+ "id": "SEC-005",
684
+ "title": "Original finding title",
685
+ "originalSeverity": "high",
686
+ "reason": "Protected by Zod schema validation at src/routes/user.ts:23",
687
+ "mitigationType": "input_validation"
688
+ }
689
+ ],
690
+ "falsePositives": [
691
+ {
692
+ "id": "BIZ-004",
693
+ "title": "TOCTOU Race Condition",
694
+ "reason": "Redis Lua script provides atomic operation - no race condition possible",
695
+ "evidence": ["Lua script at src/services/rate-limit.js:95-113"]
696
+ },
697
+ {
698
+ "id": "AUTH-003",
699
+ "title": "PKCE Code Reuse",
700
+ "reason": "Intentional design decision documented in code comment",
701
+ "evidence": ["Comment: 'Allow reuse to prevent double-click race condition'"]
702
+ }
624
703
  ],
625
704
  "positiveObservations": [
626
705
  "Good pattern 1",
627
706
  "Good pattern 2"
628
707
  ],
629
- "falsePositives": [
630
- {"id": "...", "reason": "..."}
631
- ],
708
+ "validationSummary": {
709
+ "totalInitialFindings": 18,
710
+ "mitigated": 5,
711
+ "falsePositives": 3,
712
+ "confirmed": 8,
713
+ "partial": 2,
714
+ "accuracy": "Only 56% of initial findings were actual issues"
715
+ },
632
716
  "agentsUsed": ["Security Core", "Auth & Session", "Mitigation Validator"],
633
717
  "scanDuration": 0
634
718
  }
635
719
  ```
636
720
 
721
+ ### Sanity Check Before Saving
722
+
723
+ Before saving, verify:
724
+ 1. `findings` array does NOT contain any item from `mitigatedFindings` or `falsePositives`
725
+ 2. `summary.total` equals `findings.length`
726
+ 3. Severity counts match actual findings in array
727
+ 4. No duplicate IDs across findings/mitigated/falsePositives
728
+
637
729
  Save as: .coverme/scan.json
638
730
 
639
731
  Then generate PDF report:
@@ -145,12 +145,21 @@ Before reporting ANY secret/credential finding as critical or high:
145
145
  - If file matches .gitignore patterns = NOT exposed in repo
146
146
  - Mark as "info" severity, not "critical"
147
147
 
148
- 3. **Identify environment context**:
148
+ 3. **CRITICAL: Check git HISTORY for secrets!**
149
+ Even if a file is currently gitignored, it may have been committed in the past:
150
+ ```bash
151
+ git log --all --full-history -- "**/secrets*" "**/credentials*" "**/*.env"
152
+ git log --all -p -S "AWS_SECRET" --source --all
153
+ ```
154
+ If the secret was EVER committed, it's CRITICAL - secrets in git history are exposed!
155
+
156
+ 4. **Identify environment context**:
149
157
  - `localhost`, `127.0.0.1`, `example.com` = development/example credentials
150
158
  - `.env.example`, `*.example.json` = template files, not real secrets
151
159
  - Mark these as "info" with note: "Development/example credentials"
152
160
 
153
- 4. **Severity mapping for secrets**:
161
+ 5. **Severity mapping for secrets**:
162
+ - In git history (even if now removed) = CRITICAL
154
163
  - Tracked in git + real credentials = CRITICAL
155
164
  - Tracked in git + example/dev credentials = LOW
156
165
  - NOT tracked (gitignored) + real credentials = INFO (local only)
@@ -161,10 +170,62 @@ Always include in finding:
161
170
  {
162
171
  "gitTracked": true/false,
163
172
  "gitignored": true/false,
173
+ "inGitHistory": true/false,
164
174
  "appearsToBeDev": true/false
165
175
  }
166
176
  ```
167
177
 
178
+ ## Command Injection: Config Files Are NOT Safe!
179
+
180
+ **DO NOT assume config file values are safe:**
181
+ ```javascript
182
+ // STILL VULNERABLE even though pm2Name comes from config!
183
+ const pm2Name = config.models[modelId].pm2Name;
184
+ execSync(`pm2 start ${pm2Name}`); // Command injection!
185
+ ```
186
+
187
+ Config files (models.json, config.yaml) are attack vectors if:
188
+ - File can be modified via admin panel/API
189
+ - File permissions allow non-root writes
190
+ - No schema validation on config values
191
+
192
+ **Only mark as safe if:**
193
+ - Using execFile() with argument array (not string interpolation)
194
+ - Config values validated against strict whitelist/regex
195
+ - Config is hardcoded at build time (not runtime loaded)
196
+
197
+ ## Security Misconfiguration Checks
198
+
199
+ ### Helmet Without Proper CSP
200
+ ```javascript
201
+ app.use(helmet()); // Defaults only - NOT sufficient!
202
+ ```
203
+ Report as MEDIUM if helmet() is called without:
204
+ - Custom `contentSecurityPolicy` configuration
205
+ - `hsts: { preload: true }` for HTTPS enforcement
206
+ - Proper `referrerPolicy`
207
+
208
+ ### CORS Without Whitelist
209
+ ```javascript
210
+ // VULNERABLE - reflects any origin!
211
+ res.header('Access-Control-Allow-Origin', req.headers.origin);
212
+ res.header('Access-Control-Allow-Origin', '*');
213
+ ```
214
+ Report as MEDIUM unless there's explicit domain whitelist validation.
215
+
216
+ ### Missing Dependency Security
217
+ Check for absence of:
218
+ - `npm audit` in CI/CD pipeline (.github/workflows, .gitlab-ci.yml)
219
+ - Dependabot/Renovate configuration
220
+ - SBOM generation
221
+ Report as HIGH if none exist - supply chain attacks are critical.
222
+
223
+ ### Missing Log Rotation
224
+ Check Winston/Pino/Bunyan configs for:
225
+ - `maxFiles` or `maxsize` settings
226
+ - Log retention policy
227
+ Report as LOW if missing - can lead to disk exhaustion.
228
+
168
229
  ## Files to Focus On
169
230
 
170
231
  Priority order:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coverme-scanner",
3
- "version": "1.0.19",
3
+ "version": "1.0.21",
4
4
  "description": "AI-powered code scanner with multi-agent verification for Claude Code. One command scans everything.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -223,4 +223,48 @@ Focus: Find what was MISSED
223
223
  - Don't ignore context from CLAUDE.md
224
224
  - Don't miss the forest for the trees
225
225
 
226
+ ## CRITICAL: Things That Are NOT False Positives
227
+
228
+ ### Command Injection from Config Files
229
+ **DO NOT dismiss as false positive!**
230
+ ```javascript
231
+ execSync(`pm2 start ${configValue}`) // STILL VULNERABLE!
232
+ ```
233
+ Even if the value comes from a config file (models.json, config.yaml), if that file is:
234
+ - Writable by users (admin panel, API)
235
+ - Not validated against a strict schema
236
+ - Could be modified by an attacker with file access
237
+
238
+ Then it IS a real command injection. The attack vector is just indirect.
239
+
240
+ **Only dismiss if:**
241
+ - Config file is hardcoded at build time (not runtime loaded)
242
+ - Config values are validated against strict regex/enum
243
+ - execFile() is used instead of execSync() with proper argument array
244
+
245
+ ### Secrets in Git History
246
+ **DO NOT dismiss just because file is now gitignored!**
247
+ If a secret file was EVER committed, it may still be in git history.
248
+ ```bash
249
+ git log --all --full-history -- "**/secrets*" "**/credentials*" "**/*.env"
250
+ ```
251
+ If this returns results, the secret is STILL EXPOSED even if currently gitignored.
252
+
253
+ ### CORS Without Whitelist
254
+ **DO NOT dismiss as "internal only"!**
255
+ ```javascript
256
+ res.header('Access-Control-Allow-Origin', req.headers.origin); // VULNERABLE
257
+ ```
258
+ This reflects ANY origin. Even if the server is "internal", browser-based attacks can still:
259
+ - Steal data via malicious website
260
+ - Perform CSRF-like attacks
261
+ - Exfiltrate to attacker-controlled domains
262
+
263
+ ### Missing Security Configuration
264
+ **These are real findings, not false positives:**
265
+ - `helmet()` without custom CSP configuration
266
+ - Missing `npm audit` in CI pipeline
267
+ - No Dependabot/Renovate for dependency updates
268
+ - Logs without rotation/retention policy
269
+
226
270
  START VALIDATION NOW. Be critical but fair.
@@ -178,6 +178,74 @@ The finding is incorrect:
178
178
  3. Is it localhost/development credentials only?
179
179
  4. Is there environment variable loading that overrides?
180
180
 
181
+ ### Race Condition / TOCTOU Findings (CRITICAL - Often False Positives)
182
+ **Check for atomic operations that FULLY mitigate the race:**
183
+
184
+ 1. **Redis Lua Scripts** = FULL MITIGATION
185
+ - `redis.call()` inside Lua script is atomic
186
+ - SETNX, GETSET, INCR are atomic
187
+ - Look for: `eval`, `evalsha`, `script load`
188
+ ```javascript
189
+ // This is ATOMIC - no race condition!
190
+ redis.eval(`
191
+ local current = redis.call('GET', key)
192
+ if current < limit then
193
+ redis.call('INCR', key)
194
+ return 1
195
+ end
196
+ return 0
197
+ `)
198
+ ```
199
+
200
+ 2. **Database Transactions** = FULL MITIGATION
201
+ - `BEGIN...COMMIT` with proper isolation
202
+ - `SELECT FOR UPDATE` locks rows
203
+ - Prisma `$transaction()`, TypeORM `transaction()`
204
+ - Look for: `transaction`, `FOR UPDATE`, `SERIALIZABLE`
205
+
206
+ 3. **Atomic Compare-and-Swap** = FULL MITIGATION
207
+ - `WATCH/MULTI/EXEC` in Redis
208
+ - `findOneAndUpdate` with conditions in MongoDB
209
+ - `UPDATE ... WHERE version = ?` (optimistic locking)
210
+
211
+ 4. **Mutex/Locking** = FULL MITIGATION
212
+ - `redis-lock`, `redlock`
213
+ - Database advisory locks
214
+ - File locks (flock)
215
+
216
+ **If ANY of these patterns exist, mark as MITIGATED, not "partial"!**
217
+
218
+ ### Intentional Design Decisions (Check Comments!)
219
+ **Before reporting, check if there are comments explaining WHY:**
220
+
221
+ 1. **Search for explanatory comments near the code:**
222
+ ```
223
+ grep -B5 -A5 "intentional|by design|deliberately|on purpose|security note" <file>
224
+ ```
225
+
226
+ 2. **Common patterns that are INTENTIONAL:**
227
+ - PKCE code reuse to prevent double-click race conditions
228
+ - Longer token expiry for better UX (with other mitigations)
229
+ - Allowing certain "unsafe" operations for admin users
230
+ - Development-only bypasses with environment checks
231
+
232
+ 3. **If comment explains the decision:**
233
+ ```json
234
+ {
235
+ "verdict": "false_positive",
236
+ "reason": "Intentional design decision documented in code",
237
+ "evidence": ["Comment at line 45: 'Intentionally allow reuse to prevent double-submit'"]
238
+ }
239
+ ```
240
+
241
+ ### Open Redirect Findings
242
+ 1. **Check for whitelist validation:**
243
+ ```
244
+ grep -r "isValidRedirect|allowedDomains|whitelist|validateUrl" <file>
245
+ ```
246
+ 2. If whitelist exists and covers the redirect parameter = MITIGATED
247
+ 3. Check if validation function is actually called before redirect
248
+
181
249
  ## Output Format
182
250
 
183
251
  ```json
@@ -158,6 +158,32 @@ CHECK FOR:
158
158
  - API versioning issues
159
159
  - Excessive data exposure in responses
160
160
 
161
+ **CORS MISCONFIGURATION** (MEDIUM):
162
+ Look for these vulnerable patterns:
163
+ ```javascript
164
+ // VULNERABLE - reflects ANY origin
165
+ res.header('Access-Control-Allow-Origin', req.headers.origin);
166
+ res.header('Access-Control-Allow-Origin', '*');
167
+
168
+ // VULNERABLE - no whitelist validation
169
+ app.use(cors({ origin: true }));
170
+ ```
171
+ Only mark as safe if there's explicit whitelist validation:
172
+ ```javascript
173
+ const allowedOrigins = ['https://app.example.com'];
174
+ if (allowedOrigins.includes(origin)) { ... }
175
+ ```
176
+
177
+ **HELMET MISCONFIGURATION** (MEDIUM):
178
+ ```javascript
179
+ app.use(helmet()); // Using defaults only - INSUFFICIENT!
180
+ ```
181
+ Check that helmet() includes:
182
+ - Custom `contentSecurityPolicy` with proper directives
183
+ - `hsts: { maxAge: 31536000, includeSubDomains: true, preload: true }`
184
+ - Proper `referrerPolicy`
185
+ Report as MEDIUM if using only defaults without customization.
186
+
161
187
  **FAIL-OPEN vs FAIL-CLOSED PATTERNS** (CRITICAL):
162
188
  - IP whitelist empty/missing = allow all (should deny all)
163
189
  - Auth middleware errors = request passes through (should block)
@@ -207,6 +233,14 @@ CHECK FOR:
207
233
  - Ansible vault passwords in plaintext
208
234
  - CI/CD pipeline secrets in yaml files (.github/workflows, .gitlab-ci.yml)
209
235
 
236
+ **SECRETS IN GIT HISTORY** (CRITICAL CHECK!):
237
+ Run these commands to check if secrets were EVER committed:
238
+ ```bash
239
+ git log --all --full-history -- "**/secrets*" "**/credentials*" "**/*.env"
240
+ git log --all -p -S "AWS_SECRET" -S "PRIVATE_KEY" --source
241
+ ```
242
+ If secrets appear in history, they are EXPOSED even if now gitignored!
243
+
210
244
  **PRIVILEGE ESCALATION RISKS**:
211
245
  - Containers/processes running as root
212
246
  - Missing securityContext in K8s (runAsNonRoot, readOnlyRootFilesystem)
@@ -220,6 +254,20 @@ CHECK FOR:
220
254
  - Missing config = silent fallback to insecure defaults
221
255
  - No validation of secret strength/format at startup
222
256
 
257
+ **DEPENDENCY SECURITY** (HIGH if missing):
258
+ Check for presence of:
259
+ - `npm audit` or `yarn audit` in CI pipeline
260
+ - Dependabot/Renovate configuration (.github/dependabot.yml, renovate.json)
261
+ - SBOM generation (cyclonedx, syft)
262
+ - Snyk/Trivy/Grype scanning
263
+ Report as HIGH if NONE of these exist - supply chain risk!
264
+
265
+ **LOGGING & MONITORING**:
266
+ - Log rotation configured? (maxFiles, maxsize in Winston/Pino)
267
+ - Log retention policy defined?
268
+ - Sensitive data redacted from logs?
269
+ Report as LOW if log rotation missing - disk exhaustion risk.
270
+
223
271
  For EACH finding, output the FULL JSON format.
224
272
 
225
273
  ---
@@ -577,63 +625,107 @@ Output as list of strings.
577
625
 
578
626
  ## PHASE 7: BUILD CONSENSUS & GENERATE OUTPUT
579
627
 
580
- 1. **Apply Mitigation Results** (from Phase 3):
581
- - Remove findings marked as `mitigated` or `false_positive`
582
- - Adjust severity for findings marked as `partial`
583
- - Add mitigation notes to confirmed findings
628
+ ### CRITICAL: Actually Remove False Positives!
584
629
 
585
- 2. Calculate confidence: (confirmations / total_validators) * 100
586
- 3. Remove findings with confidence < 50%
587
- 4. Add missed issues from Validator C
588
- 5. Sort: severity DESC, confidence DESC
630
+ The final report should ONLY contain findings that are:
631
+ 1. **Confirmed** by mitigation validation (no existing protection found)
632
+ 2. **Partial** mitigations (some protection but incomplete)
589
633
 
590
- ### Include Mitigation Summary
634
+ **DO NOT INCLUDE** findings that are:
635
+ - `mitigated` - full protection exists elsewhere
636
+ - `false_positive` - not actually a vulnerability
637
+ - Intentional design decisions with documented comments
638
+ - Race conditions protected by atomic operations (Lua, transactions)
591
639
 
592
- For each finding that passed validation, include:
593
- ```json
594
- {
595
- "id": "SEC-001",
596
- "mitigationStatus": "confirmed",
597
- "mitigationChecks": [
598
- "No input validation found between user input and SQL query",
599
- "No ORM - raw SQL used",
600
- "No middleware protection on this route"
601
- ]
602
- }
603
- ```
640
+ ### Step-by-Step Process:
604
641
 
605
- ### SAVE OUTPUT AS JSON
642
+ 1. **Start with all Phase 1 findings**
643
+
644
+ 2. **Apply Mitigation Validator results (Phase 3):**
645
+ - `mitigated` → REMOVE from findings, add to `mitigatedFindings` array
646
+ - `false_positive` → REMOVE from findings, add to `falsePositives` array
647
+ - `partial` → KEEP but downgrade severity if specified
648
+ - `confirmed` → KEEP with original severity
649
+
650
+ 3. **Apply Cross-Validator results (Phase 4):**
651
+ - Additional false positives → REMOVE from findings
652
+ - Duplicates → Merge into single finding
653
+
654
+ 4. **Calculate final counts AFTER removals:**
655
+ - Only count findings that remain in the `findings` array
656
+ - Do NOT count mitigated or false positive findings
657
+
658
+ 5. **Add missed issues from Validator C**
659
+
660
+ 6. **Sort remaining findings:** severity DESC, confidence DESC
661
+
662
+ ### Final JSON Structure
606
663
 
607
664
  ```json
608
665
  {
609
666
  "projectName": "project-name",
610
667
  "scanDate": "{{SCAN_DATE}}",
611
668
  "summary": {
612
- "total": 0,
613
- "critical": 0,
614
- "high": 0,
615
- "medium": 0,
616
- "low": 0,
617
- "info": 0
669
+ "total": 10,
670
+ "critical": 1,
671
+ "high": 3,
672
+ "medium": 4,
673
+ "low": 2,
674
+ "info": 0,
675
+ "mitigatedCount": 5,
676
+ "falsePositiveCount": 3
618
677
  },
619
678
  "findings": [
620
- "all findings with full fields including mitigationStatus"
679
+ "ONLY confirmed and partial findings - NOT mitigated or false positives!"
621
680
  ],
622
681
  "mitigatedFindings": [
623
- {"id": "SEC-005", "reason": "Protected by Zod schema validation", "originalSeverity": "high"}
682
+ {
683
+ "id": "SEC-005",
684
+ "title": "Original finding title",
685
+ "originalSeverity": "high",
686
+ "reason": "Protected by Zod schema validation at src/routes/user.ts:23",
687
+ "mitigationType": "input_validation"
688
+ }
689
+ ],
690
+ "falsePositives": [
691
+ {
692
+ "id": "BIZ-004",
693
+ "title": "TOCTOU Race Condition",
694
+ "reason": "Redis Lua script provides atomic operation - no race condition possible",
695
+ "evidence": ["Lua script at src/services/rate-limit.js:95-113"]
696
+ },
697
+ {
698
+ "id": "AUTH-003",
699
+ "title": "PKCE Code Reuse",
700
+ "reason": "Intentional design decision documented in code comment",
701
+ "evidence": ["Comment: 'Allow reuse to prevent double-click race condition'"]
702
+ }
624
703
  ],
625
704
  "positiveObservations": [
626
705
  "Good pattern 1",
627
706
  "Good pattern 2"
628
707
  ],
629
- "falsePositives": [
630
- {"id": "...", "reason": "..."}
631
- ],
708
+ "validationSummary": {
709
+ "totalInitialFindings": 18,
710
+ "mitigated": 5,
711
+ "falsePositives": 3,
712
+ "confirmed": 8,
713
+ "partial": 2,
714
+ "accuracy": "Only 56% of initial findings were actual issues"
715
+ },
632
716
  "agentsUsed": ["Security Core", "Auth & Session", "Mitigation Validator"],
633
717
  "scanDuration": 0
634
718
  }
635
719
  ```
636
720
 
721
+ ### Sanity Check Before Saving
722
+
723
+ Before saving, verify:
724
+ 1. `findings` array does NOT contain any item from `mitigatedFindings` or `falsePositives`
725
+ 2. `summary.total` equals `findings.length`
726
+ 3. Severity counts match actual findings in array
727
+ 4. No duplicate IDs across findings/mitigated/falsePositives
728
+
637
729
  Save as: .coverme/scan.json
638
730
 
639
731
  Then generate PDF report:
@@ -145,12 +145,21 @@ Before reporting ANY secret/credential finding as critical or high:
145
145
  - If file matches .gitignore patterns = NOT exposed in repo
146
146
  - Mark as "info" severity, not "critical"
147
147
 
148
- 3. **Identify environment context**:
148
+ 3. **CRITICAL: Check git HISTORY for secrets!**
149
+ Even if a file is currently gitignored, it may have been committed in the past:
150
+ ```bash
151
+ git log --all --full-history -- "**/secrets*" "**/credentials*" "**/*.env"
152
+ git log --all -p -S "AWS_SECRET" --source --all
153
+ ```
154
+ If the secret was EVER committed, it's CRITICAL - secrets in git history are exposed!
155
+
156
+ 4. **Identify environment context**:
149
157
  - `localhost`, `127.0.0.1`, `example.com` = development/example credentials
150
158
  - `.env.example`, `*.example.json` = template files, not real secrets
151
159
  - Mark these as "info" with note: "Development/example credentials"
152
160
 
153
- 4. **Severity mapping for secrets**:
161
+ 5. **Severity mapping for secrets**:
162
+ - In git history (even if now removed) = CRITICAL
154
163
  - Tracked in git + real credentials = CRITICAL
155
164
  - Tracked in git + example/dev credentials = LOW
156
165
  - NOT tracked (gitignored) + real credentials = INFO (local only)
@@ -161,10 +170,62 @@ Always include in finding:
161
170
  {
162
171
  "gitTracked": true/false,
163
172
  "gitignored": true/false,
173
+ "inGitHistory": true/false,
164
174
  "appearsToBeDev": true/false
165
175
  }
166
176
  ```
167
177
 
178
+ ## Command Injection: Config Files Are NOT Safe!
179
+
180
+ **DO NOT assume config file values are safe:**
181
+ ```javascript
182
+ // STILL VULNERABLE even though pm2Name comes from config!
183
+ const pm2Name = config.models[modelId].pm2Name;
184
+ execSync(`pm2 start ${pm2Name}`); // Command injection!
185
+ ```
186
+
187
+ Config files (models.json, config.yaml) are attack vectors if:
188
+ - File can be modified via admin panel/API
189
+ - File permissions allow non-root writes
190
+ - No schema validation on config values
191
+
192
+ **Only mark as safe if:**
193
+ - Using execFile() with argument array (not string interpolation)
194
+ - Config values validated against strict whitelist/regex
195
+ - Config is hardcoded at build time (not runtime loaded)
196
+
197
+ ## Security Misconfiguration Checks
198
+
199
+ ### Helmet Without Proper CSP
200
+ ```javascript
201
+ app.use(helmet()); // Defaults only - NOT sufficient!
202
+ ```
203
+ Report as MEDIUM if helmet() is called without:
204
+ - Custom `contentSecurityPolicy` configuration
205
+ - `hsts: { preload: true }` for HTTPS enforcement
206
+ - Proper `referrerPolicy`
207
+
208
+ ### CORS Without Whitelist
209
+ ```javascript
210
+ // VULNERABLE - reflects any origin!
211
+ res.header('Access-Control-Allow-Origin', req.headers.origin);
212
+ res.header('Access-Control-Allow-Origin', '*');
213
+ ```
214
+ Report as MEDIUM unless there's explicit domain whitelist validation.
215
+
216
+ ### Missing Dependency Security
217
+ Check for absence of:
218
+ - `npm audit` in CI/CD pipeline (.github/workflows, .gitlab-ci.yml)
219
+ - Dependabot/Renovate configuration
220
+ - SBOM generation
221
+ Report as HIGH if none exist - supply chain attacks are critical.
222
+
223
+ ### Missing Log Rotation
224
+ Check Winston/Pino/Bunyan configs for:
225
+ - `maxFiles` or `maxsize` settings
226
+ - Log retention policy
227
+ Report as LOW if missing - can lead to disk exhaustion.
228
+
168
229
  ## Files to Focus On
169
230
 
170
231
  Priority order: