@oculum/scanner 1.0.9 → 1.0.11

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 (365) hide show
  1. package/dist/baseline/diff.d.ts +32 -0
  2. package/dist/baseline/diff.d.ts.map +1 -0
  3. package/dist/baseline/diff.js +119 -0
  4. package/dist/baseline/diff.js.map +1 -0
  5. package/dist/baseline/index.d.ts +9 -0
  6. package/dist/baseline/index.d.ts.map +1 -0
  7. package/dist/baseline/index.js +19 -0
  8. package/dist/baseline/index.js.map +1 -0
  9. package/dist/baseline/manager.d.ts +67 -0
  10. package/dist/baseline/manager.d.ts.map +1 -0
  11. package/dist/baseline/manager.js +180 -0
  12. package/dist/baseline/manager.js.map +1 -0
  13. package/dist/baseline/types.d.ts +91 -0
  14. package/dist/baseline/types.d.ts.map +1 -0
  15. package/dist/baseline/types.js +12 -0
  16. package/dist/baseline/types.js.map +1 -0
  17. package/dist/formatters/cli-terminal.d.ts +38 -0
  18. package/dist/formatters/cli-terminal.d.ts.map +1 -1
  19. package/dist/formatters/cli-terminal.js +365 -42
  20. package/dist/formatters/cli-terminal.js.map +1 -1
  21. package/dist/formatters/github-comment.d.ts +1 -1
  22. package/dist/formatters/github-comment.d.ts.map +1 -1
  23. package/dist/formatters/github-comment.js +75 -11
  24. package/dist/formatters/github-comment.js.map +1 -1
  25. package/dist/formatters/index.d.ts +1 -1
  26. package/dist/formatters/index.d.ts.map +1 -1
  27. package/dist/formatters/index.js +4 -1
  28. package/dist/formatters/index.js.map +1 -1
  29. package/dist/index.d.ts +7 -0
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +155 -16
  32. package/dist/index.js.map +1 -1
  33. package/dist/layer1/config-audit.d.ts.map +1 -1
  34. package/dist/layer1/config-audit.js +20 -3
  35. package/dist/layer1/config-audit.js.map +1 -1
  36. package/dist/layer1/config-mcp-audit.d.ts +20 -0
  37. package/dist/layer1/config-mcp-audit.d.ts.map +1 -0
  38. package/dist/layer1/config-mcp-audit.js +239 -0
  39. package/dist/layer1/config-mcp-audit.js.map +1 -0
  40. package/dist/layer1/index.d.ts +1 -0
  41. package/dist/layer1/index.d.ts.map +1 -1
  42. package/dist/layer1/index.js +9 -1
  43. package/dist/layer1/index.js.map +1 -1
  44. package/dist/layer2/ai-agent-tools.d.ts.map +1 -1
  45. package/dist/layer2/ai-agent-tools.js +303 -0
  46. package/dist/layer2/ai-agent-tools.js.map +1 -1
  47. package/dist/layer2/ai-endpoint-protection.d.ts.map +1 -1
  48. package/dist/layer2/ai-endpoint-protection.js +17 -3
  49. package/dist/layer2/ai-endpoint-protection.js.map +1 -1
  50. package/dist/layer2/ai-execution-sinks.d.ts.map +1 -1
  51. package/dist/layer2/ai-execution-sinks.js +462 -12
  52. package/dist/layer2/ai-execution-sinks.js.map +1 -1
  53. package/dist/layer2/ai-fingerprinting.d.ts.map +1 -1
  54. package/dist/layer2/ai-fingerprinting.js +3 -0
  55. package/dist/layer2/ai-fingerprinting.js.map +1 -1
  56. package/dist/layer2/ai-mcp-security.d.ts +17 -0
  57. package/dist/layer2/ai-mcp-security.d.ts.map +1 -0
  58. package/dist/layer2/ai-mcp-security.js +679 -0
  59. package/dist/layer2/ai-mcp-security.js.map +1 -0
  60. package/dist/layer2/ai-package-hallucination.d.ts +19 -0
  61. package/dist/layer2/ai-package-hallucination.d.ts.map +1 -0
  62. package/dist/layer2/ai-package-hallucination.js +696 -0
  63. package/dist/layer2/ai-package-hallucination.js.map +1 -0
  64. package/dist/layer2/ai-prompt-hygiene.d.ts.map +1 -1
  65. package/dist/layer2/ai-prompt-hygiene.js +495 -9
  66. package/dist/layer2/ai-prompt-hygiene.js.map +1 -1
  67. package/dist/layer2/ai-rag-safety.d.ts.map +1 -1
  68. package/dist/layer2/ai-rag-safety.js +372 -1
  69. package/dist/layer2/ai-rag-safety.js.map +1 -1
  70. package/dist/layer2/auth-antipatterns.d.ts.map +1 -1
  71. package/dist/layer2/auth-antipatterns.js +4 -0
  72. package/dist/layer2/auth-antipatterns.js.map +1 -1
  73. package/dist/layer2/byok-patterns.d.ts.map +1 -1
  74. package/dist/layer2/byok-patterns.js +3 -0
  75. package/dist/layer2/byok-patterns.js.map +1 -1
  76. package/dist/layer2/dangerous-functions/child-process.d.ts +16 -0
  77. package/dist/layer2/dangerous-functions/child-process.d.ts.map +1 -0
  78. package/dist/layer2/dangerous-functions/child-process.js +74 -0
  79. package/dist/layer2/dangerous-functions/child-process.js.map +1 -0
  80. package/dist/layer2/dangerous-functions/dom-xss.d.ts +29 -0
  81. package/dist/layer2/dangerous-functions/dom-xss.d.ts.map +1 -0
  82. package/dist/layer2/dangerous-functions/dom-xss.js +179 -0
  83. package/dist/layer2/dangerous-functions/dom-xss.js.map +1 -0
  84. package/dist/layer2/dangerous-functions/index.d.ts +13 -0
  85. package/dist/layer2/dangerous-functions/index.d.ts.map +1 -0
  86. package/dist/layer2/dangerous-functions/index.js +621 -0
  87. package/dist/layer2/dangerous-functions/index.js.map +1 -0
  88. package/dist/layer2/dangerous-functions/json-parse.d.ts +31 -0
  89. package/dist/layer2/dangerous-functions/json-parse.d.ts.map +1 -0
  90. package/dist/layer2/dangerous-functions/json-parse.js +319 -0
  91. package/dist/layer2/dangerous-functions/json-parse.js.map +1 -0
  92. package/dist/layer2/dangerous-functions/math-random.d.ts +61 -0
  93. package/dist/layer2/dangerous-functions/math-random.d.ts.map +1 -0
  94. package/dist/layer2/dangerous-functions/math-random.js +459 -0
  95. package/dist/layer2/dangerous-functions/math-random.js.map +1 -0
  96. package/dist/layer2/dangerous-functions/patterns.d.ts +21 -0
  97. package/dist/layer2/dangerous-functions/patterns.d.ts.map +1 -0
  98. package/dist/layer2/dangerous-functions/patterns.js +161 -0
  99. package/dist/layer2/dangerous-functions/patterns.js.map +1 -0
  100. package/dist/layer2/dangerous-functions/request-validation.d.ts +13 -0
  101. package/dist/layer2/dangerous-functions/request-validation.d.ts.map +1 -0
  102. package/dist/layer2/dangerous-functions/request-validation.js +119 -0
  103. package/dist/layer2/dangerous-functions/request-validation.js.map +1 -0
  104. package/dist/layer2/dangerous-functions/utils/control-flow.d.ts +23 -0
  105. package/dist/layer2/dangerous-functions/utils/control-flow.d.ts.map +1 -0
  106. package/dist/layer2/dangerous-functions/utils/control-flow.js +149 -0
  107. package/dist/layer2/dangerous-functions/utils/control-flow.js.map +1 -0
  108. package/dist/layer2/dangerous-functions/utils/helpers.d.ts +31 -0
  109. package/dist/layer2/dangerous-functions/utils/helpers.d.ts.map +1 -0
  110. package/dist/layer2/dangerous-functions/utils/helpers.js +124 -0
  111. package/dist/layer2/dangerous-functions/utils/helpers.js.map +1 -0
  112. package/dist/layer2/dangerous-functions/utils/index.d.ts +9 -0
  113. package/dist/layer2/dangerous-functions/utils/index.d.ts.map +1 -0
  114. package/dist/layer2/dangerous-functions/utils/index.js +23 -0
  115. package/dist/layer2/dangerous-functions/utils/index.js.map +1 -0
  116. package/dist/layer2/dangerous-functions/utils/schema-validation.d.ts +22 -0
  117. package/dist/layer2/dangerous-functions/utils/schema-validation.d.ts.map +1 -0
  118. package/dist/layer2/dangerous-functions/utils/schema-validation.js +89 -0
  119. package/dist/layer2/dangerous-functions/utils/schema-validation.js.map +1 -0
  120. package/dist/layer2/data-exposure.d.ts.map +1 -1
  121. package/dist/layer2/data-exposure.js +3 -0
  122. package/dist/layer2/data-exposure.js.map +1 -1
  123. package/dist/layer2/framework-checks.d.ts.map +1 -1
  124. package/dist/layer2/framework-checks.js +3 -0
  125. package/dist/layer2/framework-checks.js.map +1 -1
  126. package/dist/layer2/index.d.ts +3 -0
  127. package/dist/layer2/index.d.ts.map +1 -1
  128. package/dist/layer2/index.js +61 -2
  129. package/dist/layer2/index.js.map +1 -1
  130. package/dist/layer2/logic-gates.d.ts.map +1 -1
  131. package/dist/layer2/logic-gates.js +4 -0
  132. package/dist/layer2/logic-gates.js.map +1 -1
  133. package/dist/layer2/model-supply-chain.d.ts +20 -0
  134. package/dist/layer2/model-supply-chain.d.ts.map +1 -0
  135. package/dist/layer2/model-supply-chain.js +376 -0
  136. package/dist/layer2/model-supply-chain.js.map +1 -0
  137. package/dist/layer2/risky-imports.d.ts.map +1 -1
  138. package/dist/layer2/risky-imports.js +4 -0
  139. package/dist/layer2/risky-imports.js.map +1 -1
  140. package/dist/layer2/variables.d.ts.map +1 -1
  141. package/dist/layer2/variables.js +4 -0
  142. package/dist/layer2/variables.js.map +1 -1
  143. package/dist/layer3/anthropic/auto-dismiss.d.ts +24 -0
  144. package/dist/layer3/anthropic/auto-dismiss.d.ts.map +1 -0
  145. package/dist/layer3/anthropic/auto-dismiss.js +188 -0
  146. package/dist/layer3/anthropic/auto-dismiss.js.map +1 -0
  147. package/dist/layer3/anthropic/clients.d.ts +44 -0
  148. package/dist/layer3/anthropic/clients.d.ts.map +1 -0
  149. package/dist/layer3/anthropic/clients.js +81 -0
  150. package/dist/layer3/anthropic/clients.js.map +1 -0
  151. package/dist/layer3/anthropic/index.d.ts +41 -0
  152. package/dist/layer3/anthropic/index.d.ts.map +1 -0
  153. package/dist/layer3/anthropic/index.js +141 -0
  154. package/dist/layer3/anthropic/index.js.map +1 -0
  155. package/dist/layer3/anthropic/prompts/index.d.ts +8 -0
  156. package/dist/layer3/anthropic/prompts/index.d.ts.map +1 -0
  157. package/dist/layer3/anthropic/prompts/index.js +14 -0
  158. package/dist/layer3/anthropic/prompts/index.js.map +1 -0
  159. package/dist/layer3/anthropic/prompts/semantic-analysis.d.ts +15 -0
  160. package/dist/layer3/anthropic/prompts/semantic-analysis.d.ts.map +1 -0
  161. package/dist/layer3/anthropic/prompts/semantic-analysis.js +169 -0
  162. package/dist/layer3/anthropic/prompts/semantic-analysis.js.map +1 -0
  163. package/dist/layer3/anthropic/prompts/validation.d.ts +12 -0
  164. package/dist/layer3/anthropic/prompts/validation.d.ts.map +1 -0
  165. package/dist/layer3/anthropic/prompts/validation.js +421 -0
  166. package/dist/layer3/anthropic/prompts/validation.js.map +1 -0
  167. package/dist/layer3/anthropic/providers/anthropic.d.ts +21 -0
  168. package/dist/layer3/anthropic/providers/anthropic.d.ts.map +1 -0
  169. package/dist/layer3/anthropic/providers/anthropic.js +266 -0
  170. package/dist/layer3/anthropic/providers/anthropic.js.map +1 -0
  171. package/dist/layer3/anthropic/providers/index.d.ts +8 -0
  172. package/dist/layer3/anthropic/providers/index.d.ts.map +1 -0
  173. package/dist/layer3/anthropic/providers/index.js +15 -0
  174. package/dist/layer3/anthropic/providers/index.js.map +1 -0
  175. package/dist/layer3/anthropic/providers/openai.d.ts +18 -0
  176. package/dist/layer3/anthropic/providers/openai.d.ts.map +1 -0
  177. package/dist/layer3/anthropic/providers/openai.js +340 -0
  178. package/dist/layer3/anthropic/providers/openai.js.map +1 -0
  179. package/dist/layer3/anthropic/request-builder.d.ts +20 -0
  180. package/dist/layer3/anthropic/request-builder.d.ts.map +1 -0
  181. package/dist/layer3/anthropic/request-builder.js +134 -0
  182. package/dist/layer3/anthropic/request-builder.js.map +1 -0
  183. package/dist/layer3/anthropic/types.d.ts +88 -0
  184. package/dist/layer3/anthropic/types.d.ts.map +1 -0
  185. package/dist/layer3/anthropic/types.js +38 -0
  186. package/dist/layer3/anthropic/types.js.map +1 -0
  187. package/dist/layer3/anthropic/utils/index.d.ts +9 -0
  188. package/dist/layer3/anthropic/utils/index.d.ts.map +1 -0
  189. package/dist/layer3/anthropic/utils/index.js +24 -0
  190. package/dist/layer3/anthropic/utils/index.js.map +1 -0
  191. package/dist/layer3/anthropic/utils/path-helpers.d.ts +21 -0
  192. package/dist/layer3/anthropic/utils/path-helpers.d.ts.map +1 -0
  193. package/dist/layer3/anthropic/utils/path-helpers.js +69 -0
  194. package/dist/layer3/anthropic/utils/path-helpers.js.map +1 -0
  195. package/dist/layer3/anthropic/utils/response-parser.d.ts +40 -0
  196. package/dist/layer3/anthropic/utils/response-parser.d.ts.map +1 -0
  197. package/dist/layer3/anthropic/utils/response-parser.js +285 -0
  198. package/dist/layer3/anthropic/utils/response-parser.js.map +1 -0
  199. package/dist/layer3/anthropic/utils/retry.d.ts +15 -0
  200. package/dist/layer3/anthropic/utils/retry.d.ts.map +1 -0
  201. package/dist/layer3/anthropic/utils/retry.js +62 -0
  202. package/dist/layer3/anthropic/utils/retry.js.map +1 -0
  203. package/dist/layer3/index.d.ts +1 -0
  204. package/dist/layer3/index.d.ts.map +1 -1
  205. package/dist/layer3/index.js +16 -6
  206. package/dist/layer3/index.js.map +1 -1
  207. package/dist/layer3/osv-check.d.ts +75 -0
  208. package/dist/layer3/osv-check.d.ts.map +1 -0
  209. package/dist/layer3/osv-check.js +308 -0
  210. package/dist/layer3/osv-check.js.map +1 -0
  211. package/dist/rules/framework-fixes.d.ts +48 -0
  212. package/dist/rules/framework-fixes.d.ts.map +1 -0
  213. package/dist/rules/framework-fixes.js +439 -0
  214. package/dist/rules/framework-fixes.js.map +1 -0
  215. package/dist/rules/index.d.ts +8 -0
  216. package/dist/rules/index.d.ts.map +1 -0
  217. package/dist/rules/index.js +18 -0
  218. package/dist/rules/index.js.map +1 -0
  219. package/dist/rules/metadata.d.ts +43 -0
  220. package/dist/rules/metadata.d.ts.map +1 -0
  221. package/dist/rules/metadata.js +734 -0
  222. package/dist/rules/metadata.js.map +1 -0
  223. package/dist/suppression/config-loader.d.ts +74 -0
  224. package/dist/suppression/config-loader.d.ts.map +1 -0
  225. package/dist/suppression/config-loader.js +424 -0
  226. package/dist/suppression/config-loader.js.map +1 -0
  227. package/dist/suppression/hash.d.ts +48 -0
  228. package/dist/suppression/hash.d.ts.map +1 -0
  229. package/dist/suppression/hash.js +88 -0
  230. package/dist/suppression/hash.js.map +1 -0
  231. package/dist/suppression/index.d.ts +11 -0
  232. package/dist/suppression/index.d.ts.map +1 -0
  233. package/dist/suppression/index.js +39 -0
  234. package/dist/suppression/index.js.map +1 -0
  235. package/dist/suppression/inline-parser.d.ts +39 -0
  236. package/dist/suppression/inline-parser.d.ts.map +1 -0
  237. package/dist/suppression/inline-parser.js +218 -0
  238. package/dist/suppression/inline-parser.js.map +1 -0
  239. package/dist/suppression/manager.d.ts +94 -0
  240. package/dist/suppression/manager.d.ts.map +1 -0
  241. package/dist/suppression/manager.js +292 -0
  242. package/dist/suppression/manager.js.map +1 -0
  243. package/dist/suppression/types.d.ts +151 -0
  244. package/dist/suppression/types.d.ts.map +1 -0
  245. package/dist/suppression/types.js +28 -0
  246. package/dist/suppression/types.js.map +1 -0
  247. package/dist/tiers.d.ts +1 -1
  248. package/dist/tiers.d.ts.map +1 -1
  249. package/dist/tiers.js +27 -0
  250. package/dist/tiers.js.map +1 -1
  251. package/dist/types.d.ts +62 -1
  252. package/dist/types.d.ts.map +1 -1
  253. package/dist/types.js.map +1 -1
  254. package/dist/utils/context-helpers.d.ts +4 -0
  255. package/dist/utils/context-helpers.d.ts.map +1 -1
  256. package/dist/utils/context-helpers.js +13 -9
  257. package/dist/utils/context-helpers.js.map +1 -1
  258. package/package.json +4 -2
  259. package/src/__tests__/benchmark/fixtures/layer1/mcp-config-audit.json +31 -0
  260. package/src/__tests__/benchmark/fixtures/layer2/ai-execution-sinks.ts +1489 -82
  261. package/src/__tests__/benchmark/fixtures/layer2/ai-mcp-security.ts +495 -0
  262. package/src/__tests__/benchmark/fixtures/layer2/ai-package-hallucination.ts +255 -0
  263. package/src/__tests__/benchmark/fixtures/layer2/ai-prompt-hygiene.ts +300 -1
  264. package/src/__tests__/benchmark/fixtures/layer2/ai-rag-safety.ts +139 -0
  265. package/src/__tests__/benchmark/fixtures/layer2/byok-patterns.ts +7 -0
  266. package/src/__tests__/benchmark/fixtures/layer2/data-exposure.ts +63 -0
  267. package/src/__tests__/benchmark/fixtures/layer2/excessive-agency.ts +221 -0
  268. package/src/__tests__/benchmark/fixtures/layer2/index.ts +18 -0
  269. package/src/__tests__/benchmark/fixtures/layer2/model-supply-chain.ts +204 -0
  270. package/src/__tests__/benchmark/fixtures/layer2/phase1-enhancements.ts +157 -0
  271. package/src/__tests__/snapshots/__snapshots__/anthropic-validation-refactor.test.ts.snap +758 -0
  272. package/src/__tests__/snapshots/__snapshots__/dangerous-functions-refactor.test.ts.snap +503 -0
  273. package/src/__tests__/snapshots/anthropic-validation-refactor.test.ts +321 -0
  274. package/src/__tests__/snapshots/dangerous-functions-refactor.test.ts +439 -0
  275. package/src/baseline/__tests__/diff.test.ts +261 -0
  276. package/src/baseline/__tests__/manager.test.ts +225 -0
  277. package/src/baseline/diff.ts +135 -0
  278. package/src/baseline/index.ts +29 -0
  279. package/src/baseline/manager.ts +230 -0
  280. package/src/baseline/types.ts +97 -0
  281. package/src/formatters/cli-terminal.ts +444 -41
  282. package/src/formatters/github-comment.ts +79 -11
  283. package/src/formatters/index.ts +4 -0
  284. package/src/index.ts +197 -14
  285. package/src/layer1/config-audit.ts +24 -3
  286. package/src/layer1/config-mcp-audit.ts +276 -0
  287. package/src/layer1/index.ts +16 -6
  288. package/src/layer2/ai-agent-tools.ts +336 -0
  289. package/src/layer2/ai-endpoint-protection.ts +16 -3
  290. package/src/layer2/ai-execution-sinks.ts +516 -12
  291. package/src/layer2/ai-fingerprinting.ts +5 -1
  292. package/src/layer2/ai-mcp-security.ts +730 -0
  293. package/src/layer2/ai-package-hallucination.ts +791 -0
  294. package/src/layer2/ai-prompt-hygiene.ts +547 -9
  295. package/src/layer2/ai-rag-safety.ts +382 -3
  296. package/src/layer2/auth-antipatterns.ts +5 -0
  297. package/src/layer2/byok-patterns.ts +5 -1
  298. package/src/layer2/dangerous-functions/child-process.ts +98 -0
  299. package/src/layer2/dangerous-functions/dom-xss.ts +220 -0
  300. package/src/layer2/dangerous-functions/index.ts +949 -0
  301. package/src/layer2/dangerous-functions/json-parse.ts +385 -0
  302. package/src/layer2/dangerous-functions/math-random.ts +537 -0
  303. package/src/layer2/dangerous-functions/patterns.ts +174 -0
  304. package/src/layer2/dangerous-functions/request-validation.ts +145 -0
  305. package/src/layer2/dangerous-functions/utils/control-flow.ts +162 -0
  306. package/src/layer2/dangerous-functions/utils/helpers.ts +170 -0
  307. package/src/layer2/dangerous-functions/utils/index.ts +25 -0
  308. package/src/layer2/dangerous-functions/utils/schema-validation.ts +91 -0
  309. package/src/layer2/data-exposure.ts +5 -1
  310. package/src/layer2/framework-checks.ts +5 -0
  311. package/src/layer2/index.ts +63 -1
  312. package/src/layer2/logic-gates.ts +5 -0
  313. package/src/layer2/model-supply-chain.ts +456 -0
  314. package/src/layer2/risky-imports.ts +5 -0
  315. package/src/layer2/variables.ts +5 -0
  316. package/src/layer3/__tests__/osv-check.test.ts +384 -0
  317. package/src/layer3/anthropic/auto-dismiss.ts +212 -0
  318. package/src/layer3/anthropic/clients.ts +84 -0
  319. package/src/layer3/anthropic/index.ts +170 -0
  320. package/src/layer3/anthropic/prompts/index.ts +14 -0
  321. package/src/layer3/anthropic/prompts/semantic-analysis.ts +173 -0
  322. package/src/layer3/anthropic/prompts/validation.ts +419 -0
  323. package/src/layer3/anthropic/providers/anthropic.ts +310 -0
  324. package/src/layer3/anthropic/providers/index.ts +8 -0
  325. package/src/layer3/anthropic/providers/openai.ts +384 -0
  326. package/src/layer3/anthropic/request-builder.ts +150 -0
  327. package/src/layer3/anthropic/types.ts +148 -0
  328. package/src/layer3/anthropic/utils/index.ts +26 -0
  329. package/src/layer3/anthropic/utils/path-helpers.ts +68 -0
  330. package/src/layer3/anthropic/utils/response-parser.ts +322 -0
  331. package/src/layer3/anthropic/utils/retry.ts +75 -0
  332. package/src/layer3/index.ts +18 -5
  333. package/src/layer3/osv-check.ts +420 -0
  334. package/src/rules/__tests__/framework-fixes.test.ts +689 -0
  335. package/src/rules/__tests__/metadata.test.ts +218 -0
  336. package/src/rules/framework-fixes.ts +470 -0
  337. package/src/rules/index.ts +21 -0
  338. package/src/rules/metadata.ts +831 -0
  339. package/src/suppression/__tests__/config-loader.test.ts +382 -0
  340. package/src/suppression/__tests__/hash.test.ts +166 -0
  341. package/src/suppression/__tests__/inline-parser.test.ts +212 -0
  342. package/src/suppression/__tests__/manager.test.ts +415 -0
  343. package/src/suppression/config-loader.ts +462 -0
  344. package/src/suppression/hash.ts +95 -0
  345. package/src/suppression/index.ts +51 -0
  346. package/src/suppression/inline-parser.ts +273 -0
  347. package/src/suppression/manager.ts +379 -0
  348. package/src/suppression/types.ts +174 -0
  349. package/src/tiers.ts +36 -0
  350. package/src/types.ts +90 -0
  351. package/src/utils/context-helpers.ts +13 -9
  352. package/dist/layer2/dangerous-functions.d.ts +0 -7
  353. package/dist/layer2/dangerous-functions.d.ts.map +0 -1
  354. package/dist/layer2/dangerous-functions.js +0 -1701
  355. package/dist/layer2/dangerous-functions.js.map +0 -1
  356. package/dist/layer3/anthropic.d.ts +0 -87
  357. package/dist/layer3/anthropic.d.ts.map +0 -1
  358. package/dist/layer3/anthropic.js +0 -1948
  359. package/dist/layer3/anthropic.js.map +0 -1
  360. package/dist/layer3/openai.d.ts +0 -25
  361. package/dist/layer3/openai.d.ts.map +0 -1
  362. package/dist/layer3/openai.js +0 -238
  363. package/dist/layer3/openai.js.map +0 -1
  364. package/src/layer2/dangerous-functions.ts +0 -1940
  365. package/src/layer3/anthropic.ts +0 -2257
