@clear-capabilities/agentic-security-scanner 0.76.1 → 0.78.0

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 (108) hide show
  1. package/bin/.agentic-security/findings.json +320 -9
  2. package/bin/.agentic-security/last-scan.json +320 -9
  3. package/bin/.agentic-security/last-scan.json.sig +1 -1
  4. package/bin/.agentic-security/scan-history.json +17 -377
  5. package/bin/.agentic-security/streak.json +11 -16
  6. package/bin/agentic-security.js +33 -2
  7. package/dist/178.index.js +1 -1
  8. package/dist/384.index.js +1 -1
  9. package/dist/637.index.js +1 -1
  10. package/dist/718.index.js +106 -0
  11. package/dist/824.index.js +126 -0
  12. package/dist/838.index.js +1 -1
  13. package/dist/agentic-security.mjs +32 -32
  14. package/dist/agentic-security.mjs.sha256 +1 -1
  15. package/package.json +7 -7
  16. package/src/.agentic-security/findings.json +5731 -3933
  17. package/src/.agentic-security/last-scan.json +5731 -3933
  18. package/src/.agentic-security/last-scan.json.sig +1 -1
  19. package/src/.agentic-security/scan-history.json +2533 -887
  20. package/src/.agentic-security/streak.json +11 -16
  21. package/src/dataflow/.agentic-security/findings.json +52 -24
  22. package/src/dataflow/.agentic-security/last-scan.json +52 -24
  23. package/src/dataflow/.agentic-security/last-scan.json.sig +1 -1
  24. package/src/dataflow/.agentic-security/scan-history.json +101 -134
  25. package/src/dataflow/.agentic-security/streak.json +8 -10
  26. package/src/dataflow/async-sequencing.js +16 -7
  27. package/src/dataflow/builtin-summaries.js +131 -0
  28. package/src/dataflow/catalog.js +107 -0
  29. package/src/dataflow/cross-repo.js +75 -1
  30. package/src/dataflow/engine.js +129 -0
  31. package/src/dataflow/implicit-flow.js +24 -6
  32. package/src/dataflow/stub-aware-filter.js +69 -11
  33. package/src/dataflow/summaries.js +28 -3
  34. package/src/engine-parallel.js +70 -0
  35. package/src/engine.js +165 -15
  36. package/src/ir/.agentic-security/findings.json +757 -16
  37. package/src/ir/.agentic-security/last-scan.json +757 -16
  38. package/src/ir/.agentic-security/last-scan.json.sig +1 -1
  39. package/src/ir/.agentic-security/scan-history.json +545 -138
  40. package/src/ir/.agentic-security/streak.json +11 -13
  41. package/src/ir/index.js +22 -1
  42. package/src/ir/parser-go.js +403 -0
  43. package/src/ir/parser-js.js +2 -0
  44. package/src/ir/parser-php.js +330 -0
  45. package/src/ir/parser-py.helper.py +137 -11
  46. package/src/ir/parser-rb.js +309 -0
  47. package/src/posture/.agentic-security/findings.json +407 -84
  48. package/src/posture/.agentic-security/last-scan.json +407 -84
  49. package/src/posture/.agentic-security/last-scan.json.sig +1 -1
  50. package/src/posture/.agentic-security/scan-history.json +16 -4923
  51. package/src/posture/.agentic-security/streak.json +10 -14
  52. package/src/posture/calibration.js +14 -0
  53. package/src/posture/triage.js +13 -0
  54. package/src/report/.agentic-security/findings.json +6 -5
  55. package/src/report/.agentic-security/last-scan.json +6 -5
  56. package/src/report/.agentic-security/last-scan.json.sig +1 -1
  57. package/src/report/.agentic-security/scan-history.json +3 -300
  58. package/src/report/.agentic-security/streak.json +7 -8
  59. package/src/report/index.js +23 -2
  60. package/src/sast/.agentic-security/findings.json +195 -56
  61. package/src/sast/.agentic-security/last-scan.json +195 -56
  62. package/src/sast/.agentic-security/last-scan.json.sig +1 -1
  63. package/src/sast/.agentic-security/scan-history.json +14 -394
  64. package/src/sast/.agentic-security/streak.json +10 -13
  65. package/src/sast/cache-poisoning.js +77 -0
  66. package/src/sast/comparison-safety.js +73 -0
  67. package/src/sast/db-taint.js +54 -0
  68. package/src/sast/graphql.js +127 -0
  69. package/src/sast/llm-stored-prompt.js +57 -0
  70. package/src/sast/mutation-xss.js +43 -0
  71. package/src/sast/nosql-injection.js +5 -0
  72. package/src/sast/null-byte-injection.js +76 -0
  73. package/src/sast/redos-nfa.js +338 -0
  74. package/src/sast/sensitive-data-logging.js +73 -0
  75. package/src/sast/weak-password-hash.js +77 -0
  76. package/src/sast/weak-randomness.js +100 -0
  77. package/src/sca/.agentic-security/findings.json +502 -11
  78. package/src/sca/.agentic-security/last-scan.json +502 -11
  79. package/src/sca/.agentic-security/last-scan.json.sig +1 -1
  80. package/src/sca/.agentic-security/scan-history.json +19 -1
  81. package/src/sca/.agentic-security/streak.json +6 -6
  82. package/src/sca/llm-function-extract.js +107 -0
  83. package/src/sca/vendor-detect.js +91 -0
  84. package/dist/218.index.js +0 -793
  85. package/dist/601.index.js +0 -1038
  86. package/dist/634.index.js +0 -1892
  87. package/src/integrations/.agentic-security/findings.json +0 -1504
  88. package/src/integrations/.agentic-security/last-scan.json +0 -1504
  89. package/src/integrations/.agentic-security/scan-history.json +0 -40
  90. package/src/integrations/.agentic-security/streak.json +0 -21
  91. package/src/llm-validator/.agentic-security/findings.json +0 -1891
  92. package/src/llm-validator/.agentic-security/last-scan.json +0 -1891
  93. package/src/llm-validator/.agentic-security/last-scan.json.sig +0 -1
  94. package/src/llm-validator/.agentic-security/scan-history.json +0 -168
  95. package/src/llm-validator/.agentic-security/streak.json +0 -20
  96. package/src/lsp/.agentic-security/findings.json +0 -28
  97. package/src/lsp/.agentic-security/last-scan.json +0 -28
  98. package/src/lsp/.agentic-security/scan-history.json +0 -79
  99. package/src/lsp/.agentic-security/streak.json +0 -22
  100. package/src/mcp/.agentic-security/findings.json +0 -8403
  101. package/src/mcp/.agentic-security/last-scan.json +0 -8403
  102. package/src/mcp/.agentic-security/last-scan.json.sig +0 -1
  103. package/src/mcp/.agentic-security/scan-history.json +0 -1182
  104. package/src/mcp/.agentic-security/streak.json +0 -22
  105. package/src/sast/bench-shape/.agentic-security/findings.json +0 -28
  106. package/src/sast/bench-shape/.agentic-security/last-scan.json +0 -28
  107. package/src/sast/bench-shape/.agentic-security/scan-history.json +0 -24
  108. package/src/sast/bench-shape/.agentic-security/streak.json +0 -22
