milens 0.6.7 → 0.6.9

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 (45) hide show
  1. package/README.md +18 -13
  2. package/adapters/claude-code/.claude/mcp.json +2 -2
  3. package/adapters/claude-code/CLAUDE.md +1 -1
  4. package/adapters/gemini/.gemini/context.md +2 -2
  5. package/adapters/opencode/.opencode/config.json +2 -3
  6. package/adapters/zed/.zed/settings.json +1 -1
  7. package/dist/agents-md.d.ts +1 -0
  8. package/dist/agents-md.d.ts.map +1 -1
  9. package/dist/agents-md.js +50 -1
  10. package/dist/agents-md.js.map +1 -1
  11. package/dist/analyzer/engine.d.ts +2 -0
  12. package/dist/analyzer/engine.d.ts.map +1 -1
  13. package/dist/analyzer/engine.js +56 -24
  14. package/dist/analyzer/engine.js.map +1 -1
  15. package/dist/analyzer/resolver.js +5 -2
  16. package/dist/analyzer/resolver.js.map +1 -1
  17. package/dist/analyzer/review.d.ts.map +1 -1
  18. package/dist/analyzer/review.js +5 -1
  19. package/dist/analyzer/review.js.map +1 -1
  20. package/dist/analyzer/scope-resolver.d.ts.map +1 -1
  21. package/dist/analyzer/scope-resolver.js +45 -4
  22. package/dist/analyzer/scope-resolver.js.map +1 -1
  23. package/dist/cli.js +33 -15
  24. package/dist/cli.js.map +1 -1
  25. package/dist/security/rules.d.ts +2 -1
  26. package/dist/security/rules.d.ts.map +1 -1
  27. package/dist/security/rules.js +276 -61
  28. package/dist/security/rules.js.map +1 -1
  29. package/dist/server/mcp.d.ts.map +1 -1
  30. package/dist/server/mcp.js +84 -19
  31. package/dist/server/mcp.js.map +1 -1
  32. package/dist/server/test-plan.d.ts +1 -1
  33. package/dist/server/test-plan.d.ts.map +1 -1
  34. package/dist/server/test-plan.js +48 -4
  35. package/dist/server/test-plan.js.map +1 -1
  36. package/dist/store/db.d.ts.map +1 -1
  37. package/dist/store/db.js +18 -16
  38. package/dist/store/db.js.map +1 -1
  39. package/dist/types.d.ts +21 -0
  40. package/dist/types.d.ts.map +1 -1
  41. package/dist/ui/progress.d.ts +6 -18
  42. package/dist/ui/progress.d.ts.map +1 -1
  43. package/dist/ui/progress.js +40 -94
  44. package/dist/ui/progress.js.map +1 -1
  45. package/package.json +3 -2
@@ -11,8 +11,18 @@ export const OWASP_CATEGORIES = {
11
11
  'A09:2021': 'Security Logging and Monitoring Failures',
12
12
  'A10:2021': 'Server-Side Request Forgery (SSRF)',
13
13
  };