@@ -0,0 +1,537 @@
1
+ /**
2
+ * Math.random() Detection
3
+ *
4
+ * Context-aware detection of Math.random() usage with intelligent severity
5
+ * classification based on usage context, variable names, and function intent.
6
+ */
7
+
8
+ import {
9
+ isTestOrMockFile,
10
+ isSeedOrDataGenFile,
11
+ isEducationalVulnerabilityFile,
12
+ } from '../../utils/context-helpers'
13
+ import { extractFunctionContext } from './utils/control-flow'
14
+
15
+ /**
16
+ * Check if Math.random() is used for cosmetic/UI purposes (not security)
17
+ * Cosmetic uses: CSS values, animations, UI variations, demo data
18
+ * Security uses: tokens, IDs, cryptographic operations, session management
19
+ */
20
+ export function isCosmeticMathRandom(
21
+ lineContent: string,
22
+ content: string,
23
+ lineNumber: number
24
+ ): boolean {
25
+ const lines = content.split('\n')
26
+
27
+ // Check the line itself for cosmetic indicators
28
+ const cosmeticLinePatterns = [
29
+ // CSS/style values
30
+ /['"`]\s*\$\{.*Math\.random.*\}\s*%['"`]/, // `${Math.random() * 40 + 50}%`
31
+ /Math\.random.*\s*\+\s*['"`]%['"`]/, // Math.random() * 40 + '%'
32
+ /Math\.random.*\)\s*\*\s*\d+\s*\+\s*\d+\s*\}\s*%/, // }) * 40 + 50}%
33
+ /return\s+`.*Math\.random.*%`/, // return `${...}%`
34
+ /width:\s*['"`].*Math\.random/i, // width: `${Math.random()...}%`
35
+ /height:\s*['"`].*Math\.random/i, // height: `${Math.random()...}%`
36
+ /opacity:\s*['"`]?.*Math\.random/i, // opacity: Math.random()
37
+ /transform:\s*['"`]?.*Math\.random/i, // transform: translate(...)
38
+ /rotate\(.*Math\.random/i, // rotate(Math.random() * 360)
39
+ /translate\(.*Math\.random/i, // translate(Math.random() * 100)
40
+ /scale\(.*Math\.random/i, // scale(Math.random() * 2)
41
+ // Color/animation values
42
+ /rgba?\(.*Math\.random/i, // rgb(Math.random() * 255, ...)
43
+ /hsl\(.*Math\.random/i, // hsl(Math.random() * 360, ...)
44
+ /Math\.random.*\*\s*360/, // Math.random() * 360 (degrees/hue)
45
+ /Math\.random.*\*\s*255/, // Math.random() * 255 (RGB values)
46
+ // Array/list randomization for UI
47
+ /Math\.floor\(Math\.random.*\.length\)/, // Math.floor(Math.random() * array.length)
48
+ /\[Math\.floor\(Math\.random/, // array[Math.floor(Math.random()...)]
49
+ // Demo/placeholder data
50
+ /Math\.random.*\*\s*\d+\s*\+\s*\d+.*\bpx\b/i, // Math.random() * 100 + 50 + 'px'
51
+ /Math\.random.*\*\s*\d+\s*\+\s*\d+.*\bms\b/i, // Math.random() * 1000 + 500 + 'ms'
52
+ /Math\.random.*\*\s*\d+\s*\+\s*\d+.*\bs\b/i, // Math.random() * 5 + 2 + 's'
53
+ // NOTE: toString patterns removed - now handled by analyzeToStringPattern()
54
+ // which provides more granular severity classification (info/low/medium/high)
55
+ // based on truncation length and context
56
+ ]
57
+
58
+ if (cosmeticLinePatterns.some(p => p.test(lineContent))) {
59
+ return true
60
+ }
61
+
62
+ // Check surrounding context (5 lines before and after)
63
+ const contextStart = Math.max(0, lineNumber - 5)
64
+ const contextEnd = Math.min(lines.length, lineNumber + 5)
65
+ const context = lines.slice(contextStart, contextEnd).join('\n')
66
+
67
+ // Context indicators of cosmetic use
68
+ const cosmeticContextPatterns = [
69
+ // UI component files - REMOVED, let severity classification handle these
70
+ // Style-related variables/functions
71
+ /\b(style|styles|css|className|animation|transition)/i,
72
+ /\b(width|height|opacity|color|transform|rotate|scale|translate)/i,
73
+ // Demo/example data
74
+ /\b(demo|example|placeholder|mock|fake|sample|test)Data/i,
75
+ /\b(random|shuffle|pick|choose).*\b(color|item|element|option)/i,
76
+ // Animation/timing
77
+ /setTimeout.*Math\.random/i,
78
+ /setInterval.*Math\.random/i,
79
+ /delay.*Math\.random/i,
80
+ /duration.*Math\.random/i,
81
+ // UI state variations
82
+ /\b(variant|theme|layout|position).*Math\.random/i,
83
+ // NOTE: Removed UI identifier patterns (key, id, tempId, etc.) - these should be
84
+ // classified with info/low severity by the severity classification logic, not skipped entirely
85
+ ]
86
+
87
+ if (cosmeticContextPatterns.some(p => p.test(context))) {
88
+ return true
89
+ }
90
+
91
+ // Security-sensitive patterns that override cosmetic detection
92
+ const securityPatterns = [
93
+ /\b(token|secret|key|password|credential|signature)/i,
94
+ /\b(auth|crypto|encrypt|decrypt|hash)/i,
95
+ /\b(session|nonce|salt)\b/i,
96
+ /Math\.random.*\*\s*1e\d+/, // Math.random() * 1e16 (large numbers for IDs)
97
+ ]
98
+
99
+ if (securityPatterns.some(p => p.test(lineContent) || p.test(context))) {
100
+ return false // Not cosmetic - this is security-sensitive
101
+ }
102
+
103
+ // Check for .toString(36) WITHOUT substring/slice/substr (security token pattern)
104
+ // If it has substring/slice/substr, it's already caught by cosmeticLinePatterns above
105
+ const hasToString36WithoutTruncation =
106
+ /Math\.random\(\)\.toString\(36\)/.test(lineContent) &&
107
+ !/\.(substring|substr|slice)\(/.test(lineContent)
108
+
109
+ const hasToString16WithoutTruncation =
110
+ /Math\.random\(\)\.toString\(16\)/.test(lineContent) &&
111
+ !/\.(substring|substr|slice)\(/.test(lineContent)
112
+
113
+ if (hasToString36WithoutTruncation || hasToString16WithoutTruncation) {
114
+ return false // Full-length toString() without truncation - likely security token
115
+ }
116
+
117
+ return false // Default to flagging if unclear
118
+ }
119
+
120
+ /**
121
+ * Classify function intent based on function name
122
+ * Used to determine if Math.random() usage is legitimate
123
+ */
124
+ export function classifyFunctionIntent(
125
+ functionName: string | null
126
+ ): 'uuid' | 'captcha' | 'demo' | 'security' | 'unknown' {
127
+ if (!functionName) return 'unknown'
128
+
129
+ const lower = functionName.toLowerCase()
130
+
131
+ // UUID/ID generation (UI correlation, not security)
132
+ // Check for specific UUID patterns and generic ID generation functions
133
+ const uuidPatterns = ['uuid', 'guid', 'uniqueid', 'correlationid', 'tempid', 'temp_id']
134
+ // Match patterns like generateId, generateTempId, createId, etc.
135
+ const idGenerationPatterns = /^(generate|create|make|build)(\w*)?(id|identifier)$/i
136
+ if (
137
+ uuidPatterns.some(p => lower.includes(p)) ||
138
+ idGenerationPatterns.test(lower)
139
+ ) {
140
+ return 'uuid'
141
+ }
142
+
143
+ // CAPTCHA/puzzle generation (legitimate non-security)
144
+ const captchaPatterns = ['captcha', 'puzzle', 'mathproblem']
145
+ // Also check for 'challenge' but only if not in security context
146
+ if (captchaPatterns.some(p => lower.includes(p))) return 'captcha'
147
+ if (lower.includes('challenge') && !lower.includes('auth')) return 'captcha'
148
+
149
+ // Demo/seed/fixture data
150
+ const demoPatterns = ['seed', 'fixture', 'demo', 'mock', 'fake']
151
+ if (demoPatterns.some(p => lower.includes(p))) return 'demo'
152
+
153
+ // Security-sensitive (check this after id generation to avoid false positives)
154
+ const securityPatterns = [
155
+ 'token',
156
+ 'secret',
157
+ 'key',
158
+ 'password',
159
+ 'credential',
160
+ 'signature',
161
+ ]
162
+ // Also match generate/create + security term combinations
163
+ const securityFunctionPattern =
164
+ /^(generate|create|make)(token|secret|key|session|password|credential)/i
165
+ if (
166
+ securityPatterns.some(p => lower.includes(p)) ||
167
+ securityFunctionPattern.test(lower)
168
+ ) {
169
+ return 'security'
170
+ }
171
+
172
+ return 'unknown'
173
+ }
174
+
175
+ /**
176
+ * Analyze toString() pattern in Math.random() usage
177
+ * Determines intent based on base and truncation length
178
+ */
179
+ export function analyzeToStringPattern(lineContent: string): {
180
+ hasToString: boolean
181
+ base: number | null
182
+ isTruncated: boolean
183
+ truncationLength: number | null
184
+ intent: 'short-ui-id' | 'business-id' | 'full-token' | 'unknown'
185
+ } {
186
+ const toString36Match = lineContent.match(/Math\.random\(\)\.toString\(36\)/)
187
+ const toString16Match = lineContent.match(/Math\.random\(\)\.toString\(16\)/)
188
+
189
+ if (!toString36Match && !toString16Match) {
190
+ return {
191
+ hasToString: false,
192
+ base: null,
193
+ isTruncated: false,
194
+ truncationLength: null,
195
+ intent: 'unknown',
196
+ }
197
+ }
198
+
199
+ const base = toString36Match ? 36 : 16
200
+
201
+ // Check for truncation methods
202
+ const substringMatch = lineContent.match(
203
+ /\.substring\((\d+)(?:,\s*(\d+))?\)/
204
+ )
205
+ const sliceMatch = lineContent.match(/\.slice\((\d+)(?:,\s*(\d+))?\)/)
206
+ const substrMatch = lineContent.match(/\.substr\((\d+)(?:,\s*(\d+))?\)/)
207
+
208
+ const truncMatch = substringMatch || sliceMatch || substrMatch
209
+
210
+ if (!truncMatch) {
211
+ return {
212
+ hasToString: true,
213
+ base,
214
+ isTruncated: false,
215
+ truncationLength: null,
216
+ intent: 'full-token',
217
+ }
218
+ }
219
+
220
+ // Calculate truncation length
221
+ const start = parseInt(truncMatch[1])
222
+ const end = truncMatch[2] ? parseInt(truncMatch[2]) : null
223
+
224
+ // If no end specified (e.g., .substring(7)), the result is from start to end of string
225
+ // Math.random().toString(36) produces ~11 chars like "0.abc123def"
226
+ // .substring(2) gives ~9 chars, .substring(7) gives ~4 chars
227
+ // Estimate remaining length: ~11 - start
228
+ const estimatedFullLength = 11
229
+ const length = end ? end - start : (start >= 2 ? estimatedFullLength - start : null)
230
+
231
+ // Classify intent by length
232
+ // Short (2-9 chars): UI correlation IDs, React keys
233
+ // Medium (10-15 chars): Business IDs, order numbers
234
+ if (length && length <= 9) {
235
+ return {
236
+ hasToString: true,
237
+ base,
238
+ isTruncated: true,
239
+ truncationLength: length,
240
+ intent: 'short-ui-id',
241
+ }
242
+ } else if (length && length <= 15) {
243
+ return {
244
+ hasToString: true,
245
+ base,
246
+ isTruncated: true,
247
+ truncationLength: length,
248
+ intent: 'business-id',
249
+ }
250
+ } else {
251
+ return {
252
+ hasToString: true,
253
+ base,
254
+ isTruncated: true,
255
+ truncationLength: length,
256
+ intent: 'business-id',
257
+ }
258
+ }
259
+ }
260
+
261
+ /**
262
+ * Extract variable name from Math.random() assignment
263
+ * Examples:
264
+ * const token = Math.random() -> "token"
265
+ * const businessId = Math.random().toString(36) -> "businessId"
266
+ * return Math.random() -> null (no variable)
267
+ */
268
+ export function extractMathRandomVariableName(
269
+ lineContent: string
270
+ ): string | null {
271
+ // const/let/var variableName = Math.random...
272
+ const assignmentMatch = lineContent.match(
273
+ /(?:const|let|var)\s+(\w+)\s*=.*Math\.random/
274
+ )
275
+ if (assignmentMatch) return assignmentMatch[1]
276
+
277
+ // object.property = Math.random...
278
+ const propertyMatch = lineContent.match(/(\w+)\s*[:=]\s*Math\.random/)
279
+ if (propertyMatch) return propertyMatch[1]
280
+
281
+ // function parameter default: functionName(param = Math.random())
282
+ const paramMatch = lineContent.match(/(\w+)\s*=\s*Math\.random/)
283
+ if (paramMatch) return paramMatch[1]
284
+
285
+ return null // No variable name found
286
+ }
287
+
288
+ /**
289
+ * Classify variable name security risk based on naming patterns
290
+ *
291
+ * High risk: Security-sensitive names (token, secret, key, etc.)
292
+ * Medium risk: Unclear context
293
+ * Low risk: Non-security names (id, businessId, orderId, etc.)
294
+ */
295
+ export function classifyVariableNameRisk(
296
+ varName: string | null
297
+ ): 'high' | 'medium' | 'low' {
298
+ if (!varName) return 'medium' // Unknown usage, moderate risk
299
+
300
+ const lower = varName.toLowerCase()
301
+
302
+ // High risk: security-sensitive variable names
303
+ // Note: 'key' alone is NOT included - it often means React key, not crypto key
304
+ // Instead, we match specific security key patterns
305
+ const highRiskPatterns = [
306
+ 'token',
307
+ 'secret',
308
+ 'password',
309
+ 'credential',
310
+ 'signature',
311
+ 'salt',
312
+ 'nonce',
313
+ 'session',
314
+ 'csrf',
315
+ 'auth',
316
+ 'apikey',
317
+ 'secretkey',
318
+ 'privatekey',
319
+ 'encryptionkey',
320
+ 'accesstoken',
321
+ 'refreshtoken',
322
+ 'jwt',
323
+ 'bearer',
324
+ 'oauth',
325
+ 'sessionid',
326
+ ]
327
+ if (highRiskPatterns.some(p => lower.includes(p))) {
328
+ return 'high'
329
+ }
330
+
331
+ // Low risk: clearly non-security contexts
332
+ const lowRiskPatterns = [
333
+ // Business identifiers
334
+ 'id',
335
+ 'uid',
336
+ 'guid',
337
+ 'business',
338
+ 'order',
339
+ 'invoice',
340
+ 'customer',
341
+ 'user',
342
+ 'product',
343
+ 'item',
344
+ 'transaction',
345
+ 'request',
346
+ 'reference',
347
+ 'tracking',
348
+ 'confirmation',
349
+ // Test/demo data
350
+ 'test',
351
+ 'mock',
352
+ 'demo',
353
+ 'sample',
354
+ 'example',
355
+ 'fixture',
356
+ 'random',
357
+ 'temp',
358
+ 'temporary',
359
+ 'generated',
360
+ 'dummy',
361
+ // UI identifiers (checked after high-risk, so 'apikey' etc. already caught)
362
+ 'key',
363
+ 'toast',
364
+ 'notification',
365
+ 'element',
366
+ 'component',
367
+ 'widget',
368
+ 'modal',
369
+ 'dialog',
370
+ 'popup',
371
+ 'unique',
372
+ 'react',
373
+ // Non-security randomness usage (backoff/sampling/experiments)
374
+ 'jitter',
375
+ 'retry',
376
+ 'backoff',
377
+ 'delay',
378
+ 'timeout',
379
+ 'latency',
380
+ 'sample',
381
+ 'sampling',
382
+ 'probability',
383
+ 'chance',
384
+ 'rollout',
385
+ 'experiment',
386
+ 'abtest',
387
+ 'cohort',
388
+ 'bucket',
389
+ 'variant',
390
+ ]
391
+ if (lowRiskPatterns.some(p => lower.includes(p))) {
392
+ return 'low'
393
+ }
394
+
395
+ return 'medium' // Unclear context, moderate risk
396
+ }
397
+
398
+ /**
399
+ * Analyze surrounding code context for security signals
400
+ * Returns context type and description for severity classification
401
+ */
402
+ export function analyzeMathRandomContext(
403
+ content: string,
404
+ filePath: string,
405
+ lineNumber: number
406
+ ): {
407
+ inSecurityContext: boolean
408
+ inTestContext: boolean
409
+ inUIContext: boolean
410
+ inBusinessLogicContext: boolean
411
+ contextDescription: string
412
+ } {
413
+ const lines = content.split('\n')
414
+ const start = Math.max(0, lineNumber - 10)
415
+ const end = Math.min(lines.length, lineNumber + 5)
416
+ const context = lines.slice(start, end).join('\n')
417
+
418
+ // Security context indicators (functions, imports, comments)
419
+ const securityPatterns = [
420
+ /\b(generate|create)(Token|Secret|Key|Password|Nonce|Salt|Session|Signature)/i,
421
+ /\b(auth|crypto|encrypt|decrypt|hash|sign)\b/i,
422
+ /function\s+.*(?:token|secret|key|auth|crypto)/i,
423
+ /\bimport.*(?:crypto|jsonwebtoken|bcrypt|argon2|jose)/i,
424
+ /\/\*.*(?:security|authentication|cryptograph|authorization)/i,
425
+ /\/\/.*(?:security|auth|crypto|token|secret)/i,
426
+ ]
427
+ const inSecurityContext = securityPatterns.some(p => p.test(context))
428
+
429
+ // Test context
430
+ const testFilePatterns = /\.(test|spec)\.(ts|tsx|js|jsx)$/i
431
+ const testContextPatterns = [
432
+ /\b(describe|it|test|expect|mock|jest|vitest|mocha|chai)\b/i,
433
+ /\b(beforeEach|afterEach|beforeAll|afterAll)\b/i,
434
+ /\b(fixture|stub|spy)\b/i,
435
+ ]
436
+ const inTestContext =
437
+ testFilePatterns.test(filePath) ||
438
+ testContextPatterns.some(p => p.test(context))
439
+
440
+ // UI/cosmetic context (reuse existing logic)
441
+ const lineContent = lines[lineNumber]
442
+ const inUIContext = isCosmeticMathRandom(lineContent, content, lineNumber)
443
+
444
+ // Business logic context (non-security ID generation)
445
+ // Note: UUID/CAPTCHA patterns excluded - handled by functionIntent classification
446
+ const businessLogicPatterns = [
447
+ /\b(business|order|invoice|customer|product|transaction)Id\b/i,
448
+ /\b(reference|tracking|confirmation)Number\b/i,
449
+ /\b(backoff|retry|jitter|delay|timeout|latency)\b/i,
450
+ /\b(sample|sampling|probability|chance|rollout|experiment|abtest|cohort|bucket|variant)\b/i,
451
+ ]
452
+ const inBusinessLogicContext =
453
+ businessLogicPatterns.some(p => p.test(context)) && !inSecurityContext
454
+
455
+ // Determine context description
456
+ let contextDescription = 'unknown context'
457
+ if (inSecurityContext) {
458
+ contextDescription = 'security-sensitive function'
459
+ } else if (inTestContext) {
460
+ contextDescription = 'test/mock data generation'
461
+ } else if (inUIContext) {
462
+ contextDescription = 'UI/cosmetic usage'
463
+ } else if (inBusinessLogicContext) {
464
+ contextDescription = 'non-security usage'
465
+ }
466
+
467
+ return {
468
+ inSecurityContext,
469
+ inTestContext,
470
+ inUIContext,
471
+ inBusinessLogicContext,
472
+ contextDescription,
473
+ }
474
+ }
475
+
476
+ /**
477
+ * Check if Math.random() should be skipped entirely
478
+ * Returns true for seed files, test fixtures, captcha/puzzle, uuid, and pure cosmetic uses
479
+ */
480
+ export function shouldSkipMathRandom(
481
+ content: string,
482
+ filePath: string,
483
+ lineNumber: number
484
+ ): boolean {
485
+ // Seed/data generation files - skip entirely
486
+ if (isSeedOrDataGenFile(filePath)) {
487
+ return true
488
+ }
489
+
490
+ // Educational/intentional vulnerability files - skip entirely
491
+ // These include OWASP Juice Shop, intentionally-vulnerable examples, etc.
492
+ if (isEducationalVulnerabilityFile(filePath)) {
493
+ return true
494
+ }
495
+
496
+ // Test files with test fixture patterns
497
+ if (isTestOrMockFile(filePath)) {
498
+ const lines = content.split('\n')
499
+ const line = lines[lineNumber]
500
+ // If in a test file and generating test data, skip
501
+ if (
502
+ /\b(mock|fake|fixture|test)Data/i.test(line) ||
503
+ /\b(it|test|describe)\s*\(/.test(line)
504
+ ) {
505
+ return true
506
+ }
507
+ }
508
+
509
+ // Pure cosmetic usage (CSS values, animations)
510
+ const lines = content.split('\n')
511
+ const lineContent = lines[lineNumber] || ''
512
+ if (isCosmeticMathRandom(lineContent, content, lineNumber)) {
513
+ // Additional check: if this is for animation/style, truly skip
514
+ const pureStylePatterns = [
515
+ /\.style\./,
516
+ /animation/i,
517
+ /transform/i,
518
+ /opacity/i,
519
+ /\brgb/i,
520
+ /\bhsl/i,
521
+ ]
522
+ if (pureStylePatterns.some(p => p.test(lineContent))) {
523
+ return true
524
+ }
525
+ }
526
+
527
+ // Check function context for demo/seed/captcha/uuid functions
528
+ const functionName = extractFunctionContext(content, lineNumber)
529
+ const functionIntent = classifyFunctionIntent(functionName)
530
+
531
+ // Skip demo, captcha, and uuid functions entirely - these are legitimate uses
532
+ if (functionIntent === 'demo' || functionIntent === 'captcha' || functionIntent === 'uuid') {
533
+ return true
534
+ }
535
+
536
+ return false
537
+ }