@@ -1,386 +1,6 @@
1
1
  [
2
2
  {
3
- "timestamp": "2026-05-19T14:14:43.272Z",
4
- "label": "scan",
5
- "total": 10,
6
- "critical": 0,
7
- "high": 9,
8
- "medium": 1,
9
- "low": 0,
10
- "kev": 0,
11
- "ids": [
12
- "authz:authz.js:33:AuthZ__jwt_verify_called_without_algorithms_allow_list",
13
- "client-side:CLIENT_EVAL:client-side.js:135",
14
- "client-side:CLIENT_EVAL:client-side.js:139",
15
- "client-side:CLIENT_EVAL:client-side.js:140",
16
- "llm-owasp:llm-owasp.js:180:llm01-dynamic-system:concat",
17
- "llm-owasp:llm-owasp.js:181:llm01-dynamic-system:fstring",
18
- "llm-owasp:llm-owasp.js:182:llm01-dynamic-system:template",
19
- "llm-owasp:llm-owasp.js:183:llm10-no-token-budget",
20
- "prompt-tpl:llm-owasp.js:125:Prompt_Template__user_input_interpolated_into_prompt_string_",
21
- "zip-slip:zip-slip.js:192:node-entry"
22
- ]
23
- },
24
- {
25
- "timestamp": "2026-05-19T14:15:45.304Z",
26
- "label": "scan",
27
- "total": 10,
28
- "critical": 0,
29
- "high": 9,
30
- "medium": 1,
31
- "low": 0,
32
- "kev": 0,
33
- "ids": [
34
- "authz:authz.js:33:AuthZ__jwt_verify_called_without_algorithms_allow_list",
35
- "client-side:CLIENT_EVAL:client-side.js:135",
36
- "client-side:CLIENT_EVAL:client-side.js:139",
37
- "client-side:CLIENT_EVAL:client-side.js:140",
38
- "llm-owasp:llm-owasp.js:180:llm01-dynamic-system:concat",
39
- "llm-owasp:llm-owasp.js:181:llm01-dynamic-system:fstring",
40
- "llm-owasp:llm-owasp.js:182:llm01-dynamic-system:template",
41
- "llm-owasp:llm-owasp.js:183:llm10-no-token-budget",
42
- "prompt-tpl:llm-owasp.js:125:Prompt_Template__user_input_interpolated_into_prompt_string_",
43
- "zip-slip:zip-slip.js:192:node-entry"
44
- ]
45
- },
46
- {
47
- "timestamp": "2026-05-19T14:16:41.598Z",
48
- "label": "scan",
49
- "total": 10,
50
- "critical": 0,
51
- "high": 9,
52
- "medium": 1,
53
- "low": 0,
54
- "kev": 0,
55
- "ids": [
56
- "authz:authz.js:33:AuthZ__jwt_verify_called_without_algorithms_allow_list",
57
- "client-side:CLIENT_EVAL:client-side.js:135",
58
- "client-side:CLIENT_EVAL:client-side.js:139",
59
- "client-side:CLIENT_EVAL:client-side.js:140",
60
- "llm-owasp:llm-owasp.js:180:llm01-dynamic-system:concat",
61
- "llm-owasp:llm-owasp.js:181:llm01-dynamic-system:fstring",
62
- "llm-owasp:llm-owasp.js:182:llm01-dynamic-system:template",
63
- "llm-owasp:llm-owasp.js:183:llm10-no-token-budget",
64
- "prompt-tpl:llm-owasp.js:125:Prompt_Template__user_input_interpolated_into_prompt_string_",
65
- "zip-slip:zip-slip.js:192:node-entry"
66
- ]
67
- },
68
- {
69
- "timestamp": "2026-05-19T14:17:46.030Z",
70
- "label": "scan",
71
- "total": 10,
72
- "critical": 0,
73
- "high": 9,
74
- "medium": 1,
75
- "low": 0,
76
- "kev": 0,
77
- "ids": [
78
- "authz:authz.js:33:AuthZ__jwt_verify_called_without_algorithms_allow_list",
79
- "client-side:CLIENT_EVAL:client-side.js:135",
80
- "client-side:CLIENT_EVAL:client-side.js:139",
81
- "client-side:CLIENT_EVAL:client-side.js:140",
82
- "llm-owasp:llm-owasp.js:180:llm01-dynamic-system:concat",
83
- "llm-owasp:llm-owasp.js:181:llm01-dynamic-system:fstring",
84
- "llm-owasp:llm-owasp.js:182:llm01-dynamic-system:template",
85
- "llm-owasp:llm-owasp.js:183:llm10-no-token-budget",
86
- "prompt-tpl:llm-owasp.js:125:Prompt_Template__user_input_interpolated_into_prompt_string_",
87
- "zip-slip:zip-slip.js:192:node-entry"
88
- ]
89
- },
90
- {
91
- "timestamp": "2026-05-19T14:18:37.970Z",
92
- "label": "scan",
93
- "total": 10,
94
- "critical": 0,
95
- "high": 9,
96
- "medium": 1,
97
- "low": 0,
98
- "kev": 0,
99
- "ids": [
100
- "authz:authz.js:33:AuthZ__jwt_verify_called_without_algorithms_allow_list",
101
- "client-side:CLIENT_EVAL:client-side.js:135",
102
- "client-side:CLIENT_EVAL:client-side.js:139",
103
- "client-side:CLIENT_EVAL:client-side.js:140",
104
- "llm-owasp:llm-owasp.js:180:llm01-dynamic-system:concat",
105
- "llm-owasp:llm-owasp.js:181:llm01-dynamic-system:fstring",
106
- "llm-owasp:llm-owasp.js:182:llm01-dynamic-system:template",
107
- "llm-owasp:llm-owasp.js:183:llm10-no-token-budget",
108
- "prompt-tpl:llm-owasp.js:125:Prompt_Template__user_input_interpolated_into_prompt_string_",
109
- "zip-slip:zip-slip.js:192:node-entry"
110
- ]
111
- },
112
- {
113
- "timestamp": "2026-05-19T14:19:36.932Z",
114
- "label": "scan",
115
- "total": 10,
116
- "critical": 0,
117
- "high": 9,
118
- "medium": 1,
119
- "low": 0,
120
- "kev": 0,
121
- "ids": [
122
- "authz:authz.js:33:AuthZ__jwt_verify_called_without_algorithms_allow_list",
123
- "client-side:CLIENT_EVAL:client-side.js:135",
124
- "client-side:CLIENT_EVAL:client-side.js:139",
125
- "client-side:CLIENT_EVAL:client-side.js:140",
126
- "llm-owasp:llm-owasp.js:180:llm01-dynamic-system:concat",
127
- "llm-owasp:llm-owasp.js:181:llm01-dynamic-system:fstring",
128
- "llm-owasp:llm-owasp.js:182:llm01-dynamic-system:template",
129
- "llm-owasp:llm-owasp.js:183:llm10-no-token-budget",
130
- "prompt-tpl:llm-owasp.js:125:Prompt_Template__user_input_interpolated_into_prompt_string_",
131
- "zip-slip:zip-slip.js:192:node-entry"
132
- ]
133
- },
134
- {
135
- "timestamp": "2026-05-19T14:20:31.950Z",
136
- "label": "scan",
137
- "total": 10,
138
- "critical": 0,
139
- "high": 9,
140
- "medium": 1,
141
- "low": 0,
142
- "kev": 0,
143
- "ids": [
144
- "authz:authz.js:33:AuthZ__jwt_verify_called_without_algorithms_allow_list",
145
- "client-side:CLIENT_EVAL:client-side.js:135",
146
- "client-side:CLIENT_EVAL:client-side.js:139",
147
- "client-side:CLIENT_EVAL:client-side.js:140",
148
- "llm-owasp:llm-owasp.js:180:llm01-dynamic-system:concat",
149
- "llm-owasp:llm-owasp.js:181:llm01-dynamic-system:fstring",
150
- "llm-owasp:llm-owasp.js:182:llm01-dynamic-system:template",
151
- "llm-owasp:llm-owasp.js:183:llm10-no-token-budget",
152
- "prompt-tpl:llm-owasp.js:125:Prompt_Template__user_input_interpolated_into_prompt_string_",
153
- "zip-slip:zip-slip.js:192:node-entry"
154
- ]
155
- },
156
- {
157
- "timestamp": "2026-05-19T14:21:03.047Z",
158
- "label": "scan",
159
- "total": 10,
160
- "critical": 0,
161
- "high": 9,
162
- "medium": 1,
163
- "low": 0,
164
- "kev": 0,
165
- "ids": [
166
- "authz:authz.js:33:AuthZ__jwt_verify_called_without_algorithms_allow_list",
167
- "client-side:CLIENT_EVAL:client-side.js:135",
168
- "client-side:CLIENT_EVAL:client-side.js:139",
169
- "client-side:CLIENT_EVAL:client-side.js:140",
170
- "llm-owasp:llm-owasp.js:180:llm01-dynamic-system:concat",
171
- "llm-owasp:llm-owasp.js:181:llm01-dynamic-system:fstring",
172
- "llm-owasp:llm-owasp.js:182:llm01-dynamic-system:template",
173
- "llm-owasp:llm-owasp.js:183:llm10-no-token-budget",
174
- "prompt-tpl:llm-owasp.js:125:Prompt_Template__user_input_interpolated_into_prompt_string_",
175
- "zip-slip:zip-slip.js:192:node-entry"
176
- ]
177
- },
178
- {
179
- "timestamp": "2026-05-19T14:21:45.837Z",
180
- "label": "scan",
181
- "total": 10,
182
- "critical": 0,
183
- "high": 9,
184
- "medium": 1,
185
- "low": 0,
186
- "kev": 0,
187
- "ids": [
188
- "authz:authz.js:33:AuthZ__jwt_verify_called_without_algorithms_allow_list",
189
- "client-side:CLIENT_EVAL:client-side.js:135",
190
- "client-side:CLIENT_EVAL:client-side.js:139",
191
- "client-side:CLIENT_EVAL:client-side.js:140",
192
- "llm-owasp:llm-owasp.js:180:llm01-dynamic-system:concat",
193
- "llm-owasp:llm-owasp.js:181:llm01-dynamic-system:fstring",
194
- "llm-owasp:llm-owasp.js:182:llm01-dynamic-system:template",
195
- "llm-owasp:llm-owasp.js:183:llm10-no-token-budget",
196
- "prompt-tpl:llm-owasp.js:125:Prompt_Template__user_input_interpolated_into_prompt_string_",
197
- "zip-slip:zip-slip.js:192:node-entry"
198
- ]
199
- },
200
- {
201
- "timestamp": "2026-05-19T14:24:44.477Z",
202
- "label": "scan",
203
- "total": 10,
204
- "critical": 0,
205
- "high": 9,
206
- "medium": 1,
207
- "low": 0,
208
- "kev": 0,
209
- "ids": [
210
- "authz:authz.js:33:AuthZ__jwt_verify_called_without_algorithms_allow_list",
211
- "client-side:CLIENT_EVAL:client-side.js:135",
212
- "client-side:CLIENT_EVAL:client-side.js:139",
213
- "client-side:CLIENT_EVAL:client-side.js:140",
214
- "llm-owasp:llm-owasp.js:180:llm01-dynamic-system:concat",
215
- "llm-owasp:llm-owasp.js:181:llm01-dynamic-system:fstring",
216
- "llm-owasp:llm-owasp.js:182:llm01-dynamic-system:template",
217
- "llm-owasp:llm-owasp.js:183:llm10-no-token-budget",
218
- "prompt-tpl:llm-owasp.js:125:Prompt_Template__user_input_interpolated_into_prompt_string_",
219
- "zip-slip:zip-slip.js:192:node-entry"
220
- ]
221
- },
222
- {
223
- "timestamp": "2026-05-19T14:24:50.750Z",
224
- "label": "scan",
225
- "total": 10,
226
- "critical": 0,
227
- "high": 9,
228
- "medium": 1,
229
- "low": 0,
230
- "kev": 0,
231
- "ids": [
232
- "authz:authz.js:33:AuthZ__jwt_verify_called_without_algorithms_allow_list",
233
- "client-side:CLIENT_EVAL:client-side.js:135",
234
- "client-side:CLIENT_EVAL:client-side.js:139",
235
- "client-side:CLIENT_EVAL:client-side.js:140",
236
- "llm-owasp:llm-owasp.js:180:llm01-dynamic-system:concat",
237
- "llm-owasp:llm-owasp.js:181:llm01-dynamic-system:fstring",
238
- "llm-owasp:llm-owasp.js:182:llm01-dynamic-system:template",
239
- "llm-owasp:llm-owasp.js:183:llm10-no-token-budget",
240
- "prompt-tpl:llm-owasp.js:125:Prompt_Template__user_input_interpolated_into_prompt_string_",
241
- "zip-slip:zip-slip.js:192:node-entry"
242
- ]
243
- },
244
- {
245
- "timestamp": "2026-05-19T14:53:08.606Z",
246
- "label": "scan",
247
- "total": 10,
248
- "critical": 0,
249
- "high": 9,
250
- "medium": 1,
251
- "low": 0,
252
- "kev": 0,
253
- "ids": [
254
- "authz:authz.js:33:AuthZ__jwt_verify_called_without_algorithms_allow_list",
255
- "client-side:CLIENT_EVAL:client-side.js:135",
256
- "client-side:CLIENT_EVAL:client-side.js:139",
257
- "client-side:CLIENT_EVAL:client-side.js:140",
258
- "llm-owasp:llm-owasp.js:180:llm01-dynamic-system:concat",
259
- "llm-owasp:llm-owasp.js:181:llm01-dynamic-system:fstring",
260
- "llm-owasp:llm-owasp.js:182:llm01-dynamic-system:template",
261
- "llm-owasp:llm-owasp.js:183:llm10-no-token-budget",
262
- "prompt-tpl:llm-owasp.js:125:Prompt_Template__user_input_interpolated_into_prompt_string_",
263
- "zip-slip:zip-slip.js:192:node-entry"
264
- ]
265
- },
266
- {
267
- "timestamp": "2026-05-19T21:18:42.442Z",
268
- "label": "scan",
269
- "total": 17,
270
- "critical": 0,
271
- "high": 0,
272
- "medium": 2,
273
- "low": 15,
274
- "kev": 0,
275
- "ids": [
276
- "authz:authz.js:33:AuthZ__jwt_verify_called_without_algorithms_allow_list",
277
- "client-side:CLIENT_EVAL:client-side.js:135",
278
- "client-side:CLIENT_EVAL:client-side.js:139",
279
- "client-side:CLIENT_EVAL:client-side.js:140",
280
- "llm-owasp:llm-owasp.js:180:llm01-dynamic-system:concat",
281
- "llm-owasp:llm-owasp.js:181:llm01-dynamic-system:fstring",
282
- "llm-owasp:llm-owasp.js:182:llm01-dynamic-system:template",
283
- "llm-owasp:llm-owasp.js:183:llm10-no-token-budget",
284
- "prompt-tpl:llm-owasp.js:125:Prompt_Template__user_input_interpolated_into_prompt_string_",
285
- "spec-drift:rate-limit-impl:rate-limit.js:34",
286
- "spec-drift:rate-limit-impl:rate-limit.js:77",
287
- "ssrf-meta-hardcoded:go-extended.js:39",
288
- "ssrf-meta-hardcoded:python-sinks.js:186",
289
- "ssrf-meta-hardcoded:ssrf-cloud-metadata.js:15",
290
- "ssrf-meta-hardcoded:ssrf-cloud-metadata.js:48",
291
- "ssrf-meta-hardcoded:ssrf-cloud-metadata.js:73",
292
- "zip-slip:zip-slip.js:192:node-entry"
293
- ]
294
- },
295
- {
296
- "timestamp": "2026-05-20T12:47:36.689Z",
297
- "label": "scan",
298
- "total": 17,
299
- "critical": 0,
300
- "high": 0,
301
- "medium": 2,
302
- "low": 15,
303
- "kev": 0,
304
- "ids": [
305
- "authz:authz.js:33:AuthZ__jwt_verify_called_without_algorithms_allow_list",
306
- "client-side:CLIENT_EVAL:client-side.js:135",
307
- "client-side:CLIENT_EVAL:client-side.js:139",
308
- "client-side:CLIENT_EVAL:client-side.js:140",
309
- "llm-owasp:llm-owasp.js:180:llm01-dynamic-system:concat",
310
- "llm-owasp:llm-owasp.js:181:llm01-dynamic-system:fstring",
311
- "llm-owasp:llm-owasp.js:182:llm01-dynamic-system:template",
312
- "llm-owasp:llm-owasp.js:183:llm10-no-token-budget",
313
- "prompt-tpl:llm-owasp.js:125:Prompt_Template__user_input_interpolated_into_prompt_string_",
314
- "spec-drift:rate-limit-impl:rate-limit.js:34",
315
- "spec-drift:rate-limit-impl:rate-limit.js:77",
316
- "ssrf-meta-hardcoded:go-extended.js:39",
317
- "ssrf-meta-hardcoded:python-sinks.js:186",
318
- "ssrf-meta-hardcoded:ssrf-cloud-metadata.js:15",
319
- "ssrf-meta-hardcoded:ssrf-cloud-metadata.js:48",
320
- "ssrf-meta-hardcoded:ssrf-cloud-metadata.js:73",
321
- "zip-slip:zip-slip.js:192:node-entry"
322
- ]
323
- },
324
- {
325
- "timestamp": "2026-05-20T12:48:13.459Z",
326
- "label": "scan",
327
- "total": 17,
328
- "critical": 0,
329
- "high": 0,
330
- "medium": 2,
331
- "low": 15,
332
- "kev": 0,
333
- "ids": [
334
- "authz:authz.js:33:AuthZ__jwt_verify_called_without_algorithms_allow_list",
335
- "client-side:CLIENT_EVAL:client-side.js:135",
336
- "client-side:CLIENT_EVAL:client-side.js:139",
337
- "client-side:CLIENT_EVAL:client-side.js:140",
338
- "llm-owasp:llm-owasp.js:180:llm01-dynamic-system:concat",
339
- "llm-owasp:llm-owasp.js:181:llm01-dynamic-system:fstring",
340
- "llm-owasp:llm-owasp.js:182:llm01-dynamic-system:template",
341
- "llm-owasp:llm-owasp.js:183:llm10-no-token-budget",
342
- "prompt-tpl:llm-owasp.js:125:Prompt_Template__user_input_interpolated_into_prompt_string_",
343
- "spec-drift:rate-limit-impl:rate-limit.js:34",
344
- "spec-drift:rate-limit-impl:rate-limit.js:77",
345
- "ssrf-meta-hardcoded:go-extended.js:39",
346
- "ssrf-meta-hardcoded:python-sinks.js:186",
347
- "ssrf-meta-hardcoded:ssrf-cloud-metadata.js:15",
348
- "ssrf-meta-hardcoded:ssrf-cloud-metadata.js:48",
349
- "ssrf-meta-hardcoded:ssrf-cloud-metadata.js:73",
350
- "zip-slip:zip-slip.js:192:node-entry"
351
- ]
352
- },
353
- {
354
- "timestamp": "2026-05-20T12:49:02.792Z",
355
- "label": "scan",
356
- "total": 17,
357
- "critical": 0,
358
- "high": 0,
359
- "medium": 2,
360
- "low": 15,
361
- "kev": 0,
362
- "ids": [
363
- "authz:authz.js:33:AuthZ__jwt_verify_called_without_algorithms_allow_list",
364
- "client-side:CLIENT_EVAL:client-side.js:135",
365
- "client-side:CLIENT_EVAL:client-side.js:139",
366
- "client-side:CLIENT_EVAL:client-side.js:140",
367
- "llm-owasp:llm-owasp.js:180:llm01-dynamic-system:concat",
368
- "llm-owasp:llm-owasp.js:181:llm01-dynamic-system:fstring",
369
- "llm-owasp:llm-owasp.js:182:llm01-dynamic-system:template",
370
- "llm-owasp:llm-owasp.js:183:llm10-no-token-budget",
371
- "prompt-tpl:llm-owasp.js:125:Prompt_Template__user_input_interpolated_into_prompt_string_",
372
- "spec-drift:rate-limit-impl:rate-limit.js:34",
373
- "spec-drift:rate-limit-impl:rate-limit.js:77",
374
- "ssrf-meta-hardcoded:go-extended.js:39",
375
- "ssrf-meta-hardcoded:python-sinks.js:186",
376
- "ssrf-meta-hardcoded:ssrf-cloud-metadata.js:15",
377
- "ssrf-meta-hardcoded:ssrf-cloud-metadata.js:48",
378
- "ssrf-meta-hardcoded:ssrf-cloud-metadata.js:73",
379
- "zip-slip:zip-slip.js:192:node-entry"
380
- ]
381
- },
382
- {
383
- "timestamp": "2026-05-20T12:49:42.738Z",
3
+ "timestamp": "2026-05-26T16:30:07.351Z",
384
4
  "label": "scan",
385
5
  "total": 17,
386
6
  "critical": 0,
@@ -409,7 +29,7 @@
409
29
  ]
410
30
  },