14
- const DEFAULT_EXCLUDE = '**/*.test.*,**/*.spec.*,**/node_modules/**';
15
- // ── 50 built-in security rules ──
14
+ const DEFAULT_EXCLUDE = '**/*.test.*,**/*.spec.*,**/node_modules/**,**/security/rules.ts,**/metric-milens-tool*.md,**/docs/**,**/*.html';
15
+ // ── Language-specific fileGlobs for cross-language coverage ──
16
+ const JS_TS = '**/*.{js,jsx,ts,tsx,mjs,cjs}';
17
+ const JS_TS_PY = '**/*.{js,jsx,ts,tsx,mjs,cjs,py}';
18
+ const ALL_CODE = '**/*.{js,jsx,ts,tsx,mjs,cjs,py,java,go,rs,rb,php}';
19
+ const PY_ONLY = '**/*.py';
20
+ const JAVA_ONLY = '**/*.java';
21
+ const PHP_ONLY = '**/*.php';
22
+ const DOCKER_FILES = '**/{Dockerfile,docker-compose.yml,docker-compose.yaml,.dockerignore}';
23
+ const K8S_FILES = '**/{deployment,service,pod,ingress,statefulset,daemonset,configmap,secret,role,rolebinding,clusterrole,clusterrolebinding}*.{yaml,yml}';
24
+ const TF_FILES = '**/*.tf';
25
+ // ── 190+ built-in security rules across 25 categories ──
16
26
  export const ALL_RULES = [
17
27
  // ═══════════════════════════════════════════════════════════════
18
28
  // SEC-001 – SEC-010 : Secrets (A02:2021)
@@ -26,12 +36,12 @@ export const ALL_RULES = [
26
36
  description: 'Password value appears to be hardcoded in source code. Use environment variables or a secrets manager instead.',
27
37
  patterns: [
28
38
  /(?:password|passwd|pwd)\s*[:=]\s*['"`][^'"`\n]{4,}['"`]/i,
29
- /(?:password|passwd|pwd)\s*=\s*[^'"`\s;]{4,}/i,
39
+ /(?:password|passwd|pwd)\s*=\s*(?!process\.env\.)[^'"`\s;]{4,}/i,
30
40
  ],
31
41
  excludeGlob: DEFAULT_EXCLUDE,
32
42
  fix: 'Replace hardcoded password with process.env.DB_PASSWORD or a secrets manager.',
33
43
  confidence: 0.92,
34
- enabled: true,
44
+ falsePositiveRisk: 'low', enabled: true,
35
45
  },
36
46
  {
37
47
  id: 'SEC-002',
@@ -47,7 +57,7 @@ export const ALL_RULES = [
47
57
  excludeGlob: DEFAULT_EXCLUDE,
48
58
  fix: 'Store secrets in a vault (HashiCorp Vault, AWS Secrets Manager, etc.) or environment variables.',
49
59
  confidence: 0.90,
50
- enabled: true,
60
+ falsePositiveRisk: 'low', enabled: true,
51
61
  },
52
62
  {
53
63
  id: 'SEC-003',
@@ -63,7 +73,7 @@ export const ALL_RULES = [
63
73
  excludeGlob: DEFAULT_EXCLUDE,
64
74
  fix: 'Move the API key to process.env.API_KEY and never commit credentials.',
65
75
  confidence: 0.93,
66
- enabled: true,
76
+ falsePositiveRisk: 'low', enabled: true,
67
77
  },
68
78
  {
69
79
  id: 'SEC-004',
@@ -79,7 +89,7 @@ export const ALL_RULES = [
79
89
  excludeGlob: DEFAULT_EXCLUDE,
80
90
  fix: 'Use IAM roles, instance profiles, or AWS Secrets Manager. If the key is leaked, deactivate it in the AWS console immediately.',
81
91
  confidence: 0.95,
82
- enabled: true,
92
+ falsePositiveRisk: 'low', enabled: true,
83
93
  },
84
94
  {
85
95
  id: 'SEC-005',
@@ -95,7 +105,7 @@ export const ALL_RULES = [
95
105
  excludeGlob: DEFAULT_EXCLUDE,
96
106
  fix: 'Use environment variables (STRIPE_SECRET_KEY, OPENAI_API_KEY) and never commit sk- keys.',
97
107
  confidence: 0.95,
98
- enabled: true,
108
+ falsePositiveRisk: 'low', enabled: true,
99
109
  },
100
110
  {
101
111
  id: 'SEC-006',
@@ -111,7 +121,7 @@ export const ALL_RULES = [
111
121
  excludeGlob: DEFAULT_EXCLUDE,
112
122
  fix: 'Use GITHUB_TOKEN in Actions workflows, or store PATs in repository secrets.',
113
123
  confidence: 0.95,
114
- enabled: true,
124
+ falsePositiveRisk: 'low', enabled: true,
115
125
  },
116
126
  {
117
127
  id: 'SEC-007',
@@ -127,7 +137,7 @@ export const ALL_RULES = [
127
137
  excludeGlob: DEFAULT_EXCLUDE,
128
138
  fix: 'Store private keys outside the repository; use a secrets manager or PKI infrastructure.',
129
139
  confidence: 0.95,
130
- enabled: true,
140
+ falsePositiveRisk: 'low', enabled: true,
131
141
  },
132
142
  {
133
143
  id: 'SEC-008',
@@ -143,7 +153,7 @@ export const ALL_RULES = [
143
153
  excludeGlob: DEFAULT_EXCLUDE,
144
154
  fix: 'Store private keys outside the repository; use a secrets manager or PKI infrastructure.',
145
155
  confidence: 0.95,
146
- enabled: true,
156
+ falsePositiveRisk: 'low', enabled: true,
147
157
  },
148
158
  {
149
159
  id: 'SEC-009',
@@ -159,7 +169,7 @@ export const ALL_RULES = [
159
169
  excludeGlob: DEFAULT_EXCLUDE,
160
170
  fix: 'Use environment variables or a secure token store. Rotate the exposed token.',
161
171
  confidence: 0.88,
162
- enabled: true,
172
+ falsePositiveRisk: 'low', enabled: true,
163
173
  },
164
174
  {
165
175
  id: 'SEC-010',
@@ -176,7 +186,7 @@ export const ALL_RULES = [
176
186
  excludeGlob: DEFAULT_EXCLUDE,
177
187
  fix: 'Never assign secret values to process.env in code. Use external .env files (gitignored) or a secrets manager.',
178
188
  confidence: 0.85,
179
- enabled: true,
189
+ falsePositiveRisk: 'low', enabled: true,
180
190
  },
181
191
  // ═══════════════════════════════════════════════════════════════
182
192
  // SEC-011 – SEC-019 : Injection (A03:2021)
@@ -196,7 +206,7 @@ export const ALL_RULES = [
196
206
  excludeGlob: DEFAULT_EXCLUDE,
197
207
  fix: 'Replace eval() with safer alternatives: JSON.parse() for data, or design a non-eval code path.',
198
208
  confidence: 0.92,
199
- enabled: true,
209
+ falsePositiveRisk: 'low', enabled: true,
200
210
  },
201
211
  {
202
212
  id: 'SEC-012',
@@ -213,7 +223,7 @@ export const ALL_RULES = [
213
223
  excludeGlob: DEFAULT_EXCLUDE,
214
224
  fix: 'Avoid exec(). Use getattr(), importlib, or restructure logic to not require dynamic execution.',
215
225
  confidence: 0.90,
216
- enabled: true,
226
+ falsePositiveRisk: 'low', enabled: true,
217
227
  },
218
228
  {
219
229
  id: 'SEC-013',
@@ -231,7 +241,7 @@ export const ALL_RULES = [
231
241
  excludeGlob: DEFAULT_EXCLUDE,
232
242
  fix: 'Use child_process.execFile() or child_process.spawn() with argument arrays instead of string commands.',
233
243
  confidence: 0.88,
234
- enabled: true,
244
+ falsePositiveRisk: 'low', enabled: true,
235
245
  },
236
246
  {
237
247
  id: 'SEC-014',
@@ -249,7 +259,7 @@ export const ALL_RULES = [
249
259
  excludeGlob: DEFAULT_EXCLUDE,
250
260
  fix: 'Use parameterized queries or an ORM with safe query builders (e.g., $1 placeholders, Prisma, SQLAlchemy ORM).',
251
261
  confidence: 0.91,
252
- enabled: true,
262
+ falsePositiveRisk: 'low', enabled: true,
253
263
  },
254
264
  {
255
265
  id: 'SEC-015',
@@ -266,7 +276,7 @@ export const ALL_RULES = [
266
276
  excludeGlob: DEFAULT_EXCLUDE,
267
277
  fix: 'Avoid the Function constructor. Use closures, higher-order functions, or refactor logic.',
268
278
  confidence: 0.92,
269
- enabled: true,
279
+ falsePositiveRisk: 'low', enabled: true,
270
280
  },
271
281
  {
272
282
  id: 'SEC-016',
@@ -284,7 +294,7 @@ export const ALL_RULES = [
284
294
  excludeGlob: DEFAULT_EXCLUDE,
285
295
  fix: 'Use textContent, createElement, or a sanitization library like DOMPurify before setting innerHTML.',
286
296
  confidence: 0.87,
287
- enabled: true,
297
+ falsePositiveRisk: 'low', enabled: true,
288
298
  },
289
299
  {
290
300
  id: 'SEC-017',
@@ -302,7 +312,7 @@ export const ALL_RULES = [
302
312
  excludeGlob: DEFAULT_EXCLUDE,
303
313
  fix: 'Sanitize HTML content with DOMPurify before passing to dangerouslySetInnerHTML, or use React elements instead.',
304
314
  confidence: 0.90,
305
- enabled: true,
315
+ falsePositiveRisk: 'low', enabled: true,
306
316
  },
307
317
  {
308
318
  id: 'SEC-018',
@@ -320,7 +330,7 @@ export const ALL_RULES = [
320
330
  excludeGlob: DEFAULT_EXCLUDE,
321
331
  fix: 'Use DOM manipulation APIs (createElement, appendChild) or framework-specific rendering.',
322
332
  confidence: 0.88,
323
- enabled: true,
333
+ falsePositiveRisk: 'low', enabled: true,
324
334
  },
325
335
  {
326
336
  id: 'SEC-019',
@@ -339,7 +349,7 @@ export const ALL_RULES = [
339
349
  excludeGlob: DEFAULT_EXCLUDE,
340
350
  fix: 'Pass a function reference instead of a string to setTimeout/setInterval.',
341
351
  confidence: 0.85,
342
- enabled: true,
352
+ falsePositiveRisk: 'low', enabled: true,
343
353
  },
344
354
  // ═══════════════════════════════════════════════════════════════
345
355
  // SEC-020 – SEC-023 : Unicode (A03:2021 / various)
@@ -358,7 +368,7 @@ export const ALL_RULES = [
358
368
  excludeGlob: DEFAULT_EXCLUDE,
359
369
  fix: 'Remove bidi override characters. Use explicit markup for bidirectional text if needed.',
360
370
  confidence: 0.95,
361
- enabled: true,
371
+ falsePositiveRisk: 'low', enabled: true,
362
372
  },
363
373
  {
364
374
  id: 'SEC-021',
@@ -374,7 +384,7 @@ export const ALL_RULES = [
374
384
  excludeGlob: DEFAULT_EXCLUDE,
375
385
  fix: 'Remove invisible/zero-width characters. These are often introduced accidentally or maliciously.',
376
386
  confidence: 0.93,
377
- enabled: true,
387
+ falsePositiveRisk: 'low', enabled: true,
378
388
  },
379
389
  {
380
390
  id: 'SEC-022',
@@ -392,7 +402,7 @@ export const ALL_RULES = [
392
402
  excludeGlob: DEFAULT_EXCLUDE,
393
403
  fix: 'Replace homoglyph characters with their intended ASCII/Latin equivalents. Review for malicious intent.',
394
404
  confidence: 0.80,
395
- enabled: true,
405
+ falsePositiveRisk: 'low', enabled: true,
396
406
  },
397
407
  {
398
408
  id: 'SEC-023',
@@ -409,7 +419,7 @@ export const ALL_RULES = [
409
419
  excludeGlob: DEFAULT_EXCLUDE,
410
420
  fix: 'Remove hidden Unicode characters from comments during code review.',
411
421
  confidence: 0.78,
412
- enabled: true,
422
+ falsePositiveRisk: 'low', enabled: true,
413
423
  },
414
424
  // ═══════════════════════════════════════════════════════════════
415
425
  // SEC-024 – SEC-030 : Dangerous (A03:2021 / A08:2021)
@@ -430,7 +440,7 @@ export const ALL_RULES = [
430
440
  excludeGlob: DEFAULT_EXCLUDE,
431
441
  fix: 'Use subprocess.run() with a list of arguments and shell=False (the default).',
432
442
  confidence: 0.90,
433
- enabled: true,
443
+ falsePositiveRisk: 'low', enabled: true,
434
444
  },
435
445
  {
436
446
  id: 'SEC-025',
@@ -447,7 +457,7 @@ export const ALL_RULES = [
447
457
  excludeGlob: DEFAULT_EXCLUDE,
448
458
  fix: 'Use shell=False (default) and pass command arguments as a list. Validate all user input.',
449
459
  confidence: 0.90,
450
- enabled: true,
460
+ falsePositiveRisk: 'low', enabled: true,
451
461
  },
452
462
  {
453
463
  id: 'SEC-026',
@@ -464,7 +474,7 @@ export const ALL_RULES = [
464
474
  excludeGlob: DEFAULT_EXCLUDE,
465
475
  fix: 'Use ProcessBuilder with a List<String> of arguments instead of Runtime.exec() with a single string.',
466
476
  confidence: 0.85,
467
- enabled: true,
477
+ falsePositiveRisk: 'low', enabled: true,
468
478
  },
469
479
  {
470
480
  id: 'SEC-027',
@@ -482,7 +492,7 @@ export const ALL_RULES = [
482
492
  excludeGlob: DEFAULT_EXCLUDE,
483
493
  fix: 'Set shell:false (default) and pass arguments as an array. Sanitize all user-supplied input.',
484
494
  confidence: 0.86,
485
- enabled: true,
495
+ falsePositiveRisk: 'low', enabled: true,
486
496
  },
487
497
  {
488
498
  id: 'SEC-028',
@@ -500,7 +510,7 @@ export const ALL_RULES = [
500
510
  excludeGlob: DEFAULT_EXCLUDE,
501
511
  fix: 'Use json.loads() or a safe serialization format. Never unpickle data from untrusted sources.',
502
512
  confidence: 0.92,
503
- enabled: true,
513
+ falsePositiveRisk: 'low', enabled: true,
504
514
  },
505
515
  {
506
516
  id: 'SEC-029',
@@ -517,7 +527,7 @@ export const ALL_RULES = [
517
527
  excludeGlob: DEFAULT_EXCLUDE,
518
528
  fix: 'Use json_decode() instead of unserialize(). If unserialize() is required, restrict allowed_classes.',
519
529
  confidence: 0.90,
520
- enabled: true,
530
+ falsePositiveRisk: 'low', enabled: true,
521
531
  },
522
532
  {
523
533
  id: 'SEC-030',
@@ -536,7 +546,7 @@ export const ALL_RULES = [
536
546
  excludeGlob: DEFAULT_EXCLUDE,
537
547
  fix: 'Avoid dynamic module loading. Use static imports or maintain an allowlist of safe module paths.',
538
548
  confidence: 0.84,
539
- enabled: true,
549
+ falsePositiveRisk: 'low', enabled: true,
540
550
  },
541
551
  // ═══════════════════════════════════════════════════════════════
542
552
  // SEC-031 – SEC-035 : Config (A05:2021 / A04:2021)
@@ -558,7 +568,7 @@ export const ALL_RULES = [
558
568
  excludeGlob: DEFAULT_EXCLUDE,
559
569
  fix: 'Ensure middleware matcher config explicitly lists protected routes. Do not use wildcard exclusions.',
560
570
  confidence: 0.82,
561
- enabled: true,
571
+ falsePositiveRisk: 'low', enabled: true,
562
572
  },
563
573
  {
564
574
  id: 'SEC-032',
@@ -577,7 +587,7 @@ export const ALL_RULES = [
577
587
  excludeGlob: DEFAULT_EXCLUDE,
578
588
  fix: 'Replace "*" with an explicit allowlist of trusted origins. Never pair "*" with credentials:true.',
579
589
  confidence: 0.88,
580
- enabled: true,
590
+ falsePositiveRisk: 'low', enabled: true,
581
591
  },
582
592
  {
583
593
  id: 'SEC-033',
@@ -590,13 +600,13 @@ export const ALL_RULES = [
590
600
  /secure\s*:\s*false/,
591
601
  /\bcookie\s*\(\s*[^)]*secure\s*:\s*false[^)]*\)/,
592
602
  /Set-Cookie\s*[=:].*;\s*Secure\s*=\s*false/i,
593
- /res\.cookie\s*\([^)]*\)(?!.*secure\s*:\s*true)/,
603
+ /res\.cookie\s*\((?!.*secure\s*:\s*true)/,
594
604
  ],
595
605
  fileGlob: '**/*.{js,jsx,ts,tsx,mjs,cjs,py}',
596
606
  excludeGlob: DEFAULT_EXCLUDE,
597
607
  fix: 'Set secure:true on all cookies in production. Use HTTPS everywhere.',
598
608
  confidence: 0.85,
599
- enabled: true,
609
+ falsePositiveRisk: 'low', enabled: true,
600
610
  },
601
611
  {
602
612
  id: 'SEC-034',
@@ -609,13 +619,13 @@ export const ALL_RULES = [
609
619
  /httpOnly\s*:\s*false/,
610
620
  /\bcookie\s*\(\s*[^)]*httpOnly\s*:\s*false[^)]*\)/,
611
621
  /Set-Cookie\s*[=:].*;\s*HttpOnly\s*=\s*false/i,
612
- /res\.cookie\s*\([^)]*\)(?!.*httpOnly\s*:\s*true)/,
622
+ /res\.cookie\s*\((?!.*httpOnly\s*:\s*true)/,
613
623
  ],
614
624
  fileGlob: '**/*.{js,jsx,ts,tsx,mjs,cjs,py}',
615
625
  excludeGlob: DEFAULT_EXCLUDE,
616
626
  fix: 'Set httpOnly:true on all session/authentication cookies to prevent JavaScript access.',
617
627
  confidence: 0.85,
618
- enabled: true,
628
+ falsePositiveRisk: 'low', enabled: true,
619
629
  },
620
630
  {
621
631
  id: 'SEC-035',
@@ -635,7 +645,7 @@ export const ALL_RULES = [
635
645
  excludeGlob: DEFAULT_EXCLUDE,
636
646
  fix: 'Disable debug mode in production. Use environment-specific config files.',
637
647
  confidence: 0.78,
638
- enabled: true,
648
+ falsePositiveRisk: 'low', enabled: true,
639
649
  },
640
650
  // ═══════════════════════════════════════════════════════════════
641
651
  // SEC-036 – SEC-040 : Data Leak (A09:2021)
@@ -656,7 +666,7 @@ export const ALL_RULES = [
656
666
  excludeGlob: DEFAULT_EXCLUDE,
657
667
  fix: 'Remove or redact password values from log output. Use a logging library with automatic PII redaction.',
658
668
  confidence: 0.82,
659
- enabled: true,
669
+ falsePositiveRisk: 'low', enabled: true,
660
670
  },
661
671
  {
662
672
  id: 'SEC-037',
@@ -673,7 +683,7 @@ export const ALL_RULES = [
673
683
  excludeGlob: DEFAULT_EXCLUDE,
674
684
  fix: 'Never log tokens or secrets. Mask sensitive values before logging (e.g., log only first 4 chars).',
675
685
  confidence: 0.83,
676
- enabled: true,
686
+ falsePositiveRisk: 'low', enabled: true,
677
687
  },
678
688
  {
679
689
  id: 'SEC-038',
@@ -691,7 +701,7 @@ export const ALL_RULES = [
691
701
  excludeGlob: DEFAULT_EXCLUDE,
692
702
  fix: 'Store connection strings without credentials in code; inject credentials from environment variables at runtime.',
693
703
  confidence: 0.89,
694
- enabled: true,
704
+ falsePositiveRisk: 'low', enabled: true,
695
705
  },
696
706
  {
697
707
  id: 'SEC-039',
@@ -710,7 +720,7 @@ export const ALL_RULES = [
710
720
  excludeGlob: DEFAULT_EXCLUDE,
711
721
  fix: 'Use HTTPS URLs from environment variables. Never hardcode internal IPs.',
712
722
  confidence: 0.75,
713
- enabled: true,
723
+ falsePositiveRisk: 'low', enabled: true,
714
724
  },
715
725
  {
716
726
  id: 'SEC-040',
@@ -720,15 +730,15 @@ export const ALL_RULES = [
720
730
  name: 'General console.log left in production code',
721
731
  description: 'Unconditional console.log statements may leak internal state to the browser console in production.',
722
732
  patterns: [
723
- /^\s*console\.log\s*\(/m,
724
- /^\s*console\.warn\s*\(/m,
725
- /^\s*console\.debug\s*\(/m,
733
+ /^\s*console\.log\s*\([^)]*(?:\$\{|req\.|res\.|err|error|user|token|secret)/m,
734
+ /^\s*console\.warn\s*\([^)]*(?:\$\{|req\.|res\.|err|error)/m,
735
+ /^\s*console\.debug\s*\([^)]*(?:\$\{|req\.|res\.|token|secret)/m,
726
736
  ],
727
737
  fileGlob: '**/*.{js,jsx,ts,tsx,mjs,cjs}',
728
738
  excludeGlob: DEFAULT_EXCLUDE,
729
739
  fix: 'Replace console.log with a proper logging framework that supports log levels and can be silenced in production.',
730
740
  confidence: 0.70,
731
- enabled: true,
741
+ falsePositiveRisk: 'low', enabled: true,
732
742
  },
733
743
  // ═══════════════════════════════════════════════════════════════
734
744
  // SEC-041 – SEC-044 : Crypto (A02:2021)
@@ -752,7 +762,7 @@ export const ALL_RULES = [
752
762
  excludeGlob: DEFAULT_EXCLUDE,
753
763
  fix: 'Replace MD5 with SHA-256 or SHA-3 for security-sensitive hashing. MD5 is only acceptable for non-cryptographic checksums.',
754
764
  confidence: 0.93,
755
- enabled: true,
765
+ falsePositiveRisk: 'low', enabled: true,
756
766
  },
757
767
  {
758
768
  id: 'SEC-042',
@@ -772,7 +782,7 @@ export const ALL_RULES = [
772
782
  excludeGlob: DEFAULT_EXCLUDE,
773
783
  fix: 'Use SHA-256 or SHA-3 instead of SHA-1 for any security-sensitive operation.',
774
784
  confidence: 0.90,
775
- enabled: true,
785
+ falsePositiveRisk: 'low', enabled: true,
776
786
  },
777
787
  {
778
788
  id: 'SEC-043',
@@ -789,7 +799,7 @@ export const ALL_RULES = [
789
799
  excludeGlob: DEFAULT_EXCLUDE,
790
800
  fix: 'Use crypto.randomBytes(), crypto.randomUUID(), or crypto.getRandomValues() for cryptographically secure randomness.',
791
801
  confidence: 0.85,
792
- enabled: true,
802
+ falsePositiveRisk: 'low', enabled: true,
793
803
  },
794
804
  {
795
805
  id: 'SEC-044',
@@ -808,7 +818,7 @@ export const ALL_RULES = [
808
818
  excludeGlob: DEFAULT_EXCLUDE,
809
819
  fix: 'Generate a unique, cryptographically random salt/IV per operation using crypto.randomBytes(). Never hardcode.',
810
820
  confidence: 0.86,
811
- enabled: true,
821
+ falsePositiveRisk: 'low', enabled: true,
812
822
  },
813
823
  // ═══════════════════════════════════════════════════════════════
814
824
  // SEC-045 – SEC-048 : Auth (A01:2021 / A07:2021)
@@ -828,7 +838,7 @@ export const ALL_RULES = [
828
838
  excludeGlob: DEFAULT_EXCLUDE,
829
839
  fix: 'Use a role hierarchy checker or a dedicated authorization library (e.g., CASL, Oso). Validate RBAC claims from a trusted source.',
830
840
  confidence: 0.80,
831
- enabled: true,
841
+ falsePositiveRisk: 'low', enabled: true,
832
842
  },
833
843
  {
834
844
  id: 'SEC-046',
@@ -845,7 +855,7 @@ export const ALL_RULES = [
845
855
  excludeGlob: DEFAULT_EXCLUDE,
846
856
  fix: 'Apply authentication middleware to all protected routes. Use a route grouping pattern to apply middleware consistently.',
847
857
  confidence: 0.78,
848
- enabled: true,
858
+ falsePositiveRisk: 'low', enabled: true,
849
859
  },
850
860
  {
851
861
  id: 'SEC-047',
@@ -855,15 +865,14 @@ export const ALL_RULES = [
855
865
  name: 'JWT created without expiration',
856
866
  description: 'JWTs without an exp claim are valid indefinitely, increasing the blast radius if a token is leaked.',
857
867
  patterns: [
858
- /jwt\.sign\s*\(\s*[^)]*\{(?![^}]*\bexpiresIn\b)[^}]*\}\s*\)/i,
859
- /jwt\.sign\s*\(\s*[^)]*\{(?![^}]*\bexp\b)[^}]*\}\s*\)/i,
860
- /sign\s*\(\s*payload[^)]*\)(?!.*expiresIn)/i,
868
+ /jwt\.sign\s*\(\s*(?!.*\b(?:expiresIn|expires|exp)\b)[^)]*\)/i,
869
+ /sign\s*\(\s*payload(?!.*\b(?:expiresIn|expires|exp)\b)[^)]*\)/i,
861
870
  ],
862
871
  fileGlob: '**/*.{js,jsx,ts,tsx,py}',
863
872
  excludeGlob: DEFAULT_EXCLUDE,
864
873
  fix: 'Always set an expiresIn or exp claim when signing JWTs. Use short-lived tokens with refresh token rotation.',
865
874
  confidence: 0.82,
866
- enabled: true,
875
+ falsePositiveRisk: 'low', enabled: true,
867
876
  },
868
877
  {
869
878
  id: 'SEC-048',
@@ -884,7 +893,7 @@ export const ALL_RULES = [
884
893
  excludeGlob: DEFAULT_EXCLUDE,
885
894
  fix: 'Use HttpOnly, Secure cookies for session tokens. Never pass session IDs in URL query parameters.',
886
895
  confidence: 0.86,
887
- enabled: true,
896
+ falsePositiveRisk: 'low', enabled: true,
888
897
  },
889
898
  // ═══════════════════════════════════════════════════════════════
890
899
  // SEC-049 – SEC-050 : File Access (A01:2021)
@@ -906,7 +915,7 @@ export const ALL_RULES = [
906
915
  excludeGlob: DEFAULT_EXCLUDE,
907
916
  fix: 'Validate and sanitize user input. Use path.resolve() and check that the resolved path is within the allowed directory.',
908
917
  confidence: 0.88,
909
- enabled: true,
918
+ falsePositiveRisk: 'low', enabled: true,
910
919
  },
911
920
  {
912
921
  id: 'SEC-050',
@@ -924,8 +933,214 @@ export const ALL_RULES = [
924
933
  excludeGlob: DEFAULT_EXCLUDE,
925
934
  fix: 'Sanitize file paths. Use an allowlist of permitted paths. Validate that resolved paths stay within an allowed root directory.',
926
935
  confidence: 0.90,
927
- enabled: true,
936
+ falsePositiveRisk: 'low', enabled: true,
928
937
  },
938
+ { id: 'SEC-051', category: 'secrets', owasp: 'A02:2021', severity: 'CRITICAL', name: 'Hardcoded JWT secret', description: 'JWT signing secret hardcoded in source code.', patterns: [/\b(?:jwtSecret|JWT_SECRET|jwt_secret)\s*[:=]\s*['"`][A-Za-z0-9_\-]{16,}['"`]/, /secret\s*[:=]\s*['"`][A-Za-z0-9_\-]{16,}['"`].*jwt/i], excludeGlob: DEFAULT_EXCLUDE, fix: 'Use process.env.JWT_SECRET from environment variables.', confidence: 0.95, falsePositiveRisk: 'medium', enabled: true },
939
+ { id: 'SEC-052', category: 'secrets', owasp: 'A02:2021', severity: 'CRITICAL', name: 'Hardcoded encryption key', description: 'Encryption key hardcoded in source code.', patterns: [/\b(?:encrypt(?:ion)?Key|ENCRYPT(?:ION)?_KEY|secretKey|SECRET_KEY)\s*[:=]\s*['"`][A-Za-z0-9_\-]{16,}['"`]/i], fix: 'Use process.env.ENCRYPTION_KEY or a key management service.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
940
+ { id: 'SEC-053', category: 'secrets', owasp: 'A02:2021', severity: 'CRITICAL', name: 'Hardcoded AWS Secret Access Key', description: 'AWS secret access key exposed.', patterns: [/aws_secret_access_key\s*[:=]\s*['"`][A-Za-z0-9+\/=]{40}['"`]/i, /secretAccessKey\s*[:=]\s*['"`][A-Za-z0-9+\/=]{40}['"`]/], fix: 'Use AWS IAM roles or environment variables.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
941
+ { id: 'SEC-054', category: 'secrets', owasp: 'A02:2021', severity: 'CRITICAL', name: 'Hardcoded AWS Session Token', description: 'AWS session token exposed.', patterns: [/aws_session_token\s*[:=]\s*['"`][A-Za-z0-9+\/=]{100,}['"`]/i], fix: 'Use temporary credentials via IAM roles.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
942
+ { id: 'SEC-055', category: 'secrets', owasp: 'A02:2021', severity: 'CRITICAL', name: 'GCP Service Account Key', description: 'Google Cloud service account JSON key exposed.', patterns: [/"type"\s*:\s*"service_account"/, /"private_key_id"\s*:\s*"[a-f0-9]+"/], fileGlob: '**/*.{json,js,ts}', fix: 'Use GCP IAM roles or Workload Identity.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
943
+ { id: 'SEC-056', category: 'secrets', owasp: 'A02:2021', severity: 'CRITICAL', name: 'Azure Storage Key', description: 'Azure storage account key exposed.', patterns: [/AccountKey\s*=\s*[A-Za-z0-9+\/=]{88}/, /DefaultEndpointsProtocol.*AccountKey/], fix: 'Use Azure Managed Identity.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
944
+ { id: 'SEC-057', category: 'secrets', owasp: 'A02:2021', severity: 'CRITICAL', name: 'Slack Token', description: 'Slack bot or user token exposed.', patterns: [/xox[baprs]\-[0-9A-Za-z\-]{10,}/], fix: 'Store in environment variables.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
945
+ { id: 'SEC-058', category: 'secrets', owasp: 'A02:2021', severity: 'CRITICAL', name: 'Discord Token', description: 'Discord bot token exposed.', patterns: [/[MNO][A-Za-z\d\-_]{23,25}\.[A-Za-z\d\-_]{6}\.[A-Za-z\d\-_]{27,38}/], fix: 'Store in environment variables.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
946
+ { id: 'SEC-059', category: 'secrets', owasp: 'A02:2021', severity: 'CRITICAL', name: 'Twilio Token', description: 'Twilio auth token or API key exposed.', patterns: [/SK[0-9a-fA-F]{32}/, /twilio.*token\s*[:=]\s*['"`][A-Za-z0-9]{32,}['"`]/i], fix: 'Store in environment variables.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
947
+ { id: 'SEC-060', category: 'secrets', owasp: 'A02:2021', severity: 'CRITICAL', name: 'SendGrid API Key', description: 'SendGrid API key exposed.', patterns: [/SG\.[A-Za-z0-9_\-]{20,}\.[A-Za-z0-9_\-]{20,}/, /sendgrid.*(?:api[_-]?key|key)\s*[:=]\s*['"`][A-Za-z0-9_\-]{20,}['"`]/i], fix: 'Store in environment variables.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
948
+ { id: 'SEC-061', category: 'secrets', owasp: 'A02:2021', severity: 'CRITICAL', name: 'Firebase Admin Key', description: 'Firebase service account key or config exposed.', patterns: [/"project_id"\s*:\s*"[^"]+".*"private_key"/, /firebase.*config.*apiKey/i], fileGlob: '**/*.{json,js,ts}', fix: 'Use Firebase Admin SDK with environment-based credentials.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
949
+ { id: 'SEC-062', category: 'secrets', owasp: 'A02:2021', severity: 'CRITICAL', name: 'DSA Private Key', description: 'DSA private key exposed.', patterns: [/-----BEGIN DSA PRIVATE KEY-----/], excludeGlob: DEFAULT_EXCLUDE, fix: 'Store outside the repository.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
950
+ { id: 'SEC-063', category: 'secrets', owasp: 'A02:2021', severity: 'CRITICAL', name: 'PGP Private Key', description: 'PGP/GPG private key exposed.', patterns: [/-----BEGIN PGP PRIVATE KEY BLOCK-----/], excludeGlob: DEFAULT_EXCLUDE, fix: 'Store outside the repository.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
951
+ { id: 'SEC-064', category: 'secrets', owasp: 'A02:2021', severity: 'CRITICAL', name: 'SSH Private Key', description: 'SSH private key exposed.', patterns: [/-----BEGIN (?:RSA|DSA|EC|OPENSSH) PRIVATE KEY-----/], excludeGlob: DEFAULT_EXCLUDE, fix: 'Store outside the repository.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
952
+ { id: 'SEC-065', category: 'secrets', owasp: 'A02:2021', severity: 'HIGH', name: 'Generic Refresh Token', description: 'OAuth refresh token hardcoded.', patterns: [/refresh[_-]?token\s*[:=]\s*['"`][A-Za-z0-9_\-.]{16,}['"`]/i], fix: 'Store refresh tokens in secure storage.', confidence: 0.85, falsePositiveRisk: 'low', enabled: true },
953
+ { id: 'SEC-066', category: 'secrets', owasp: 'A02:2021', severity: 'CRITICAL', name: 'Credential in Dockerfile', description: 'Credentials hardcoded in Dockerfile.', patterns: [/ENV\s+(?:PASSWORD|SECRET|TOKEN|KEY)\s*=\s*\S+/i, /ARG\s+(?:PASSWORD|SECRET|TOKEN|KEY)\s*=\s*\S+/i], fileGlob: DOCKER_FILES, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use Docker secrets or build args without default values.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
954
+ { id: 'SEC-067', category: 'secrets', owasp: 'A02:2021', severity: 'CRITICAL', name: 'Credential in Terraform', description: 'Secrets hardcoded in Terraform files.', patterns: [/(?:password|secret|token|key)\s*=\s*"[^"]{4,}"/i], fileGlob: TF_FILES, fix: 'Use Terraform variables with sensitive=true.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
955
+ { id: 'SEC-068', category: 'secrets', owasp: 'A02:2021', severity: 'CRITICAL', name: 'Credential in Kubernetes Manifest', description: 'Secrets hardcoded in K8s manifests.', patterns: [/(?:password|secret|token)\s*:\s*[A-Za-z0-9_\-]{8,}/], fileGlob: K8S_FILES, fix: 'Use Kubernetes Secrets and reference via secretKeyRef.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
956
+ { id: 'SEC-069', category: 'secrets', owasp: 'A02:2021', severity: 'HIGH', name: 'GitLab Token', description: 'GitLab PAT exposed.', patterns: [/glpat\-[A-Za-z0-9_\-]{20,}/, /gitlab.*token\s*[:=]\s*['"`][A-Za-z0-9_\-]{20,}['"`]/i], fix: 'Store in environment variables.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
957
+ { id: 'SEC-070', category: 'secrets', owasp: 'A02:2021', severity: 'HIGH', name: 'Hardcoded OAuth client secret', description: 'OAuth client secret hardcoded.', patterns: [/client[_-]?secret\s*[:=]\s*['"`][A-Za-z0-9_\-]{16,}['"`]/i, /CLIENT_SECRET\s*=\s*['"`][A-Za-z0-9_\-]{16,}['"`]/], fix: 'Use environment variables or OAuth secret management.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
958
+ // ═══════════════════════════════════════════════════════════════
959
+ // SEC-071 – SEC-087 : SQLi/NoSQLi/Template/Log Injection (A03:2021)
960
+ // ═══════════════════════════════════════════════════════════════
961
+ { id: 'SEC-071', category: 'injection', owasp: 'A03:2021', severity: 'CRITICAL', name: 'NoSQL Injection', description: 'Unsanitized user input in NoSQL query.', patterns: [/\{\s*\$where\s*:\s*req\./, /\{\s*\$regex\s*:\s*req\./, /\.find\(\s*\{\s*[^}]*req\./, /\{\s*(?:\$(?:where|gt|lt|ne|in|nin|regex|eq|expr))\s*:/], fileGlob: JS_TS, fix: 'Sanitize all user input used in NoSQL queries.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
962
+ { id: 'SEC-072', category: 'injection', owasp: 'A03:2021', severity: 'HIGH', name: 'LDAP Injection', description: 'Unsanitized input in LDAP query filters.', patterns: [/\(.*=\s*(?:req\.|request\.|params\.|query\.|body\.)/, /ldap.*search.*filter.*req\./i], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Escape LDAP filter special characters.', confidence: 0.85, falsePositiveRisk: 'low', enabled: true },
963
+ { id: 'SEC-073', category: 'injection', owasp: 'A03:2021', severity: 'HIGH', name: 'XPath Injection', description: 'Unsanitized input in XPath expressions.', patterns: [/\.evaluate\s*\(\s*[`'"].*req\./, /xpath.*compile.*req\./i], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use parameterized XPath queries.', confidence: 0.85, falsePositiveRisk: 'low', enabled: true },
964
+ { id: 'SEC-074', category: 'injection', owasp: 'A03:2021', severity: 'HIGH', name: 'CRLF Injection', description: 'CRLF injection in HTTP response headers.', patterns: [/setHeader\s*\(\s*[`'"][^`'"]*\\r\\n/, /header\s*\(\s*[`'"][^`'"]*\\r\\n/, /response\.write.*%0d%0a/i], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Strip CR/LF characters from user input before inserting into headers.', confidence: 0.85, falsePositiveRisk: 'low', enabled: true },
965
+ { id: 'SEC-075', category: 'injection', owasp: 'A03:2021', severity: 'CRITICAL', name: 'Server-Side Template Injection', description: 'User input rendered in template without sanitization.', patterns: [/render_template_string\s*\(.*req\./i, /\.render\s*\(\s*\{.*req\./, /\{\{.*req\.(?:params|query|body)/, /\$\{.*req\.(?:params|query|body)/], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Never pass raw user input to template render functions.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
966
+ { id: 'SEC-076', category: 'injection', owasp: 'A03:2021', severity: 'HIGH', name: 'EL/OGNL Injection', description: 'Expression Language injection in Java.', patterns: [/\$\{[^}]*request\.getParameter/, /#\{[^}]*request\.getParameter/], fileGlob: JAVA_ONLY, fix: 'Do not evaluate user input as EL/OGNL.', confidence: 0.85, falsePositiveRisk: 'low', enabled: true },
967
+ { id: 'SEC-077', category: 'injection', owasp: 'A03:2021', severity: 'MEDIUM', name: 'CSV Formula Injection', description: 'CSV export vulnerable to formula injection.', patterns: [/\.write\s*\(\s*[`'"].*=[`'"]/, /csv.*write.*=/i, /to_csv.*=/i], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Prefix cells starting with =, +, -, @ with a single quote.', confidence: 0.80, falsePositiveRisk: 'low', enabled: true },
968
+ { id: 'SEC-078', category: 'injection', owasp: 'A03:2021', severity: 'MEDIUM', name: 'Log Injection', description: 'User input written to logs without sanitization.', patterns: [/logger\s*\.\s*(?:info|error|warn|debug|log)\s*\(\s*[^)]*req\./, /console\.log\s*\(\s*[^)]*req\.(?:params|query|body)/], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Sanitize user input before logging. Strip newlines.', confidence: 0.75, falsePositiveRisk: 'low', enabled: true },
969
+ { id: 'SEC-079', category: 'injection', owasp: 'A03:2021', severity: 'HIGH', name: 'Mongo Operator Injection', description: 'User-controlled $ operators in MongoDB.', patterns: [/\$\s*(?:where|regex|gt|lt|ne|in|nin|expr)\s*:\s*(?:req\.|request\.|params\.|query\.|body\.)/], fileGlob: JS_TS, excludeGlob: DEFAULT_EXCLUDE, fix: 'Whitelist allowed operators and sanitize values.', confidence: 0.85, falsePositiveRisk: 'low', enabled: true },
970
+ { id: 'SEC-080', category: 'injection', owasp: 'A03:2021', severity: 'HIGH', name: 'GraphQL Injection', description: 'Raw GraphQL query built with user input.', patterns: [/graphql\s*\(\s*[`'].*req\./, /gql\s*\(\s*[`'].*req\./, /execute\s*\(\s*[`'].*req\./i], fileGlob: JS_TS, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use parameterized queries and input validation.', confidence: 0.85, falsePositiveRisk: 'low', enabled: true },
971
+ { id: 'SEC-081', category: 'injection', owasp: 'A03:2021', severity: 'MEDIUM', name: 'Host Header Injection', description: 'Request host header used unsafely.', patterns: [/req\.(?:headers|get)\(?['"]host['"]/, /request\.getHeader\s*\(\s*['"]Host['"]/], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Validate host header against a trusted domain list.', confidence: 0.75, falsePositiveRisk: 'low', enabled: true },
972
+ { id: 'SEC-082', category: 'injection', owasp: 'A03:2021', severity: 'HIGH', name: 'Email Header Injection', description: 'User input in email headers.', patterns: [/mail\s*\(\s*\{[^}]*subject\s*:\s*(?:req\.|request\.|params\.)/, /sendmail.*(?:req\.|request\.|params\.)/i, /transport\.sendMail.*req\./i], fileGlob: JS_TS_PY, fix: 'Sanitize user input before inserting into email headers.', confidence: 0.80, falsePositiveRisk: 'low', enabled: true },
973
+ { id: 'SEC-083', category: 'injection', owasp: 'A03:2021', severity: 'HIGH', name: 'HTTP Header Injection', description: 'User input inserted into HTTP response headers.', patterns: [/res\.setHeader\s*\(\s*(?:req\.|request\.|params\.)/, /response\.headers\.set\s*\(\s*[`'][^`']*\$\{/, /header\s*\(\s*[`'][^`']*\$\{.*req\./], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Strip newline characters from user input before setting headers.', confidence: 0.85, falsePositiveRisk: 'low', enabled: true },
974
+ { id: 'SEC-084', category: 'injection', owasp: 'A03:2021', severity: 'HIGH', name: 'XML Injection', description: 'User input inserted into XML without encoding.', patterns: [/\.innerHTML\s*=\s*['"`]<\?xml/, /xml\s*\+\s*(?:req\.|request\.|params\.)/, /xmldom.*parse.*req\./i], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Encode special XML characters before insertion.', confidence: 0.85, falsePositiveRisk: 'low', enabled: true },
975
+ { id: 'SEC-085', category: 'injection', owasp: 'A03:2021', severity: 'MEDIUM', name: 'Argument Injection', description: 'Command arguments built from user input.', patterns: [/\.spawn\s*\(\s*['"][^'"]+['"]\s*,\s*\[.*(?:req\.|request\.|params\.)/, /execFile\s*\(\s*['"][^'"]+['"]\s*,\s*\[.*(?:req\.|request\.|params\.)/], fileGlob: JS_TS, excludeGlob: DEFAULT_EXCLUDE, fix: 'Validate and sanitize arguments. Do not use user input in command arguments.', confidence: 0.85, falsePositiveRisk: 'low', enabled: true },
976
+ { id: 'SEC-086', category: 'injection', owasp: 'A03:2021', severity: 'HIGH', name: 'Shell Injection', description: 'Shell command with user-supplied input.', patterns: [/exec\s*\(\s*[`'].*\$\{.*req\./, /exec\s*\(\s*['"][^'"]*['"]\s*\+\s*(?:req\.|request\.|params\.)/, /`[^`]*\$[({]\s*(?:req\.|request\.|params\.)/], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use execFile instead of exec. Avoid shell interpretation.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
977
+ { id: 'SEC-087', category: 'injection', owasp: 'A03:2021', severity: 'HIGH', name: 'Dynamic Code Generation', description: 'User input used to generate executable code.', patterns: [/new Function\s*\(\s*(?:req\.|request\.|params\.)/, /compile\s*\(\s*(?:req\.|request\.|params\.)/, /vm\.runInNewContext.*req\./], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Never generate executable code from user input.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
978
+ // ═══════════════════════════════════════════════════════════════
979
+ // SEC-088 – SEC-095 : RCE (A03:2021)
980
+ // ═══════════════════════════════════════════════════════════════
981
+ { id: 'SEC-088', category: 'rce', owasp: 'A03:2021', severity: 'CRITICAL', name: 'execSync() dynamic input', description: 'execSync with user-controlled input.', patterns: [/execSync\s*\(\s*[^)]*(?:req\.|request\.|params\.|query\.|body\.)/, /execSync\s*\(\s*`[^`]*\$\{[^}]*\}[^`]*`/], fileGlob: JS_TS, fix: 'Avoid execSync with user input.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
982
+ { id: 'SEC-089', category: 'rce', owasp: 'A03:2021', severity: 'CRITICAL', name: 'PowerShell Invoke-Expression', description: 'Invoke-Expression with dynamic input.', patterns: [/Invoke-Expression\s+\$/, /iex\s+\$/], excludeGlob: DEFAULT_EXCLUDE, fix: 'Never use Invoke-Expression with variable input.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
983
+ { id: 'SEC-090', category: 'rce', owasp: 'A03:2021', severity: 'HIGH', name: 'Dynamic Class Loading', description: 'Dynamic class loading with user-controlled name.', patterns: [/Class\.forName\s*\(\s*req\./, /classLoader\.loadClass\s*\(\s*req\./i, /importlib\.import_module\s*\(\s*req\./i, /__import__\s*\(\s*req\./i], fileGlob: ALL_CODE, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use an allowlist for dynamically loaded classes.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
984
+ { id: 'SEC-091', category: 'rce', owasp: 'A03:2021', severity: 'HIGH', name: 'Reflection Execute', description: 'Reflection-based invocation with user input.', patterns: [/\.getMethod\s*\(\s*req\./, /\.invoke\s*\([^)]*req\./, /method\.call\s*\([^)]*req\./], fileGlob: ALL_CODE, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use an allowlist of permitted methods.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
985
+ { id: 'SEC-092', category: 'rce', owasp: 'A03:2021', severity: 'HIGH', name: 'Unsafe Script Engine', description: 'Script engine evaluating user input.', patterns: [/scriptEngine\.eval\s*\(\s*req\./i, /ScriptEngine.*eval.*request/i], fileGlob: JAVA_ONLY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Never pass user input to script engine eval.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
986
+ { id: 'SEC-093', category: 'rce', owasp: 'A03:2021', severity: 'HIGH', name: 'Bash Command Substitution', description: 'Shell command substitution with user input.', patterns: [/`\s*\$[({]\s*(?:req\.|request\.|params\.|query\.)/, /\$\(\s*(?:req\.|request\.|params\.)/], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use execFile instead of shell commands with substitution.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
987
+ // ═══════════════════════════════════════════════════════════════
988
+ // SEC-094 – SEC-100 : XSS (A03:2021)
989
+ // ═══════════════════════════════════════════════════════════════
990
+ { id: 'SEC-094', category: 'xss', owasp: 'A03:2021', severity: 'HIGH', name: 'outerHTML dynamic assignment', description: 'outerHTML set with dynamic content.', patterns: [/\.outerHTML\s*=\s*(?:req\.|request\.|params\.|query\.)/, /\.outerHTML\s*=\s*[`'].*\$\{/], fileGlob: JS_TS, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use textContent or DOM manipulation instead.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
991
+ { id: 'SEC-095', category: 'xss', owasp: 'A03:2021', severity: 'HIGH', name: 'insertAdjacentHTML dynamic', description: 'insertAdjacentHTML called with user input.', patterns: [/\.insertAdjacentHTML\s*\(\s*[^,]*,\s*(?:req\.|request\.|params\.)/, /\.insertAdjacentHTML\s*\(\s*[^,]*,\s*`[^`]*\$/], fileGlob: JS_TS, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use insertAdjacentElement or textContent instead.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
992
+ { id: 'SEC-096', category: 'xss', owasp: 'A03:2021', severity: 'HIGH', name: 'jQuery html() dynamic', description: 'jQuery .html() called with user input.', patterns: [/\$\([^)]*\)\s*\.\s*html\s*\(\s*(?:req\.|request\.|params\.)/, /\.html\s*\(\s*[`'].*\$\{[^}]*req\./], fileGlob: JS_TS, fix: 'Use .text() instead of .html() for user content.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
993
+ { id: 'SEC-097', category: 'xss', owasp: 'A03:2021', severity: 'HIGH', name: 'DOM XSS Sink', description: 'User input flowing into DOM XSS sink.', patterns: [/\.(?:innerHTML|outerHTML)\s*=\s*(?:location|document\.)/, /eval\s*\(\s*(?:location\.hash|location\.search)/, /document\.write\s*\(\s*(?:location\.hash|location\.search)/], fileGlob: JS_TS, excludeGlob: DEFAULT_EXCLUDE, fix: 'Sanitize all user input before DOM insertion.', confidence: 0.85, falsePositiveRisk: 'low', enabled: true },
994
+ { id: 'SEC-098', category: 'xss', owasp: 'A03:2021', severity: 'MEDIUM', name: 'SVG Script Injection', description: 'Inline SVG with script tag.', patterns: [/<svg[^>]*>.*<script/i, /<svg[^>]*onload\s*=/i], fileGlob: '**/*.{jsx,tsx}', fix: 'Sanitize SVG content before rendering.', confidence: 0.80, falsePositiveRisk: 'low', enabled: true },
995
+ { id: 'SEC-099', category: 'xss', owasp: 'A03:2021', severity: 'HIGH', name: 'Inline Event Handler Injection', description: 'Inline event handlers with user data.', patterns: [/on(?:click|load|error|mouseover|focus|blur|submit)\s*=\s*[`'].*\$\{/, /on\w+\s*=\s*\{.*req\./], fileGlob: '**/*.{jsx,tsx}', fix: 'Use addEventListener instead of inline handlers.', confidence: 0.85, falsePositiveRisk: 'low', enabled: true },
996
+ { id: 'SEC-100', category: 'xss', owasp: 'A03:2021', severity: 'MEDIUM', name: 'Unsafe Markdown Rendering', description: 'Markdown rendered without sanitization.', patterns: [/dangerouslySetInnerHTML.*marked/, /\.innerHTML\s*=.*markdown/i, /\.innerHTML\s*=.*md\s*\(/], fileGlob: JS_TS, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use DOMPurify to sanitize rendered HTML.', confidence: 0.80, falsePositiveRisk: 'low', enabled: true },
997
+ // ═══════════════════════════════════════════════════════════════
998
+ // SEC-101 – SEC-110 : Deserialization (A08:2021)
999
+ // ═══════════════════════════════════════════════════════════════
1000
+ { id: 'SEC-101', category: 'deserialization', owasp: 'A08:2021', severity: 'CRITICAL', name: 'marshal.loads() untrusted', description: 'Python marshal.loads on untrusted data.', patterns: [/marshal\.loads?\s*\(/, /marshal\.load\s*\(/], fileGlob: PY_ONLY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use json.loads instead.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1001
+ { id: 'SEC-102', category: 'deserialization', owasp: 'A08:2021', severity: 'CRITICAL', name: 'yaml.load() unsafe', description: 'PyYAML yaml.load without SafeLoader.', patterns: [/yaml\.load\s*\(/, /yaml\.load\s*\([^,)]*\)/, /yaml\.load_all\s*\(/], fileGlob: PY_ONLY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use yaml.safe_load() instead.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1002
+ { id: 'SEC-103', category: 'deserialization', owasp: 'A08:2021', severity: 'CRITICAL', name: 'Java readObject() untrusted', description: 'ObjectInputStream.readObject on untrusted data.', patterns: [/ObjectInputStream.*readObject/, /\.readObject\s*\(\s*\)/], fileGlob: JAVA_ONLY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Validate serialized objects. Use a whitelist.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1003
+ { id: 'SEC-104', category: 'deserialization', owasp: 'A08:2021', severity: 'CRITICAL', name: 'BinaryFormatter Deserialize', description: 'BinaryFormatter.Deserialize.', patterns: [/BinaryFormatter.*Deserialize/, /IFormatter.*Deserialize/], excludeGlob: DEFAULT_EXCLUDE, fix: 'Use a safer serializer or whitelist allowed types.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1004
+ { id: 'SEC-105', category: 'deserialization', owasp: 'A08:2021', severity: 'HIGH', name: 'Jackson Default Typing', description: 'Jackson ObjectMapper with default typing.', patterns: [/enableDefaultTyping\s*\(/, /ObjectMapper.*enableDefaultTyping/], fileGlob: JAVA_ONLY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Disable default typing or use a strict type whitelist.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1005
+ { id: 'SEC-106', category: 'deserialization', owasp: 'A08:2021', severity: 'HIGH', name: 'Fastjson AutoType', description: 'Fastjson with autoType enabled.', patterns: [/JSON\.parse.*autoType/, /ParserConfig.*AutoTypeSupport/, /@type\s*:/], fileGlob: JAVA_ONLY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Disable autoType in Fastjson.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1006
+ { id: 'SEC-107', category: 'deserialization', owasp: 'A08:2021', severity: 'HIGH', name: 'PHP unserialize() untrusted', description: 'unserialize on untrusted data.', patterns: [/unserialize\s*\(\s*(?:\$_(?:GET|POST|REQUEST|COOKIE)|req\.|request\.)/i, /unserialize\s*\(\s*[^)]*base64_decode/], fileGlob: PHP_ONLY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use json_decode instead. Never unserialize user input.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1007
+ { id: 'SEC-108', category: 'deserialization', owasp: 'A08:2021', severity: 'HIGH', name: 'Kryo Unsafe Deserialize', description: 'Kryo deserialization without registration.', patterns: [/new Kryo\s*\(/, /kryo\.readClassAndObject/, /kryo\.readObject/], fileGlob: JAVA_ONLY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Enable registration required.', confidence: 0.85, falsePositiveRisk: 'low', enabled: true },
1008
+ { id: 'SEC-109', category: 'deserialization', owasp: 'A08:2021', severity: 'HIGH', name: 'XMLDecoder Deserialization', description: 'XMLDecoder used for deserialization.', patterns: [/XMLDecoder/, /xmlDecoder\.readObject/], fileGlob: JAVA_ONLY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Avoid XMLDecoder. Use a safer data format.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1009
+ // ═══════════════════════════════════════════════════════════════
1010
+ // SEC-110 – SEC-115 : SSRF (A10:2021)
1011
+ // ═══════════════════════════════════════════════════════════════
1012
+ { id: 'SEC-110', category: 'ssrf', owasp: 'A10:2021', severity: 'CRITICAL', name: 'User Controlled URL Fetch', description: 'User-supplied URL in HTTP request.', patterns: [/fetch\s*\(\s*(?:req\.|request\.|params\.|query\.|body\.)/, /axios\s*\(\s*\{[^}]*url\s*:\s*(?:req\.|request\.)/, /requests\.(?:get|post|put)\s*\(\s*(?:req\.|request\.|params\.)/i, /http\.(?:get|request)\s*\(\s*(?:req\.|request\.|params\.)/, /got\s*\(\s*(?:req\.|request\.|params\.)/], fileGlob: JS_TS_PY, fix: 'Validate user-supplied URLs against a whitelist of allowed domains.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1013
+ { id: 'SEC-111', category: 'ssrf', owasp: 'A10:2021', severity: 'HIGH', name: 'SSRF via File URL', description: 'file:// URL used with user input.', patterns: [/['"`]file:\/\/['"`]\s*\+/, /url\.startsWith\s*\(\s*['"`]file:/, /['"`]file:\/\/['"`]\s*\+\s*(?:req\.|request\.)/], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Block file:// URLs from user input.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1014
+ { id: 'SEC-112', category: 'ssrf', owasp: 'A10:2021', severity: 'MEDIUM', name: 'SSRF via Gopher Protocol', description: 'gopher:// URL with user input.', patterns: [/['"`]gopher:\/\/['"`]/, /url\.includes\s*\(\s*['"`]gopher:/], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Block gopher:// URLs from user input.', confidence: 0.85, falsePositiveRisk: 'low', enabled: true },
1015
+ { id: 'SEC-113', category: 'ssrf', owasp: 'A10:2021', severity: 'HIGH', name: 'SSRF Cloud Metadata', description: 'Requests to cloud metadata endpoints.', patterns: [/169\.254\.169\.254/, /metadata\.google\.internal/, /instance-data/], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Block requests to internal IPs and metadata endpoints.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1016
+ // ═══════════════════════════════════════════════════════════════
1017
+ // SEC-114 – SEC-116 : XXE (A05:2021)
1018
+ // ═══════════════════════════════════════════════════════════════
1019
+ { id: 'SEC-114', category: 'xxe', owasp: 'A05:2021', severity: 'CRITICAL', name: 'XML External Entity', description: 'XML parser with external entities enabled.', patterns: [/DocumentBuilderFactory.*setExpandEntityReferences\s*\(\s*true/, /SAXParserFactory.*external-general-entities.*true/, /XMLInputFactory.*IS_SUPPORTING_EXTERNAL_ENTITIES.*true/], fileGlob: JAVA_ONLY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Disable external entities.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1020
+ { id: 'SEC-115', category: 'xxe', owasp: 'A05:2021', severity: 'HIGH', name: 'DTD Processing Enabled', description: 'XML DTD processing enabled.', patterns: [/DOCTYPE/, /<!ENTITY/, /xml\.etree\.ElementTree.*DOCTYPE/], fileGlob: ALL_CODE, excludeGlob: DEFAULT_EXCLUDE, fix: 'Disable DTD processing in XML parsers.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1021
+ { id: 'SEC-116', category: 'xxe', owasp: 'A05:2021', severity: 'HIGH', name: 'External Schema Loading', description: 'XML schema loaded from external URL.', patterns: [/schemaLocation\s*=\s*['"`]http/, /xsi:schemaLocation\s*=\s*['"`]http/], fileGlob: ALL_CODE, excludeGlob: DEFAULT_EXCLUDE, fix: 'Disable loading of external schemas.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1022
+ // ═══════════════════════════════════════════════════════════════
1023
+ // SEC-117 – SEC-122 : Path Traversal & File Operations (A01:2021)
1024
+ // ═══════════════════════════════════════════════════════════════
1025
+ { id: 'SEC-117', category: 'path-traversal', owasp: 'A01:2021', severity: 'HIGH', name: 'Absolute Path Injection', description: 'User input used as absolute file path.', patterns: [/\/\s*\+\s*(?:req\.|request\.|params\.|query\.|body\.)/, /path\.join\s*\(\s*['"`]\/['"`]\s*,\s*(?:req\.|request\.|params\.)/, /os\.path\.join\s*\(\s*['"`]\/['"`]\s*,\s*(?:req\.|request\.|params\.)/], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Restrict file access to an allowed directory.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1026
+ { id: 'SEC-118', category: 'path-traversal', owasp: 'A01:2021', severity: 'HIGH', name: 'Zip Slip', description: 'Zip extraction with path traversal.', patterns: [/\.extract\s*\(\s*(?:req\.|request\.)/, /unzip.*\.\./i, /extractall\s*\(/, /tar\.extract/], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Validate each entry path before extraction.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1027
+ { id: 'SEC-119', category: 'file-access', owasp: 'A01:2021', severity: 'HIGH', name: 'fs.writeFile user path', description: 'fs.writeFile with user-controlled path.', patterns: [/fs\.writeFile(?:Sync)?\s*\(\s*(?:req\.|request\.|params\.|query\.|body\.)/, /fs\.writeFile(?:Sync)?\s*\(\s*`[^`]*\$\{/], fileGlob: JS_TS, excludeGlob: DEFAULT_EXCLUDE, fix: 'Restrict write paths to an allowed directory.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1028
+ { id: 'SEC-120', category: 'file-upload', owasp: 'A01:2021', severity: 'CRITICAL', name: 'Unrestricted File Upload', description: 'File upload without type/size validation.', patterns: [/\.upload\s*\(/, /multer\s*\(\s*\{[^}]*\}\s*\)/, /req\.file\s*\./, /request\.files\s*\./], fileGlob: JS_TS_PY, fix: 'Validate file type, size, and scan for malware.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1029
+ // ═══════════════════════════════════════════════════════════════
1030
+ // SEC-121 – SEC-128 : Authentication & Authorization (A07:2021 + A01:2021)
1031
+ // ═══════════════════════════════════════════════════════════════
1032
+ { id: 'SEC-121', category: 'auth', owasp: 'A07:2021', severity: 'CRITICAL', name: 'Missing Authentication', description: 'Route handler without authentication check.', patterns: [/router\.(?:get|post|put|delete|patch)\s*\(\s*['"`]\/(?:admin|api|dashboard)['"`]\s*,\s*(?!\s*(?:auth|middleware|guard|authenticate|isAuth|requireAuth|withAuth)\b)/i, /@(?:Get|Post|Put|Delete)\s*\(\s*['"].*(?:admin|api)/], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Add authentication middleware.', confidence: 0.65, falsePositiveRisk: 'high', enabled: true },
1033
+ { id: 'SEC-122', category: 'auth', owasp: 'A07:2021', severity: 'HIGH', name: 'Default Credentials', description: 'Default username/password in code.', patterns: [/['"`]admin['"`]\s*,\s*['"`]admin['"`]/, /['"`]root['"`]\s*,\s*['"`]root['"`]/, /['"`]admin['"`]\s*,\s*['"`]password['"`]/], excludeGlob: DEFAULT_EXCLUDE, fix: 'Replace default credentials. Use environment variables.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1034
+ { id: 'SEC-123', category: 'auth', owasp: 'A07:2021', severity: 'HIGH', name: 'Session Fixation', description: 'Session ID not regenerated after login.', patterns: [/session\.regenerate/, /req\.session\.regenerate/, /login.*session/], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Regenerate session ID after authentication.', confidence: 0.85, falsePositiveRisk: 'low', enabled: true },
1035
+ { id: 'SEC-124', category: 'auth', owasp: 'A01:2021', severity: 'HIGH', name: 'IDOR Vulnerability', description: 'User ID from request used in data access.', patterns: [/\.findById\s*\(\s*req\.params\.(?!.*(?:userId|ownerId|user_id)\s*[:=])/, /\.get\s*\(\s*req\.params\.id(?!.*(?:userId|ownerId|user_id)\s*[:=])/, /WHERE.*=\s*req\.params\./i, /SELECT.*req\.params\./i], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Verify that the requesting user owns the resource.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1036
+ { id: 'SEC-125', category: 'auth', owasp: 'A01:2021', severity: 'HIGH', name: 'Mass Assignment', description: 'Request body spread directly into model.', patterns: [/\.create\s*\(\s*req\.body/, /\.update\s*\(\s*[^,]*,\s*req\.body/, /new\s+\w+\s*\(\s*req\.body/, /\w+\s*\.\s*set\s*\(\s*req\.body/], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Whitelist allowed fields.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1037
+ { id: 'SEC-126', category: 'auth', owasp: 'A01:2021', severity: 'MEDIUM', name: 'Privilege Escalation', description: 'Role set from request without validation.', patterns: [/role\s*[:=]\s*req\.(?:body|params|query)\./, /req\.body\.role/, /\.role\s*=\s*req\./], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Never set user role from client input.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1038
+ { id: 'SEC-127', category: 'auth', owasp: 'A07:2021', severity: 'HIGH', name: 'Missing Rate Limiting', description: 'Login endpoint without rate limiting.', patterns: [/router\.(?:post|get)\s*\(\s*['"`]\/(?:login|signin|auth)/, /@(?:Post|Get)\s*\(\s*['"].*(?:login|signin|auth)/], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Add rate limiting to auth endpoints.', confidence: 0.60, falsePositiveRisk: 'high', enabled: true },
1039
+ { id: 'SEC-128', category: 'auth', owasp: 'A07:2021', severity: 'MEDIUM', name: 'Predictable Session ID', description: 'Custom session ID generation.', patterns: [/Math\.random.*session/i, /Date\.now\s*\(\s*\).*session/i, /session.*=.*toString\s*\(\s*36\s*\)/], fileGlob: JS_TS, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use framework built-in session ID generation.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1040
+ // ═══════════════════════════════════════════════════════════════
1041
+ // SEC-129 – SEC-135 : JWT & Session (A07:2021)
1042
+ // ═══════════════════════════════════════════════════════════════
1043
+ { id: 'SEC-129', category: 'jwt', owasp: 'A07:2021', severity: 'CRITICAL', name: 'JWT None Algorithm', description: 'JWT verified without algorithm check.', patterns: [/algorithms\s*:\s*\[['"`]none['"`]\]/, /verify\s*\(\s*token.*none/i, /jwt\.verify\s*\((?!.*algorithms\s*:)/i], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Always specify allowed algorithms in jwt.verify().', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1044
+ { id: 'SEC-130', category: 'jwt', owasp: 'A07:2021', severity: 'HIGH', name: 'JWT weak secret', description: 'JWT signed with short/weak secret.', patterns: [/jwt\.sign\s*\([^,]*,\s*['"`][A-Za-z0-9]{1,15}['"`]\)/, /JWT_SECRET\s*=\s*['"`][A-Za-z0-9]{1,15}['"`]/], fix: 'Use a secret of at least 256 bits.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1045
+ { id: 'SEC-131', category: 'jwt', owasp: 'A07:2021', severity: 'CRITICAL', name: 'JWT Signature Not Verified', description: 'JWT used without signature verification.', patterns: [/jwt\.decode\s*\(\s*token\s*\)/, /\.decode\s*\(\s*token\s*\)/, /jose.*decode.*without.*verify/i], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Always use jwt.verify() instead of jwt.decode().', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1046
+ { id: 'SEC-132', category: 'jwt', owasp: 'A07:2021', severity: 'MEDIUM', name: 'JWT Long Expiration', description: 'JWT with excessively long expiration.', patterns: [/expiresIn\s*:\s*['"`]\d{2,}d['"`]/, /expiresIn\s*:\s*\d{8,}/, /maxAge\s*:\s*\d{8,}/], fileGlob: JS_TS_PY, fix: 'Use short-lived tokens with refresh tokens.', confidence: 0.85, falsePositiveRisk: 'low', enabled: true },
1047
+ // ═══════════════════════════════════════════════════════════════
1048
+ // SEC-133 – SEC-142 : Crypto (A02:2021)
1049
+ // ═══════════════════════════════════════════════════════════════
1050
+ { id: 'SEC-133', category: 'crypto', owasp: 'A02:2021', severity: 'HIGH', name: 'MD2 Hash', description: 'MD2 hash used (broken).', patterns: [/['"`]md2['"`]/i, /MD2\s*\./, /hashlib\.md2/], fileGlob: ALL_CODE, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use SHA-256 or better.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1051
+ { id: 'SEC-134', category: 'crypto', owasp: 'A02:2021', severity: 'HIGH', name: 'MD4 Hash', description: 'MD4 hash used (broken).', patterns: [/['"`]md4['"`]/i, /MD4\s*\./, /hashlib\.md4/], fileGlob: ALL_CODE, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use SHA-256 or better.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1052
+ { id: 'SEC-135', category: 'crypto', owasp: 'A02:2021', severity: 'HIGH', name: 'DES Encryption', description: 'DES cipher used (broken).', patterns: [/['"`]des['"`]/i, /Cipher\.getInstance\s*\(\s*['"]DES/, /DES\.MODE/], fileGlob: ALL_CODE, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use AES-256-GCM. Do not use DES.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1053
+ { id: 'SEC-136', category: 'crypto', owasp: 'A02:2021', severity: 'HIGH', name: '3DES Encryption', description: '3DES cipher used (deprecated).', patterns: [/['"`]3des['"`]/i, /['"`]DESede['"`]/, /TripleDES/, /3DES\.MODE/], fileGlob: ALL_CODE, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use AES-256-GCM.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1054
+ { id: 'SEC-137', category: 'crypto', owasp: 'A02:2021', severity: 'HIGH', name: 'RC2 Encryption', description: 'RC2 cipher used (broken).', patterns: [/['"`]rc2['"`]/i, /RC2\.MODE/], fileGlob: ALL_CODE, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use AES-256-GCM.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1055
+ { id: 'SEC-138', category: 'crypto', owasp: 'A02:2021', severity: 'HIGH', name: 'RC4 Encryption', description: 'RC4 cipher used (broken).', patterns: [/['"`]rc4['"`]/i, /ArcFour/, /RC4\.MODE/], fileGlob: ALL_CODE, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use AES-256-GCM.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1056
+ { id: 'SEC-139', category: 'crypto', owasp: 'A02:2021', severity: 'HIGH', name: 'ECB Mode Encryption', description: 'ECB cipher mode used (insecure).', patterns: [/['"`]ECB['"`]/, /Cipher\.getInstance\s*\(\s*['"]AES\/ECB/, /AES\.MODE_ECB/], fileGlob: ALL_CODE, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use AES-GCM or AES-CBC with random IV.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1057
+ { id: 'SEC-140', category: 'crypto', owasp: 'A02:2021', severity: 'MEDIUM', name: 'Weak RSA Key Length', description: 'RSA key < 2048 bits.', patterns: [/RSA\.generate\s*\(\s*1024/, /rsa\.generate\s*\(\s*1024/], fileGlob: ALL_CODE, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use RSA keys of at least 2048 bits.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1058
+ { id: 'SEC-141', category: 'crypto', owasp: 'A02:2021', severity: 'HIGH', name: 'Custom Crypto Implementation', description: 'Custom cryptography detected.', patterns: [/function\s+(?:encrypt|decrypt|hash|cipher)\s*\(/, /class\s+(?:Encrypt|Decrypt|Cipher|Hash)\s*\{/], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use well-vetted libraries. Never roll your own crypto.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1059
+ { id: 'SEC-142', category: 'crypto', owasp: 'A02:2021', severity: 'MEDIUM', name: 'Insecure UUID Generation', description: 'Non-cryptographic UUID.', patterns: [/Math\.random.*uuid/i, /\.substring.*Math\.random/], fileGlob: JS_TS, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use crypto.randomUUID() instead.', confidence: 0.85, falsePositiveRisk: 'low', enabled: true },
1060
+ // ═══════════════════════════════════════════════════════════════
1061
+ // SEC-143 – SEC-148 : CORS & Headers (A05:2021)
1062
+ // ═══════════════════════════════════════════════════════════════
1063
+ { id: 'SEC-143', category: 'cors-headers', owasp: 'A05:2021', severity: 'HIGH', name: 'CORS Wildcard Credentials', description: 'CORS with credentials and wildcard origin.', patterns: [/credentials\s*:\s*true.*origin\s*:\s*['"`]\*['"`]/, /origin\s*:\s*['"`]\*['"`].*credentials\s*:\s*true/], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Specify explicit origins when using credentials.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1064
+ { id: 'SEC-144', category: 'cors-headers', owasp: 'A05:2021', severity: 'HIGH', name: 'Missing HSTS Header', description: 'Strict-Transport-Security not configured.', patterns: [/hsts\s*:\s*false/i, /Strict-Transport-Security.*max-age=0/], fileGlob: JS_TS, excludeGlob: DEFAULT_EXCLUDE, fix: 'Enable HSTS with max-age at least 1 year.', confidence: 0.60, falsePositiveRisk: 'medium', enabled: true },
1065
+ { id: 'SEC-145', category: 'cors-headers', owasp: 'A05:2021', severity: 'MEDIUM', name: 'Missing X-Frame-Options', description: 'X-Frame-Options not set.', patterns: [/frameGuard\s*:\s*false/i, /frameguard\s*:\s*false/i], fileGlob: JS_TS, excludeGlob: DEFAULT_EXCLUDE, fix: 'Set X-Frame-Options: DENY or SAMEORIGIN.', confidence: 0.55, falsePositiveRisk: 'medium', enabled: true },
1066
+ { id: 'SEC-146', category: 'cors-headers', owasp: 'A05:2021', severity: 'MEDIUM', name: 'Missing X-Content-Type-Options', description: 'nosniff header not set.', patterns: [/noSniff\s*:\s*false/i, /nosniff\s*:\s*false/i], fileGlob: JS_TS, excludeGlob: DEFAULT_EXCLUDE, fix: 'Set X-Content-Type-Options: nosniff.', confidence: 0.55, falsePositiveRisk: 'medium', enabled: true },
1067
+ { id: 'SEC-147', category: 'cors-headers', owasp: 'A05:2021', severity: 'LOW', name: 'Missing Referrer Policy', description: 'Referrer-Policy not set.', patterns: [/referrerPolicy\s*:\s*false/i], fileGlob: JS_TS, excludeGlob: DEFAULT_EXCLUDE, fix: 'Set Referrer-Policy: strict-origin-when-cross-origin.', confidence: 0.45, falsePositiveRisk: 'high', enabled: true },
1068
+ // ═══════════════════════════════════════════════════════════════
1069
+ // SEC-148 – SEC-155 : Info Disclosure (A09:2021)
1070
+ // ═══════════════════════════════════════════════════════════════
1071
+ { id: 'SEC-148', category: 'data-leak', owasp: 'A09:2021', severity: 'HIGH', name: 'Stack Trace Exposure', description: 'Error details sent to client.', patterns: [/res\.send\s*\(\s*err\.stack/, /\.status.*\.send.*err/, /\.json\s*\(\s*\{\s*error\s*:\s*err/, /traceback\.format_exc\s*\(\s*\)/], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Log errors server-side. Send generic error messages.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1072
+ { id: 'SEC-149', category: 'data-leak', owasp: 'A09:2021', severity: 'MEDIUM', name: 'Source Map Exposure', description: 'Source maps deployed to production.', patterns: [/\.map['"`]\s*\)/, /sourceMap.*true.*production/i, /devtool.*source-map/], fileGlob: JS_TS, excludeGlob: DEFAULT_EXCLUDE, fix: 'Do not deploy source maps to production.', confidence: 0.55, falsePositiveRisk: 'medium', enabled: true },
1073
+ { id: 'SEC-150', category: 'data-leak', owasp: 'A09:2021', severity: 'HIGH', name: 'Git Directory Exposure', description: '.git directory accessible.', patterns: [/\.git\/HEAD/, /\.git\/config/], fileGlob: '**/*.{json,yaml,yml}', fix: 'Ensure .git directory is not deployed.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1074
+ { id: 'SEC-151', category: 'data-leak', owasp: 'A09:2021', severity: 'MEDIUM', name: 'Backup File Exposure', description: 'Backup files deployed.', patterns: [/\.bak['"`]/, /\.backup['"`]/, /\.old['"`]/, /\.swp['"`]/, /~\s*$/], excludeGlob: DEFAULT_EXCLUDE, fix: 'Remove backup files before deployment.', confidence: 0.50, falsePositiveRisk: 'high', enabled: true },
1075
+ // ═══════════════════════════════════════════════════════════════
1076
+ // SEC-152 – SEC-156 : Docker Security (A05:2021)
1077
+ // ═══════════════════════════════════════════════════════════════
1078
+ { id: 'SEC-152', category: 'docker', owasp: 'A05:2021', severity: 'CRITICAL', name: 'Container Running As Root', description: 'Docker container runs as root.', patterns: [/USER\s+root/, /^USER\s+0$/m], fileGlob: DOCKER_FILES, excludeGlob: DEFAULT_EXCLUDE, fix: 'Run containers as a non-root user.', confidence: 0.55, falsePositiveRisk: 'high', enabled: true },
1079
+ { id: 'SEC-153', category: 'docker', owasp: 'A05:2021', severity: 'CRITICAL', name: 'Privileged Container', description: 'Container in privileged mode.', patterns: [/privileged\s*:\s*true/, /--privileged/], fileGlob: DOCKER_FILES, excludeGlob: DEFAULT_EXCLUDE, fix: 'Remove privileged mode.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1080
+ { id: 'SEC-154', category: 'docker', owasp: 'A05:2021', severity: 'CRITICAL', name: 'Docker Socket Mounted', description: 'Docker socket mounted.', patterns: [/\/var\/run\/docker\.sock/], fileGlob: DOCKER_FILES, excludeGlob: DEFAULT_EXCLUDE, fix: 'Do not mount Docker socket.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1081
+ { id: 'SEC-155', category: 'docker', owasp: 'A05:2021', severity: 'HIGH', name: 'ADD Remote URL', description: 'ADD with remote URL.', patterns: [/^ADD\s+https?:/, /^ADD\s+http:/], fileGlob: DOCKER_FILES, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use curl with pinned checksums.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1082
+ { id: 'SEC-156', category: 'docker', owasp: 'A05:2021', severity: 'MEDIUM', name: 'Latest Tag Usage', description: ':latest tag in production.', patterns: [/:latest/, /image\s*:\s*\w+\s*$/, /FROM\s+\w+\s*$/], fileGlob: DOCKER_FILES, excludeGlob: DEFAULT_EXCLUDE, fix: 'Pin to a specific version tag.', confidence: 0.85, falsePositiveRisk: 'low', enabled: true },
1083
+ // ═══════════════════════════════════════════════════════════════
1084
+ // SEC-157 – SEC-162 : Kubernetes Security (A05:2021)
1085
+ // ═══════════════════════════════════════════════════════════════
1086
+ { id: 'SEC-157', category: 'kubernetes', owasp: 'A05:2021', severity: 'CRITICAL', name: 'Privileged Pod', description: 'K8s pod with privileged context.', patterns: [/privileged\s*:\s*true/, /securityContext\s*:\s*\n\s*privileged\s*:\s*true/], fileGlob: K8S_FILES, excludeGlob: DEFAULT_EXCLUDE, fix: 'Do not run pods in privileged mode.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1087
+ { id: 'SEC-158', category: 'kubernetes', owasp: 'A05:2021', severity: 'CRITICAL', name: 'HostPath Mount', description: 'hostPath volume mount.', patterns: [/hostPath\s*:/, /path\s*:\s*\/[^\/]/], fileGlob: K8S_FILES, excludeGlob: DEFAULT_EXCLUDE, fix: 'Avoid hostPath mounts.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1088
+ { id: 'SEC-159', category: 'kubernetes', owasp: 'A05:2021', severity: 'HIGH', name: 'Run As Root', description: 'Pod with runAsUser 0.', patterns: [/runAsUser\s*:\s*0/, /runAsNonRoot\s*:\s*false/], fileGlob: K8S_FILES, excludeGlob: DEFAULT_EXCLUDE, fix: 'Set runAsNonRoot: true.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1089
+ { id: 'SEC-160', category: 'kubernetes', owasp: 'A05:2021', severity: 'CRITICAL', name: 'Cluster Admin Binding', description: 'ClusterRoleBinding to cluster-admin.', patterns: [/cluster-admin/, /ClusterRoleBinding.*cluster-admin/], fileGlob: K8S_FILES, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use least-privilege roles.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1090
+ { id: 'SEC-161', category: 'kubernetes', owasp: 'A05:2021', severity: 'HIGH', name: 'Host Network Enabled', description: 'Pod using host network.', patterns: [/hostNetwork\s*:\s*true/, /hostPID\s*:\s*true/, /hostIPC\s*:\s*true/], fileGlob: K8S_FILES, excludeGlob: DEFAULT_EXCLUDE, fix: 'Disable hostNetwork/hostPID/hostIPC.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1091
+ // ═══════════════════════════════════════════════════════════════
1092
+ // SEC-162 – SEC-166 : Terraform/IaC (A05:2021)
1093
+ // ═══════════════════════════════════════════════════════════════
1094
+ { id: 'SEC-162', category: 'iac', owasp: 'A05:2021', severity: 'CRITICAL', name: 'Open CIDR 0.0.0.0/0', description: 'Security group open to world.', patterns: [/cidr_blocks\s*=\s*\[['"]0\.0\.0\.0\/0['"]\]/, /source_ranges\s*=\s*\[['"]0\.0\.0\.0\/0['"]\]/], fileGlob: TF_FILES, excludeGlob: DEFAULT_EXCLUDE, fix: 'Restrict CIDR blocks.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1095
+ { id: 'SEC-163', category: 'iac', owasp: 'A05:2021', severity: 'HIGH', name: 'Unencrypted Storage', description: 'Storage without encryption.', patterns: [/encrypted\s*=\s*false/, /encryption\s*{\s*enabled\s*=\s*false/], fileGlob: TF_FILES, excludeGlob: DEFAULT_EXCLUDE, fix: 'Enable encryption at rest.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1096
+ { id: 'SEC-164', category: 'iac', owasp: 'A05:2021', severity: 'HIGH', name: 'Public Database Instance', description: 'Database publicly accessible.', patterns: [/publicly_accessible\s*=\s*true/], fileGlob: TF_FILES, excludeGlob: DEFAULT_EXCLUDE, fix: 'Set publicly_accessible to false.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1097
+ // ═══════════════════════════════════════════════════════════════
1098
+ // SEC-165 – SEC-172 : Cloud Security (A05:2021)
1099
+ // ═══════════════════════════════════════════════════════════════
1100
+ { id: 'SEC-165', category: 'cloud', owasp: 'A05:2021', severity: 'CRITICAL', name: 'Public S3 Bucket', description: 'S3 bucket with public access.', patterns: [/acl\s*=\s*['"]public/, /block_public_acls\s*=\s*false/, /block_public_policy\s*=\s*false/], fileGlob: TF_FILES, excludeGlob: DEFAULT_EXCLUDE, fix: 'Block all public access to S3 buckets.', confidence: 0.50, falsePositiveRisk: 'high', enabled: true },
1101
+ { id: 'SEC-166', category: 'cloud', owasp: 'A05:2021', severity: 'CRITICAL', name: 'Open Security Group', description: 'Security group wide-open ports.', patterns: [/from_port\s*=\s*0.*to_port\s*=\s*0/, /protocol\s*=\s*['"]\-1['"]/], fileGlob: TF_FILES, excludeGlob: DEFAULT_EXCLUDE, fix: 'Restrict security group rules.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1102
+ // ═══════════════════════════════════════════════════════════════
1103
+ // SEC-167 – SEC-172 : API Security (A01/A04:2021)
1104
+ // ═══════════════════════════════════════════════════════════════
1105
+ { id: 'SEC-167', category: 'api-security', owasp: 'A01:2021', severity: 'HIGH', name: 'Missing API Authentication', description: 'API endpoint without auth.', patterns: [/router\.\w+\s*\(\s*['"`]\/api\/v?\d*\/\w+['"`]\s*,/, /@\w+\s*\(\s*['"`]\/api\/v?\d*\/\w+['"`]\)/], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Require authentication for all API endpoints.', confidence: 0.65, falsePositiveRisk: 'high', enabled: true },
1106
+ { id: 'SEC-168', category: 'api-security', owasp: 'A04:2021', severity: 'MEDIUM', name: 'Missing Request Size Limit', description: 'No body size limit on API.', patterns: [/bodyParser\.json\s*\(\s*\)/, /express\.json\s*\(\s*\)/], fileGlob: JS_TS, excludeGlob: DEFAULT_EXCLUDE, fix: 'Set a reasonable request body size limit.', confidence: 0.80, falsePositiveRisk: 'low', enabled: true },
1107
+ { id: 'SEC-169', category: 'api-security', owasp: 'A04:2021', severity: 'MEDIUM', name: 'GraphQL Introspection Enabled', description: 'Introspection left enabled.', patterns: [/introspection\s*:\s*true/], fileGlob: JS_TS, excludeGlob: DEFAULT_EXCLUDE, fix: 'Disable GraphQL introspection in production.', confidence: 0.80, falsePositiveRisk: 'low', enabled: true },
1108
+ { id: 'SEC-170', category: 'api-security', owasp: 'A04:2021', severity: 'MEDIUM', name: 'GraphQL Excessive Depth', description: 'No depth limit on queries.', patterns: [/ApolloServer.*no.*depth/, /graphql.*no.*maxDepth/i, /validationRules.*\[\s*\]/], fileGlob: JS_TS, excludeGlob: DEFAULT_EXCLUDE, fix: 'Set a maximum query depth.', confidence: 0.80, falsePositiveRisk: 'low', enabled: true },
1109
+ // ═══════════════════════════════════════════════════════════════
1110
+ // SEC-171 – SEC-175 : Business Logic (A04:2021)
1111
+ // ═══════════════════════════════════════════════════════════════
1112
+ { id: 'SEC-171', category: 'business-logic', owasp: 'A04:2021', severity: 'MEDIUM', name: 'Integer Overflow', description: 'Integer arithmetic potentially vulnerable to overflow.', patterns: [/amount\s*\*\s*\d+\s*\+/, /\b(?:price|amount|total|cost)\s*\*\s*(?:req\.|request\.|params\.|query\.|body\.)/], fileGlob: JS_TS, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use BigInt for financial calculations.', confidence: 0.40, falsePositiveRisk: 'high', enabled: true },
1113
+ { id: 'SEC-172', category: 'business-logic', owasp: 'A04:2021', severity: 'MEDIUM', name: 'Negative Value Processing', description: 'No validation for negative values.', patterns: [/price\s*=\s*req\.body\./, /amount\s*=\s*req\.body\./, /quantity\s*=\s*req\.body\./], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Validate that price/amount values are positive.', confidence: 0.80, falsePositiveRisk: 'low', enabled: true },
1114
+ { id: 'SEC-173', category: 'business-logic', owasp: 'A04:2021', severity: 'MEDIUM', name: 'TOCTOU Vulnerability', description: 'Check-then-use pattern.', patterns: [/if\s*\(\s*existsSync/, /if\s*\(\s*fs\.existsSync/, /if\s*\(\s*os\.path\.exists/], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Use atomic operations.', confidence: 0.75, falsePositiveRisk: 'low', enabled: true },
1115
+ // ═══════════════════════════════════════════════════════════════
1116
+ // SEC-174 – SEC-180 : Misc (various OWASP)
1117
+ // ═══════════════════════════════════════════════════════════════
1118
+ { id: 'SEC-174', category: 'misc', owasp: 'A01:2021', severity: 'HIGH', name: 'Open Redirect', description: 'User-controlled URL in redirect.', patterns: [/res\.redirect\s*\(\s*(?:req\.|request\.|params\.|query\.|body\.)/, /redirect\s*\(\s*(?:req\.|request\.|params\.|query\.|body\.)/, /location\.(?:replace|href|assign)\s*=\s*(?:req\.|request\.|params\.)/], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Validate redirect URLs against a whitelist.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1119
+ { id: 'SEC-175', category: 'misc', owasp: 'A01:2021', severity: 'HIGH', name: 'Missing CSRF Protection', description: 'State-changing endpoint without CSRF.', patterns: [/csrf\s*:\s*false/i, /\.post\s*\(\s*['"`]\/[^'"]*['"`]\s*,(?!.*csrf)/], fileGlob: JS_TS, excludeGlob: DEFAULT_EXCLUDE, fix: 'Enable CSRF protection.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1120
+ { id: 'SEC-176', category: 'misc', owasp: 'A03:2021', severity: 'MEDIUM', name: 'Unsafe Regex (ReDoS)', description: 'Regex with catastrophic backtracking.', patterns: [/\(\s*\w\+\s*\)\s*\+\s*\)/, /\(\s*\.\*\s*\)\s*\+/, /\(\s*(?:\w\+\s*\|)+\w\+\s*\)\s*\*/], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Rewrite regex to avoid nested quantifiers.', confidence: 0.75, falsePositiveRisk: 'low', enabled: true },
1121
+ { id: 'SEC-177', category: 'misc', owasp: 'A04:2021', severity: 'HIGH', name: 'Prototype Pollution', description: 'Object merge with user input.', patterns: [/Object\.assign\s*\(\s*[^,]*,\s*req\./, /\.\.\.\s*req\.body/, /\{\s*\.\.\.\s*req\.body/, /\.extend\s*\(\s*[^,]*,\s*req\./, /_.merge\s*\(\s*[^,]*,\s*req\./, /lodash.*merge.*req\./i], fileGlob: JS_TS, excludeGlob: DEFAULT_EXCLUDE, fix: 'Validate user input before merging.', confidence: 0.90, falsePositiveRisk: 'low', enabled: true },
1122
+ { id: 'SEC-178', category: 'misc', owasp: 'A01:2021', severity: 'MEDIUM', name: 'Reverse Tabnabbing', description: 'target="_blank" without noopener.', patterns: [/target\s*=\s*['"`]_blank['"`](?!.*noopener)/, /window\.open\s*\(\s*(?!.*noopener)/], fileGlob: '**/*.{jsx,tsx}', fix: 'Add rel="noopener noreferrer".', confidence: 0.80, falsePositiveRisk: 'low', enabled: true },
1123
+ { id: 'SEC-179', category: 'misc', owasp: 'A04:2021', severity: 'MEDIUM', name: 'Resource Exhaustion', description: 'Unbounded resource allocation.', patterns: [/\.split\s*\(\s*(?:req\.|request\.|params\.)/, /Array\s*\(\s*parseInt\s*\(\s*(?:req\.|request\.|params\.)/, /\.repeat\s*\(\s*(?:req\.|request\.|params\.)/], fileGlob: JS_TS_PY, excludeGlob: DEFAULT_EXCLUDE, fix: 'Apply limits to user-supplied values.', confidence: 0.80, falsePositiveRisk: 'low', enabled: true },
1124
+ // ═══════════════════════════════════════════════════════════════
1125
+ // SEC-180 – SEC-185 : Dependency Security (A06:2021)
1126
+ // ═══════════════════════════════════════════════════════════════
1127
+ { id: 'SEC-180', category: 'dependency', owasp: 'A06:2021', severity: 'HIGH', name: 'Unpinned Dependency', description: 'Version not pinned.', patterns: [/"\*"\s*:/, /"\^/, /"~/, /">=/], fileGlob: '**/package.json', excludeGlob: DEFAULT_EXCLUDE, fix: 'Pin dependency versions.', confidence: 0.85, falsePositiveRisk: 'low', enabled: true },
1128
+ { id: 'SEC-181', category: 'dependency', owasp: 'A06:2021', severity: 'HIGH', name: 'Untrusted Package Source', description: 'Non-standard registry.', patterns: [/registry\s*=\s*['"`]https?:\/\/(?!registry\.npmjs|registry\.yarnpkg)/], fileGlob: '**/{.npmrc,.yarnrc}', fix: 'Only use trusted registries.', confidence: 0.85, falsePositiveRisk: 'low', enabled: true },
1129
+ { id: 'SEC-182', category: 'dependency', owasp: 'A06:2021', severity: 'MEDIUM', name: 'Unsafe Postinstall', description: 'postinstall scripts enabled.', patterns: [/ignore-scripts\s*=\s*false/, /unsafe-perm\s*=\s*true/], fileGlob: '**/{.npmrc,.yarnrc}', fix: 'Set ignore-scripts=true.', confidence: 0.85, falsePositiveRisk: 'low', enabled: true },
1130
+ { id: 'SEC-183', category: 'dependency', owasp: 'A06:2021', severity: 'HIGH', name: 'Dependency Confusion', description: 'Internal package name collision.', patterns: [/"@(?:company|internal|private)\//], fileGlob: '**/package.json', excludeGlob: DEFAULT_EXCLUDE, fix: 'Use scoped packages with registry mappings.', confidence: 0.80, falsePositiveRisk: 'low', enabled: true },
1131
+ // ═══════════════════════════════════════════════════════════════
1132
+ // SEC-184 – SEC-188 : Session & Cookie (A07:2021)
1133
+ // ═══════════════════════════════════════════════════════════════
1134
+ { id: 'SEC-184', category: 'config', owasp: 'A07:2021', severity: 'HIGH', name: 'Session Cookie Missing SameSite', description: 'Cookie without SameSite.', patterns: [/cookie\s*\(\s*['"`][^'"]*['"`]\s*,\s*(?!.*sameSite)/i, /session.*cookie.*(?!.*sameSite)/i], excludeGlob: DEFAULT_EXCLUDE, fileGlob: JS_TS_PY, fix: 'Set SameSite=Lax on session cookies.', confidence: 0.85, falsePositiveRisk: 'low', enabled: true },
1135
+ { id: 'SEC-185', category: 'config', owasp: 'A07:2021', severity: 'MEDIUM', name: 'Session Stored Client Side', description: 'Session data in client storage.', patterns: [/localStorage\.setItem/, /sessionStorage\.setItem/, /document\.cookie\s*=\s*[^;]*token/i], fileGlob: JS_TS, excludeGlob: DEFAULT_EXCLUDE, fix: 'Store tokens in httpOnly cookies.', confidence: 0.85, falsePositiveRisk: 'low', enabled: true },
1136
+ // ═══════════════════════════════════════════════════════════════
1137
+ // SEC-186 – SEC-190 : Additional Secrets
1138
+ // ═══════════════════════════════════════════════════════════════
1139
+ { id: 'SEC-186', category: 'secrets', owasp: 'A02:2021', severity: 'HIGH', name: 'Hardcoded SMTP Credential', description: 'SMTP credentials hardcoded.', patterns: [/smtp.*(?:user|pass)\s*[:=]\s*['"`][^'"`]{3,}['"`]/i, /nodemailer.*auth\s*:\s*\{[^}]*pass\s*:\s*['"`]/i], fix: 'Use environment variables.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1140
+ { id: 'SEC-187', category: 'secrets', owasp: 'A02:2021', severity: 'HIGH', name: 'Hardcoded LDAP Credential', description: 'LDAP bind password.', patterns: [/ldap.*(?:password|bindpw)\s*[:=]\s*['"`][^'"`]{3,}['"`]/i], fix: 'Use environment variables.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1141
+ { id: 'SEC-188', category: 'secrets', owasp: 'A02:2021', severity: 'HIGH', name: 'Hardcoded FTP Credential', description: 'FTP password hardcoded.', patterns: [/ftp.*(?:password|pass)\s*[:=]\s*['"`][^'"`]{3,}['"`]/i], fix: 'Use environment variables.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1142
+ { id: 'SEC-189', category: 'secrets', owasp: 'A02:2021', severity: 'CRITICAL', name: 'Anthropic API Key', description: 'Anthropic API key exposed.', patterns: [/sk-ant-[a-zA-Z0-9\-_]{30,}/, /anthropic.*(?:api[_-]?key|key)\s*[:=]\s*['"`]sk-ant/i], fix: 'Store in environment variables.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
1143
+ { id: 'SEC-190', category: 'secrets', owasp: 'A02:2021', severity: 'HIGH', name: 'Hardcoded Database Password', description: 'DB password in connection string.', patterns: [/mysql:\/\/[^:]+:[^@]+@/, /postgres:\/\/[^:]+:[^@]+@/, /mongodb:\/\/[^:]+:[^@]+@/, /DATABASE_URL\s*=\s*[`'"][^`'"]*:[^`'"]*@/i], excludeGlob: DEFAULT_EXCLUDE, fix: 'Use environment variables for DB credentials.', confidence: 0.95, falsePositiveRisk: 'low', enabled: true },
929
1144
  ];
930
1145
  // ── Utility functions ──
931
1146
  export function loadRules() {