411
31
  {
412
- "timestamp": "2026-05-20T12:51:21.872Z",
32
+ "timestamp": "2026-05-26T16:34:28.797Z",
413
33
  "label": "scan",
414
34
  "total": 17,
415
35
  "critical": 0,
@@ -438,7 +58,7 @@
438
58
  ]
439
59
  },
440
60
  {
441
- "timestamp": "2026-05-20T12:51:36.006Z",
61
+ "timestamp": "2026-05-27T01:10:20.082Z",
442
62
  "label": "scan",
443
63
  "total": 17,
444
64
  "critical": 0,
@@ -467,7 +87,7 @@
467
87
  ]
468
88
  },
469
89
  {
470
- "timestamp": "2026-05-20T12:52:34.978Z",
90
+ "timestamp": "2026-05-27T03:05:16.971Z",
471
91
  "label": "scan",
472
92
  "total": 17,
473
93
  "critical": 0,
@@ -496,7 +116,7 @@
496
116
  ]
497
117
  },
498
118
  {
499
- "timestamp": "2026-05-20T12:52:49.358Z",
119
+ "timestamp": "2026-05-27T03:18:22.550Z",
500
120
  "label": "scan",
501
121
  "total": 17,
502
122
  "critical": 0,
@@ -525,7 +145,7 @@
525
145
  ]
526
146
  },
527
147
  {
528
- "timestamp": "2026-05-20T12:54:08.915Z",
148
+ "timestamp": "2026-05-27T09:09:50.637Z",
529
149
  "label": "scan",
530
150
  "total": 17,
531
151
  "critical": 0,
@@ -554,7 +174,7 @@
554
174
  ]
555
175
  },
556
176
  {
557
- "timestamp": "2026-05-20T15:30:14.990Z",
177
+ "timestamp": "2026-05-27T09:10:10.121Z",
558
178
  "label": "scan",
559
179
  "total": 17,
560
180
  "critical": 0,
@@ -583,7 +203,7 @@
583
203
  ]
584
204
  },
585
205
  {
586
- "timestamp": "2026-05-20T15:30:55.692Z",
206
+ "timestamp": "2026-05-27T09:12:25.348Z",
587
207
  "label": "scan",
588
208
  "total": 17,
589
209
  "critical": 0,
@@ -612,7 +232,7 @@
612
232
  ]
613
233
  },
614
234
  {
615
- "timestamp": "2026-05-20T15:31:40.849Z",
235
+ "timestamp": "2026-05-27T09:17:13.165Z",
616
236
  "label": "scan",
617
237
  "total": 17,
618
238
  "critical": 0,
@@ -641,7 +261,7 @@
641
261
  ]
642
262
  },
643
263
  {
644
- "timestamp": "2026-05-20T15:33:07.999Z",
264
+ "timestamp": "2026-05-27T09:21:04.965Z",
645
265
  "label": "scan",
646
266
  "total": 17,
647
267
  "critical": 0,
@@ -670,7 +290,7 @@
670
290
  ]
671
291
  },
672
292
  {
673
- "timestamp": "2026-05-20T17:05:28.913Z",
293
+ "timestamp": "2026-05-27T09:21:46.189Z",
674
294
  "label": "scan",
675
295
  "total": 17,
676
296
  "critical": 0,
@@ -699,7 +319,7 @@
699
319
  ]
700
320
  },
701
321
  {
702
- "timestamp": "2026-05-20T17:06:53.366Z",
322
+ "timestamp": "2026-05-27T09:24:34.687Z",
703
323
  "label": "scan",
704
324
  "total": 17,
705
325
  "critical": 0,
@@ -728,7 +348,7 @@
728
348
  ]
729
349
  },
730
350
  {
731
- "timestamp": "2026-05-20T17:07:18.341Z",
351
+ "timestamp": "2026-05-27T09:43:08.807Z",
732
352
  "label": "scan",
733
353
  "total": 17,
734
354
  "critical": 0,
@@ -757,7 +377,7 @@
757
377
  ]
758
378
  },
759
379
  {
760
- "timestamp": "2026-05-20T17:07:59.605Z",
380
+ "timestamp": "2026-05-27T09:43:30.205Z",
761
381
  "label": "scan",
762
382
  "total": 17,
763
383
  "critical": 0,
@@ -1,23 +1,20 @@
1
1
  {
2
- "firstScanDate": "2026-05-13T13:02:38.907Z",
3
- "lastScanDate": "2026-05-20T17:07:59.655Z",
4
- "totalScans": 203,
5
- "daysCleanCritical": 4,
6
- "lastCleanDate": "2026-05-20",
2
+ "firstScanDate": "2026-05-26T16:30:07.386Z",
3
+ "lastScanDate": "2026-05-27T09:43:30.233Z",
4
+ "totalScans": 14,
5
+ "daysCleanCritical": 2,
6
+ "lastCleanDate": "2026-05-27",
7
7
  "lastCriticalDate": null,
8
8
  "hasEverHadCritical": false,
9
- "bestDaysCleanCritical": 4,
10
- "totalFindingsAtFirstScan": 11,
11
- "totalFindingsAtLastScan": 27,
12
- "totalFixesInferred": 1,
9
+ "bestDaysCleanCritical": 2,
10
+ "totalFindingsAtFirstScan": 27,
11
+ "totalFindingsAtLastScan": 28,
12
+ "totalFixesInferred": 0,
13
13
  "lastGrade": "A-",
14
14
  "bestGrade": "A-",
15
15
  "launchCheckPassedAt": null,
16
16
  "achievements": [
17
- "first-fix",
18
- "first-scan",
19
- "scan-veteran-100",
20
- "scan-veteran-25"
17
+ "first-scan"
21
18
  ],
22
19
  "previousGrade": "A-"
23
20
  }
@@ -0,0 +1,77 @@
1
+ // Cache poisoning via tainted response headers.
2
+ //
3
+ // Detects reflected request headers in responses that CDNs/proxies key on.
4
+ // X-Forwarded-Host, X-Forwarded-Proto, X-Original-URL reflected into
5
+ // response headers or HTML body enables web cache poisoning attacks.
6
+
7
+ function _line(raw, idx) { return raw.slice(0, idx).split('\n').length; }
8
+
9
+ const CACHE_KEY_HEADERS = /x-forwarded-host|x-forwarded-proto|x-original-url|x-rewrite-url|x-forwarded-for|x-host/i;
10
+ const TAINT_SOURCES = /req\.headers|request\.headers|request\.META|getHeader|get_header|\$_SERVER/;
11
+
12
+ export function scanCachePoisoning(fp, raw) {
13
+ if (!fp || !raw || typeof raw !== 'string') return [];
14
+ if (raw.length > 500_000) return [];
15
+ if (!/\.(?:js|jsx|ts|tsx|mjs|cjs|py|go|rb|php|phtml)$/i.test(fp)) return [];
16
+
17
+ const findings = [];
18
+
19
+ // Pattern 1: Reflected cache-key header in response
20
+ // res.setHeader('X-Forwarded-Host', req.headers['x-forwarded-host'])
21
+ const headerReflectRe = /(?:setHeader|set|header|add_header|Header\.Set|Header\.Add)\s*\(\s*['"]([^'"]+)['"]\s*,\s*[^)]*(?:req\.headers|request\.headers|request\.META|\$_SERVER)/g;
22
+ for (const m of raw.matchAll(headerReflectRe)) {
23
+ const headerName = m[1];
24
+ if (!CACHE_KEY_HEADERS.test(headerName)) continue;
25
+ const line = _line(raw, m.index);
26
+ findings.push({
27
+ id: `cache-poison-reflect:${fp}:${line}`,
28
+ file: fp, line,
29
+ vuln: `Cache Poisoning — ${headerName} reflected from request to response`,
30
+ severity: 'high',
31
+ family: 'cache-poisoning',
32
+ cwe: 'CWE-349',
33
+ parser: 'CACHE-POISON',
34
+ confidence: 0.75,
35
+ description: `The ${headerName} request header is reflected in the response. If a CDN or reverse proxy caches this response, an attacker can poison the cache for all users by sending a crafted ${headerName} value.`,
36
+ remediation: `Don't reflect ${headerName} into the response. If you need the value for redirects, validate it against an allow-list of trusted hosts.`,
37
+ });
38
+ }
39
+
40
+ // Pattern 2: Cache-Control or Vary set from user input
41
+ const cacheControlTaintRe = /(?:Cache-Control|Vary)\s*['"]\s*,\s*[^)]*(?:req\.|request\.|params|query|body|\$_GET|\$_REQUEST)/g;
42
+ for (const m of raw.matchAll(cacheControlTaintRe)) {
43
+ const line = _line(raw, m.index);
44
+ findings.push({
45
+ id: `cache-poison-control:${fp}:${line}`,
46
+ file: fp, line,
47
+ vuln: 'Cache Poisoning — Cache-Control or Vary header set from user input',
48
+ severity: 'high',
49
+ family: 'cache-poisoning',
50
+ cwe: 'CWE-349',
51
+ parser: 'CACHE-POISON',
52
+ confidence: 0.65,
53
+ description: 'Cache-Control or Vary response header is derived from user input. An attacker can manipulate caching behavior to serve stale or poisoned content.',
54
+ remediation: 'Set Cache-Control and Vary headers from server-side constants, never from user input.',
55
+ });
56
+ }
57
+
58
+ // Pattern 3: Host header used in URL generation (redirect/link)
59
+ const hostRedirectRe = /(?:req\.headers\.host|request\.get_host|request\.host|request\.META\s*\[\s*['"]HTTP_HOST['"])\s*[^;\n]*(?:redirect|location|href|url|link)/gi;
60
+ for (const m of raw.matchAll(hostRedirectRe)) {
61
+ const line = _line(raw, m.index);
62
+ findings.push({
63
+ id: `cache-poison-host:${fp}:${line}`,
64
+ file: fp, line,
65
+ vuln: 'Cache Poisoning — Host header used in URL/redirect generation',
66
+ severity: 'medium',
67
+ family: 'cache-poisoning',
68
+ cwe: 'CWE-644',
69
+ parser: 'CACHE-POISON',
70
+ confidence: 0.60,
71
+ description: 'The Host request header is used to generate URLs or redirects. Combined with caching, an attacker can redirect all cached users to a malicious host.',
72
+ remediation: 'Use a server-configured base URL instead of the Host header. Validate Host against an allow-list.',
73
+ });
74
+ }
75
+
76
+ return findings;
77
+ }
@@ -0,0 +1,73 @@
1
+ // Timing-safe comparison and type-coercion safety detector.
2
+ //
3
+ // Flags:
4
+ // 1. Direct === / == on HMAC/signature/token/OTP values (timing attack)
5
+ // 2. Loose == in authorization checks (type coercion)
6
+ // 3. Missing timingSafeEqual / hmac.compare_digest in verification functions
7
+
8
+ const TIMING_SENSITIVE = /\b(hmac|signature|digest|hash|mac|checksum|token|otp|apiKey|api_key|secret_key|webhook_secret|signing_key)\b/i;
9
+ const AUTH_CONTEXT = /\b(role|permission|isAdmin|is_admin|accessLevel|access_level|privilege|authorization|auth_level)\b/i;
10
+
11
+ function _line(raw, idx) { return raw.slice(0, idx).split('\n').length; }
12
+
13
+ export function scanComparisonSafety(fp, raw) {
14
+ if (!fp || !raw || typeof raw !== 'string') return [];
15
+ if (raw.length > 500_000) return [];
16
+ if (!/\.(?:js|jsx|ts|tsx|mjs|cjs|py|go)$/i.test(fp)) return [];
17
+
18
+ const findings = [];
19
+
20
+ // 1. Timing-unsafe comparison: x === y where x or y is named like a secret
21
+ for (const m of raw.matchAll(/(\w+)\s*===?\s*(\w+)/g)) {
22
+ const left = m[1], right = m[2];
23
+ if (!TIMING_SENSITIVE.test(left) && !TIMING_SENSITIVE.test(right)) continue;
24
+ const line = _line(raw, m.index);
25
+ const lineStart = raw.lastIndexOf('\n', m.index) + 1;
26
+ const lineText = raw.slice(lineStart, raw.indexOf('\n', m.index));
27
+ // Skip if timingSafeEqual or compare_digest is nearby
28
+ const context = raw.slice(Math.max(0, m.index - 200), m.index + 200);
29
+ if (/timingSafeEqual|compare_digest|ConstantTimeCompare|constant_time_compare/i.test(context)) continue;
30
+ // Skip if inside a comment
31
+ if (/^\s*\/\/|^\s*#|^\s*\*/.test(lineText)) continue;
32
+ findings.push({
33
+ id: `timing-unsafe:${fp}:${line}`,
34
+ file: fp, line,
35
+ vuln: 'Timing-Unsafe Comparison — secret/HMAC compared with === instead of timingSafeEqual',
36
+ severity: 'medium',
37
+ family: 'timing-attack',
38
+ cwe: 'CWE-208',
39
+ parser: 'COMPARISON',
40
+ confidence: 0.70,
41
+ description: `String === comparison on "${TIMING_SENSITIVE.exec(left + ' ' + right)?.[1] || 'secret'}" leaks timing information. An attacker can measure response times to guess the value byte-by-byte.`,
42
+ remediation: 'Use crypto.timingSafeEqual(Buffer.from(a), Buffer.from(b)) in Node.js, hmac.compare_digest(a, b) in Python, or subtle.ConstantTimeCompare(a, b) in Go.',
43
+ snippet: lineText.trim().slice(0, 100),
44
+ });
45
+ }
46
+
47
+ // 2. Loose equality == in auth context
48
+ for (const m of raw.matchAll(/(\w+)\s*==\s*(?!=)(\w+|['"][^'"]+['"])/g)) {
49
+ const left = m[1], right = m[2];
50
+ if (!AUTH_CONTEXT.test(left) && !AUTH_CONTEXT.test(right)) continue;
51
+ const line = _line(raw, m.index);
52
+ const lineStart = raw.lastIndexOf('\n', m.index) + 1;
53
+ const lineText = raw.slice(lineStart, raw.indexOf('\n', m.index));
54
+ if (/^\s*\/\/|^\s*#|^\s*\*/.test(lineText)) continue;
55
+ // Only flag JS/TS (Python and Go use == for equality, not coercion)
56
+ if (!/\.(?:js|jsx|ts|tsx|mjs|cjs)$/i.test(fp)) continue;
57
+ findings.push({
58
+ id: `loose-equality-auth:${fp}:${line}`,
59
+ file: fp, line,
60
+ vuln: 'Loose Equality in Auth Check — == allows type coercion bypass',
61
+ severity: 'high',
62
+ family: 'type-coercion',
63
+ cwe: 'CWE-697',
64
+ parser: 'COMPARISON',
65
+ confidence: 0.65,
66
+ description: `Loose equality (==) on "${AUTH_CONTEXT.exec(left + ' ' + right)?.[1] || 'auth field'}" allows type coercion. "1" == 1 is true; an attacker may bypass checks by sending a different type.`,
67
+ remediation: 'Use strict equality (===) for all authorization checks.',
68
+ snippet: lineText.trim().slice(0, 100),
69
+ });
70
+ }
71
+
72
+ return findings;
73
+ }