@oculum/scanner 1.0.10 → 1.0.12

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 (520) hide show
  1. package/dist/ai-context/index.d.ts +6 -0
  2. package/dist/ai-context/index.d.ts.map +1 -0
  3. package/dist/ai-context/index.js +13 -0
  4. package/dist/ai-context/index.js.map +1 -0
  5. package/dist/ai-context/manager.d.ts +67 -0
  6. package/dist/ai-context/manager.d.ts.map +1 -0
  7. package/dist/ai-context/manager.js +104 -0
  8. package/dist/ai-context/manager.js.map +1 -0
  9. package/dist/baseline/diff.d.ts +32 -0
  10. package/dist/baseline/diff.d.ts.map +1 -0
  11. package/dist/baseline/diff.js +119 -0
  12. package/dist/baseline/diff.js.map +1 -0
  13. package/dist/baseline/index.d.ts +9 -0
  14. package/dist/baseline/index.d.ts.map +1 -0
  15. package/dist/baseline/index.js +19 -0
  16. package/dist/baseline/index.js.map +1 -0
  17. package/dist/baseline/manager.d.ts +67 -0
  18. package/dist/baseline/manager.d.ts.map +1 -0
  19. package/dist/baseline/manager.js +180 -0
  20. package/dist/baseline/manager.js.map +1 -0
  21. package/dist/baseline/types.d.ts +91 -0
  22. package/dist/baseline/types.d.ts.map +1 -0
  23. package/dist/baseline/types.js +12 -0
  24. package/dist/baseline/types.js.map +1 -0
  25. package/dist/category-filter.d.ts +125 -0
  26. package/dist/category-filter.d.ts.map +1 -0
  27. package/dist/category-filter.js +360 -0
  28. package/dist/category-filter.js.map +1 -0
  29. package/dist/filtering/context-adjustments.d.ts +23 -0
  30. package/dist/filtering/context-adjustments.d.ts.map +1 -0
  31. package/dist/filtering/context-adjustments.js +100 -0
  32. package/dist/filtering/context-adjustments.js.map +1 -0
  33. package/dist/filtering/index.d.ts +3 -0
  34. package/dist/filtering/index.d.ts.map +1 -0
  35. package/dist/filtering/index.js +8 -0
  36. package/dist/filtering/index.js.map +1 -0
  37. package/dist/filtering/pipeline.d.ts +48 -0
  38. package/dist/filtering/pipeline.d.ts.map +1 -0
  39. package/dist/filtering/pipeline.js +76 -0
  40. package/dist/filtering/pipeline.js.map +1 -0
  41. package/dist/formatters/ai-context.d.ts +23 -0
  42. package/dist/formatters/ai-context.d.ts.map +1 -0
  43. package/dist/formatters/ai-context.js +238 -0
  44. package/dist/formatters/ai-context.js.map +1 -0
  45. package/dist/formatters/cli-terminal.d.ts +38 -0
  46. package/dist/formatters/cli-terminal.d.ts.map +1 -1
  47. package/dist/formatters/cli-terminal.js +365 -42
  48. package/dist/formatters/cli-terminal.js.map +1 -1
  49. package/dist/formatters/github-comment.d.ts +2 -2
  50. package/dist/formatters/github-comment.d.ts.map +1 -1
  51. package/dist/formatters/github-comment.js +77 -13
  52. package/dist/formatters/github-comment.js.map +1 -1
  53. package/dist/formatters/ide/claude-code.d.ts +17 -0
  54. package/dist/formatters/ide/claude-code.d.ts.map +1 -0
  55. package/dist/formatters/ide/claude-code.js +94 -0
  56. package/dist/formatters/ide/claude-code.js.map +1 -0
  57. package/dist/formatters/ide/cursor.d.ts +13 -0
  58. package/dist/formatters/ide/cursor.d.ts.map +1 -0
  59. package/dist/formatters/ide/cursor.js +125 -0
  60. package/dist/formatters/ide/cursor.js.map +1 -0
  61. package/dist/formatters/ide/index.d.ts +62 -0
  62. package/dist/formatters/ide/index.d.ts.map +1 -0
  63. package/dist/formatters/ide/index.js +184 -0
  64. package/dist/formatters/ide/index.js.map +1 -0
  65. package/dist/formatters/ide/windsurf.d.ts +13 -0
  66. package/dist/formatters/ide/windsurf.d.ts.map +1 -0
  67. package/dist/formatters/ide/windsurf.js +117 -0
  68. package/dist/formatters/ide/windsurf.js.map +1 -0
  69. package/dist/formatters/index.d.ts +3 -1
  70. package/dist/formatters/index.d.ts.map +1 -1
  71. package/dist/formatters/index.js +20 -1
  72. package/dist/formatters/index.js.map +1 -1
  73. package/dist/index.d.ts +11 -0
  74. package/dist/index.d.ts.map +1 -1
  75. package/dist/index.js +423 -56
  76. package/dist/index.js.map +1 -1
  77. package/dist/layer1/comments.d.ts +4 -1
  78. package/dist/layer1/comments.d.ts.map +1 -1
  79. package/dist/layer1/comments.js +1 -1
  80. package/dist/layer1/comments.js.map +1 -1
  81. package/dist/layer1/config-audit.d.ts +4 -1
  82. package/dist/layer1/config-audit.d.ts.map +1 -1
  83. package/dist/layer1/config-audit.js +65 -14
  84. package/dist/layer1/config-audit.js.map +1 -1
  85. package/dist/layer1/config-mcp-audit.d.ts +23 -0
  86. package/dist/layer1/config-mcp-audit.d.ts.map +1 -0
  87. package/dist/layer1/config-mcp-audit.js +239 -0
  88. package/dist/layer1/config-mcp-audit.js.map +1 -0
  89. package/dist/layer1/entropy.d.ts +4 -1
  90. package/dist/layer1/entropy.d.ts.map +1 -1
  91. package/dist/layer1/entropy.js +212 -1
  92. package/dist/layer1/entropy.js.map +1 -1
  93. package/dist/layer1/file-flags.d.ts +4 -1
  94. package/dist/layer1/file-flags.d.ts.map +1 -1
  95. package/dist/layer1/file-flags.js +12 -5
  96. package/dist/layer1/file-flags.js.map +1 -1
  97. package/dist/layer1/index.d.ts +1 -0
  98. package/dist/layer1/index.d.ts.map +1 -1
  99. package/dist/layer1/index.js +22 -19
  100. package/dist/layer1/index.js.map +1 -1
  101. package/dist/layer1/patterns.d.ts +4 -1
  102. package/dist/layer1/patterns.d.ts.map +1 -1
  103. package/dist/layer1/patterns.js +34 -4
  104. package/dist/layer1/patterns.js.map +1 -1
  105. package/dist/layer1/urls.d.ts +4 -1
  106. package/dist/layer1/urls.d.ts.map +1 -1
  107. package/dist/layer1/urls.js +162 -14
  108. package/dist/layer1/urls.js.map +1 -1
  109. package/dist/layer1/weak-crypto.d.ts +4 -1
  110. package/dist/layer1/weak-crypto.d.ts.map +1 -1
  111. package/dist/layer1/weak-crypto.js +144 -7
  112. package/dist/layer1/weak-crypto.js.map +1 -1
  113. package/dist/layer2/ai-agent-tools.d.ts +4 -1
  114. package/dist/layer2/ai-agent-tools.d.ts.map +1 -1
  115. package/dist/layer2/ai-agent-tools.js +964 -2
  116. package/dist/layer2/ai-agent-tools.js.map +1 -1
  117. package/dist/layer2/ai-endpoint-protection.d.ts +2 -0
  118. package/dist/layer2/ai-endpoint-protection.d.ts.map +1 -1
  119. package/dist/layer2/ai-endpoint-protection.js +18 -4
  120. package/dist/layer2/ai-endpoint-protection.js.map +1 -1
  121. package/dist/layer2/ai-execution-sinks.d.ts +4 -1
  122. package/dist/layer2/ai-execution-sinks.d.ts.map +1 -1
  123. package/dist/layer2/ai-execution-sinks.js +688 -29
  124. package/dist/layer2/ai-execution-sinks.js.map +1 -1
  125. package/dist/layer2/ai-fingerprinting.d.ts +4 -1
  126. package/dist/layer2/ai-fingerprinting.d.ts.map +1 -1
  127. package/dist/layer2/ai-fingerprinting.js +28 -32
  128. package/dist/layer2/ai-fingerprinting.js.map +1 -1
  129. package/dist/layer2/ai-mcp-security.d.ts +20 -0
  130. package/dist/layer2/ai-mcp-security.d.ts.map +1 -0
  131. package/dist/layer2/ai-mcp-security.js +877 -0
  132. package/dist/layer2/ai-mcp-security.js.map +1 -0
  133. package/dist/layer2/ai-package-hallucination.d.ts +22 -0
  134. package/dist/layer2/ai-package-hallucination.d.ts.map +1 -0
  135. package/dist/layer2/ai-package-hallucination.js +828 -0
  136. package/dist/layer2/ai-package-hallucination.js.map +1 -0
  137. package/dist/layer2/ai-prompt-hygiene.d.ts +4 -1
  138. package/dist/layer2/ai-prompt-hygiene.d.ts.map +1 -1
  139. package/dist/layer2/ai-prompt-hygiene.js +817 -17
  140. package/dist/layer2/ai-prompt-hygiene.js.map +1 -1
  141. package/dist/layer2/ai-rag-safety.d.ts +4 -1
  142. package/dist/layer2/ai-rag-safety.d.ts.map +1 -1
  143. package/dist/layer2/ai-rag-safety.js +454 -3
  144. package/dist/layer2/ai-rag-safety.js.map +1 -1
  145. package/dist/layer2/ai-schema-validation.d.ts +4 -1
  146. package/dist/layer2/ai-schema-validation.d.ts.map +1 -1
  147. package/dist/layer2/ai-schema-validation.js +2 -2
  148. package/dist/layer2/ai-schema-validation.js.map +1 -1
  149. package/dist/layer2/auth-antipatterns.d.ts +2 -0
  150. package/dist/layer2/auth-antipatterns.d.ts.map +1 -1
  151. package/dist/layer2/auth-antipatterns.js +209 -20
  152. package/dist/layer2/auth-antipatterns.js.map +1 -1
  153. package/dist/layer2/byok-patterns.d.ts +4 -1
  154. package/dist/layer2/byok-patterns.d.ts.map +1 -1
  155. package/dist/layer2/byok-patterns.js +5 -2
  156. package/dist/layer2/byok-patterns.js.map +1 -1
  157. package/dist/layer2/dangerous-functions/child-process.d.ts +16 -0
  158. package/dist/layer2/dangerous-functions/child-process.d.ts.map +1 -0
  159. package/dist/layer2/dangerous-functions/child-process.js +74 -0
  160. package/dist/layer2/dangerous-functions/child-process.js.map +1 -0
  161. package/dist/layer2/dangerous-functions/dom-xss.d.ts +34 -0
  162. package/dist/layer2/dangerous-functions/dom-xss.d.ts.map +1 -0
  163. package/dist/layer2/dangerous-functions/dom-xss.js +230 -0
  164. package/dist/layer2/dangerous-functions/dom-xss.js.map +1 -0
  165. package/dist/layer2/dangerous-functions/index.d.ts +16 -0
  166. package/dist/layer2/dangerous-functions/index.d.ts.map +1 -0
  167. package/dist/layer2/dangerous-functions/index.js +1152 -0
  168. package/dist/layer2/dangerous-functions/index.js.map +1 -0
  169. package/dist/layer2/dangerous-functions/json-parse.d.ts +31 -0
  170. package/dist/layer2/dangerous-functions/json-parse.d.ts.map +1 -0
  171. package/dist/layer2/dangerous-functions/json-parse.js +319 -0
  172. package/dist/layer2/dangerous-functions/json-parse.js.map +1 -0
  173. package/dist/layer2/dangerous-functions/math-random.d.ts +111 -0
  174. package/dist/layer2/dangerous-functions/math-random.d.ts.map +1 -0
  175. package/dist/layer2/dangerous-functions/math-random.js +684 -0
  176. package/dist/layer2/dangerous-functions/math-random.js.map +1 -0
  177. package/dist/layer2/dangerous-functions/patterns.d.ts +21 -0
  178. package/dist/layer2/dangerous-functions/patterns.d.ts.map +1 -0
  179. package/dist/layer2/dangerous-functions/patterns.js +163 -0
  180. package/dist/layer2/dangerous-functions/patterns.js.map +1 -0
  181. package/dist/layer2/dangerous-functions/request-validation.d.ts +13 -0
  182. package/dist/layer2/dangerous-functions/request-validation.d.ts.map +1 -0
  183. package/dist/layer2/dangerous-functions/request-validation.js +119 -0
  184. package/dist/layer2/dangerous-functions/request-validation.js.map +1 -0
  185. package/dist/layer2/dangerous-functions/utils/control-flow.d.ts +24 -0
  186. package/dist/layer2/dangerous-functions/utils/control-flow.d.ts.map +1 -0
  187. package/dist/layer2/dangerous-functions/utils/control-flow.js +70 -0
  188. package/dist/layer2/dangerous-functions/utils/control-flow.js.map +1 -0
  189. package/dist/layer2/dangerous-functions/utils/helpers.d.ts +31 -0
  190. package/dist/layer2/dangerous-functions/utils/helpers.d.ts.map +1 -0
  191. package/dist/layer2/dangerous-functions/utils/helpers.js +147 -0
  192. package/dist/layer2/dangerous-functions/utils/helpers.js.map +1 -0
  193. package/dist/layer2/dangerous-functions/utils/index.d.ts +9 -0
  194. package/dist/layer2/dangerous-functions/utils/index.d.ts.map +1 -0
  195. package/dist/layer2/dangerous-functions/utils/index.js +23 -0
  196. package/dist/layer2/dangerous-functions/utils/index.js.map +1 -0
  197. package/dist/layer2/dangerous-functions/utils/schema-validation.d.ts +22 -0
  198. package/dist/layer2/dangerous-functions/utils/schema-validation.d.ts.map +1 -0
  199. package/dist/layer2/dangerous-functions/utils/schema-validation.js +102 -0
  200. package/dist/layer2/dangerous-functions/utils/schema-validation.js.map +1 -0
  201. package/dist/layer2/data-exposure.d.ts +4 -1
  202. package/dist/layer2/data-exposure.d.ts.map +1 -1
  203. package/dist/layer2/data-exposure.js +14 -38
  204. package/dist/layer2/data-exposure.js.map +1 -1
  205. package/dist/layer2/framework-checks.d.ts +4 -1
  206. package/dist/layer2/framework-checks.d.ts.map +1 -1
  207. package/dist/layer2/framework-checks.js +5 -2
  208. package/dist/layer2/framework-checks.js.map +1 -1
  209. package/dist/layer2/index.d.ts +12 -1
  210. package/dist/layer2/index.d.ts.map +1 -1
  211. package/dist/layer2/index.js +110 -45
  212. package/dist/layer2/index.js.map +1 -1
  213. package/dist/layer2/logic-gates.d.ts +4 -1
  214. package/dist/layer2/logic-gates.d.ts.map +1 -1
  215. package/dist/layer2/logic-gates.js +58 -20
  216. package/dist/layer2/logic-gates.js.map +1 -1
  217. package/dist/layer2/model-supply-chain.d.ts +23 -0
  218. package/dist/layer2/model-supply-chain.d.ts.map +1 -0
  219. package/dist/layer2/model-supply-chain.js +444 -0
  220. package/dist/layer2/model-supply-chain.js.map +1 -0
  221. package/dist/layer2/risky-imports.d.ts +4 -1
  222. package/dist/layer2/risky-imports.d.ts.map +1 -1
  223. package/dist/layer2/risky-imports.js +6 -2
  224. package/dist/layer2/risky-imports.js.map +1 -1
  225. package/dist/layer2/variables.d.ts +4 -1
  226. package/dist/layer2/variables.d.ts.map +1 -1
  227. package/dist/layer2/variables.js +6 -2
  228. package/dist/layer2/variables.js.map +1 -1
  229. package/dist/layer3/anthropic/auto-dismiss.d.ts +24 -0
  230. package/dist/layer3/anthropic/auto-dismiss.d.ts.map +1 -0
  231. package/dist/layer3/anthropic/auto-dismiss.js +199 -0
  232. package/dist/layer3/anthropic/auto-dismiss.js.map +1 -0
  233. package/dist/layer3/anthropic/clients.d.ts +44 -0
  234. package/dist/layer3/anthropic/clients.d.ts.map +1 -0
  235. package/dist/layer3/anthropic/clients.js +81 -0
  236. package/dist/layer3/anthropic/clients.js.map +1 -0
  237. package/dist/layer3/anthropic/index.d.ts +41 -0
  238. package/dist/layer3/anthropic/index.d.ts.map +1 -0
  239. package/dist/layer3/anthropic/index.js +141 -0
  240. package/dist/layer3/anthropic/index.js.map +1 -0
  241. package/dist/layer3/anthropic/prompts/index.d.ts +8 -0
  242. package/dist/layer3/anthropic/prompts/index.d.ts.map +1 -0
  243. package/dist/layer3/anthropic/prompts/index.js +14 -0
  244. package/dist/layer3/anthropic/prompts/index.js.map +1 -0
  245. package/dist/layer3/anthropic/prompts/semantic-analysis.d.ts +15 -0
  246. package/dist/layer3/anthropic/prompts/semantic-analysis.d.ts.map +1 -0
  247. package/dist/layer3/anthropic/prompts/semantic-analysis.js +169 -0
  248. package/dist/layer3/anthropic/prompts/semantic-analysis.js.map +1 -0
  249. package/dist/layer3/anthropic/prompts/validation.d.ts +12 -0
  250. package/dist/layer3/anthropic/prompts/validation.d.ts.map +1 -0
  251. package/dist/layer3/anthropic/prompts/validation.js +421 -0
  252. package/dist/layer3/anthropic/prompts/validation.js.map +1 -0
  253. package/dist/layer3/anthropic/providers/anthropic.d.ts +21 -0
  254. package/dist/layer3/anthropic/providers/anthropic.d.ts.map +1 -0
  255. package/dist/layer3/anthropic/providers/anthropic.js +266 -0
  256. package/dist/layer3/anthropic/providers/anthropic.js.map +1 -0
  257. package/dist/layer3/anthropic/providers/index.d.ts +8 -0
  258. package/dist/layer3/anthropic/providers/index.d.ts.map +1 -0
  259. package/dist/layer3/anthropic/providers/index.js +15 -0
  260. package/dist/layer3/anthropic/providers/index.js.map +1 -0
  261. package/dist/layer3/anthropic/providers/openai.d.ts +18 -0
  262. package/dist/layer3/anthropic/providers/openai.d.ts.map +1 -0
  263. package/dist/layer3/anthropic/providers/openai.js +340 -0
  264. package/dist/layer3/anthropic/providers/openai.js.map +1 -0
  265. package/dist/layer3/anthropic/request-builder.d.ts +20 -0
  266. package/dist/layer3/anthropic/request-builder.d.ts.map +1 -0
  267. package/dist/layer3/anthropic/request-builder.js +134 -0
  268. package/dist/layer3/anthropic/request-builder.js.map +1 -0
  269. package/dist/layer3/anthropic/types.d.ts +88 -0
  270. package/dist/layer3/anthropic/types.d.ts.map +1 -0
  271. package/dist/layer3/anthropic/types.js +38 -0
  272. package/dist/layer3/anthropic/types.js.map +1 -0
  273. package/dist/layer3/anthropic/utils/index.d.ts +9 -0
  274. package/dist/layer3/anthropic/utils/index.d.ts.map +1 -0
  275. package/dist/layer3/anthropic/utils/index.js +24 -0
  276. package/dist/layer3/anthropic/utils/index.js.map +1 -0
  277. package/dist/layer3/anthropic/utils/path-helpers.d.ts +21 -0
  278. package/dist/layer3/anthropic/utils/path-helpers.d.ts.map +1 -0
  279. package/dist/layer3/anthropic/utils/path-helpers.js +69 -0
  280. package/dist/layer3/anthropic/utils/path-helpers.js.map +1 -0
  281. package/dist/layer3/anthropic/utils/response-parser.d.ts +40 -0
  282. package/dist/layer3/anthropic/utils/response-parser.d.ts.map +1 -0
  283. package/dist/layer3/anthropic/utils/response-parser.js +285 -0
  284. package/dist/layer3/anthropic/utils/response-parser.js.map +1 -0
  285. package/dist/layer3/anthropic/utils/retry.d.ts +15 -0
  286. package/dist/layer3/anthropic/utils/retry.d.ts.map +1 -0
  287. package/dist/layer3/anthropic/utils/retry.js +62 -0
  288. package/dist/layer3/anthropic/utils/retry.js.map +1 -0
  289. package/dist/layer3/index.d.ts +1 -0
  290. package/dist/layer3/index.d.ts.map +1 -1
  291. package/dist/layer3/index.js +16 -6
  292. package/dist/layer3/index.js.map +1 -1
  293. package/dist/layer3/osv-check.d.ts +75 -0
  294. package/dist/layer3/osv-check.d.ts.map +1 -0
  295. package/dist/layer3/osv-check.js +308 -0
  296. package/dist/layer3/osv-check.js.map +1 -0
  297. package/dist/modes/incremental.js +1 -1
  298. package/dist/rules/framework-fixes.d.ts +48 -0
  299. package/dist/rules/framework-fixes.d.ts.map +1 -0
  300. package/dist/rules/framework-fixes.js +439 -0
  301. package/dist/rules/framework-fixes.js.map +1 -0
  302. package/dist/rules/index.d.ts +8 -0
  303. package/dist/rules/index.d.ts.map +1 -0
  304. package/dist/rules/index.js +18 -0
  305. package/dist/rules/index.js.map +1 -0
  306. package/dist/rules/metadata.d.ts +43 -0
  307. package/dist/rules/metadata.d.ts.map +1 -0
  308. package/dist/rules/metadata.js +734 -0
  309. package/dist/rules/metadata.js.map +1 -0
  310. package/dist/suppression/config-loader.d.ts +74 -0
  311. package/dist/suppression/config-loader.d.ts.map +1 -0
  312. package/dist/suppression/config-loader.js +424 -0
  313. package/dist/suppression/config-loader.js.map +1 -0
  314. package/dist/suppression/hash.d.ts +48 -0
  315. package/dist/suppression/hash.d.ts.map +1 -0
  316. package/dist/suppression/hash.js +88 -0
  317. package/dist/suppression/hash.js.map +1 -0
  318. package/dist/suppression/index.d.ts +11 -0
  319. package/dist/suppression/index.d.ts.map +1 -0
  320. package/dist/suppression/index.js +39 -0
  321. package/dist/suppression/index.js.map +1 -0
  322. package/dist/suppression/inline-parser.d.ts +39 -0
  323. package/dist/suppression/inline-parser.d.ts.map +1 -0
  324. package/dist/suppression/inline-parser.js +218 -0
  325. package/dist/suppression/inline-parser.js.map +1 -0
  326. package/dist/suppression/manager.d.ts +94 -0
  327. package/dist/suppression/manager.d.ts.map +1 -0
  328. package/dist/suppression/manager.js +292 -0
  329. package/dist/suppression/manager.js.map +1 -0
  330. package/dist/suppression/types.d.ts +151 -0
  331. package/dist/suppression/types.d.ts.map +1 -0
  332. package/dist/suppression/types.js +28 -0
  333. package/dist/suppression/types.js.map +1 -0
  334. package/dist/tiers.d.ts +3 -3
  335. package/dist/tiers.d.ts.map +1 -1
  336. package/dist/tiers.js +34 -7
  337. package/dist/tiers.js.map +1 -1
  338. package/dist/types.d.ts +140 -9
  339. package/dist/types.d.ts.map +1 -1
  340. package/dist/types.js +34 -0
  341. package/dist/types.js.map +1 -1
  342. package/dist/utils/code-analysis.d.ts +39 -0
  343. package/dist/utils/code-analysis.d.ts.map +1 -0
  344. package/dist/utils/code-analysis.js +159 -0
  345. package/dist/utils/code-analysis.js.map +1 -0
  346. package/dist/utils/comment-analyzer.d.ts +38 -0
  347. package/dist/utils/comment-analyzer.d.ts.map +1 -0
  348. package/dist/utils/comment-analyzer.js +218 -0
  349. package/dist/utils/comment-analyzer.js.map +1 -0
  350. package/dist/utils/context-helpers.d.ts +112 -1
  351. package/dist/utils/context-helpers.d.ts.map +1 -1
  352. package/dist/utils/context-helpers.js +364 -11
  353. package/dist/utils/context-helpers.js.map +1 -1
  354. package/dist/utils/environment-context.d.ts +76 -0
  355. package/dist/utils/environment-context.d.ts.map +1 -0
  356. package/dist/utils/environment-context.js +271 -0
  357. package/dist/utils/environment-context.js.map +1 -0
  358. package/dist/utils/intent-detector.d.ts +66 -0
  359. package/dist/utils/intent-detector.d.ts.map +1 -0
  360. package/dist/utils/intent-detector.js +282 -0
  361. package/dist/utils/intent-detector.js.map +1 -0
  362. package/dist/utils/parsed-file.d.ts +51 -0
  363. package/dist/utils/parsed-file.d.ts.map +1 -0
  364. package/dist/utils/parsed-file.js +95 -0
  365. package/dist/utils/parsed-file.js.map +1 -0
  366. package/dist/utils/route-hierarchy.d.ts +50 -0
  367. package/dist/utils/route-hierarchy.d.ts.map +1 -0
  368. package/dist/utils/route-hierarchy.js +226 -0
  369. package/dist/utils/route-hierarchy.js.map +1 -0
  370. package/dist/utils/schema-semantics.d.ts +45 -0
  371. package/dist/utils/schema-semantics.d.ts.map +1 -0
  372. package/dist/utils/schema-semantics.js +193 -0
  373. package/dist/utils/schema-semantics.js.map +1 -0
  374. package/package.json +4 -2
  375. package/src/__tests__/benchmark/fixtures/layer1/mcp-config-audit.json +31 -0
  376. package/src/__tests__/benchmark/fixtures/layer2/ai-execution-sinks.ts +1489 -82
  377. package/src/__tests__/benchmark/fixtures/layer2/ai-mcp-security.ts +495 -0
  378. package/src/__tests__/benchmark/fixtures/layer2/ai-package-hallucination.ts +255 -0
  379. package/src/__tests__/benchmark/fixtures/layer2/ai-prompt-hygiene.ts +300 -1
  380. package/src/__tests__/benchmark/fixtures/layer2/ai-rag-safety.ts +139 -0
  381. package/src/__tests__/benchmark/fixtures/layer2/byok-patterns.ts +7 -0
  382. package/src/__tests__/benchmark/fixtures/layer2/data-exposure.ts +63 -0
  383. package/src/__tests__/benchmark/fixtures/layer2/excessive-agency.ts +221 -0
  384. package/src/__tests__/benchmark/fixtures/layer2/index.ts +30 -0
  385. package/src/__tests__/benchmark/fixtures/layer2/model-supply-chain.ts +204 -0
  386. package/src/__tests__/benchmark/fixtures/layer2/phase1-enhancements.ts +157 -0
  387. package/src/__tests__/benchmark/fixtures/layer2/phase5-excessive-agency.ts +580 -0
  388. package/src/__tests__/benchmark/fixtures/layer2/sprint6-ai-enhancements.ts +515 -0
  389. package/src/__tests__/benchmark/run-depth-validation.ts +9 -9
  390. package/src/__tests__/category-filter.test.ts +478 -0
  391. package/src/__tests__/regression/known-false-positives.test.ts +490 -0
  392. package/src/__tests__/snapshots/__snapshots__/anthropic-validation-refactor.test.ts.snap +762 -0
  393. package/src/__tests__/snapshots/__snapshots__/dangerous-functions-refactor.test.ts.snap +503 -0
  394. package/src/__tests__/snapshots/__snapshots__/scan-depth.test.ts.snap +0 -9
  395. package/src/__tests__/snapshots/anthropic-validation-refactor.test.ts +321 -0
  396. package/src/__tests__/snapshots/dangerous-functions-refactor.test.ts +439 -0
  397. package/src/__tests__/validation/run-validation.ts +7 -7
  398. package/src/ai-context/__tests__/manager.test.ts +193 -0
  399. package/src/ai-context/index.ts +15 -0
  400. package/src/ai-context/manager.ts +145 -0
  401. package/src/baseline/__tests__/diff.test.ts +261 -0
  402. package/src/baseline/__tests__/manager.test.ts +225 -0
  403. package/src/baseline/diff.ts +135 -0
  404. package/src/baseline/index.ts +29 -0
  405. package/src/baseline/manager.ts +230 -0
  406. package/src/baseline/types.ts +97 -0
  407. package/src/category-filter.ts +400 -0
  408. package/src/filtering/__tests__/pipeline.test.ts +134 -0
  409. package/src/filtering/context-adjustments.ts +111 -0
  410. package/src/filtering/index.ts +10 -0
  411. package/src/filtering/pipeline.ts +130 -0
  412. package/src/formatters/__tests__/ai-context.test.ts +254 -0
  413. package/src/formatters/ai-context.ts +302 -0
  414. package/src/formatters/cli-terminal.ts +444 -41
  415. package/src/formatters/github-comment.ts +82 -14
  416. package/src/formatters/ide/__tests__/ide.test.ts +319 -0
  417. package/src/formatters/ide/claude-code.ts +110 -0
  418. package/src/formatters/ide/cursor.ts +147 -0
  419. package/src/formatters/ide/index.ts +216 -0
  420. package/src/formatters/ide/windsurf.ts +135 -0
  421. package/src/formatters/index.ts +28 -0
  422. package/src/index.ts +506 -45
  423. package/src/layer1/comments.ts +3 -1
  424. package/src/layer1/config-audit.ts +74 -14
  425. package/src/layer1/config-mcp-audit.ts +278 -0
  426. package/src/layer1/entropy.ts +234 -1
  427. package/src/layer1/file-flags.ts +17 -6
  428. package/src/layer1/index.ts +29 -23
  429. package/src/layer1/patterns.ts +42 -4
  430. package/src/layer1/urls.ts +188 -14
  431. package/src/layer1/weak-crypto.ts +168 -16
  432. package/src/layer2/ai-agent-tools.ts +1043 -2
  433. package/src/layer2/ai-endpoint-protection.ts +19 -4
  434. package/src/layer2/ai-execution-sinks.ts +755 -29
  435. package/src/layer2/ai-fingerprinting.ts +33 -33
  436. package/src/layer2/ai-mcp-security.ts +933 -0
  437. package/src/layer2/ai-package-hallucination.ts +940 -0
  438. package/src/layer2/ai-prompt-hygiene.ts +898 -17
  439. package/src/layer2/ai-rag-safety.ts +467 -5
  440. package/src/layer2/ai-schema-validation.ts +4 -2
  441. package/src/layer2/auth-antipatterns.ts +235 -20
  442. package/src/layer2/byok-patterns.ts +9 -3
  443. package/src/layer2/dangerous-functions/child-process.ts +98 -0
  444. package/src/layer2/dangerous-functions/dom-xss.ts +292 -0
  445. package/src/layer2/dangerous-functions/index.ts +1533 -0
  446. package/src/layer2/dangerous-functions/json-parse.ts +385 -0
  447. package/src/layer2/dangerous-functions/math-random.ts +789 -0
  448. package/src/layer2/dangerous-functions/patterns.ts +176 -0
  449. package/src/layer2/dangerous-functions/request-validation.ts +145 -0
  450. package/src/layer2/dangerous-functions/utils/control-flow.ts +35 -0
  451. package/src/layer2/dangerous-functions/utils/helpers.ts +170 -0
  452. package/src/layer2/dangerous-functions/utils/index.ts +25 -0
  453. package/src/layer2/dangerous-functions/utils/schema-validation.ts +106 -0
  454. package/src/layer2/data-exposure.ts +18 -39
  455. package/src/layer2/framework-checks.ts +9 -2
  456. package/src/layer2/index.ts +124 -43
  457. package/src/layer2/logic-gates.ts +64 -22
  458. package/src/layer2/model-supply-chain.ts +531 -0
  459. package/src/layer2/risky-imports.ts +9 -2
  460. package/src/layer2/variables.ts +9 -2
  461. package/src/layer3/__tests__/osv-check.test.ts +384 -0
  462. package/src/layer3/anthropic/auto-dismiss.ts +223 -0
  463. package/src/layer3/anthropic/clients.ts +84 -0
  464. package/src/layer3/anthropic/index.ts +170 -0
  465. package/src/layer3/anthropic/prompts/index.ts +14 -0
  466. package/src/layer3/anthropic/prompts/semantic-analysis.ts +173 -0
  467. package/src/layer3/anthropic/prompts/validation.ts +419 -0
  468. package/src/layer3/anthropic/providers/anthropic.ts +310 -0
  469. package/src/layer3/anthropic/providers/index.ts +8 -0
  470. package/src/layer3/anthropic/providers/openai.ts +384 -0
  471. package/src/layer3/anthropic/request-builder.ts +150 -0
  472. package/src/layer3/anthropic/types.ts +148 -0
  473. package/src/layer3/anthropic/utils/index.ts +26 -0
  474. package/src/layer3/anthropic/utils/path-helpers.ts +68 -0
  475. package/src/layer3/anthropic/utils/response-parser.ts +322 -0
  476. package/src/layer3/anthropic/utils/retry.ts +75 -0
  477. package/src/layer3/index.ts +18 -5
  478. package/src/layer3/osv-check.ts +420 -0
  479. package/src/modes/incremental.ts +1 -1
  480. package/src/rules/__tests__/framework-fixes.test.ts +689 -0
  481. package/src/rules/__tests__/metadata.test.ts +218 -0
  482. package/src/rules/framework-fixes.ts +470 -0
  483. package/src/rules/index.ts +21 -0
  484. package/src/rules/metadata.ts +831 -0
  485. package/src/suppression/__tests__/config-loader.test.ts +382 -0
  486. package/src/suppression/__tests__/hash.test.ts +166 -0
  487. package/src/suppression/__tests__/inline-parser.test.ts +212 -0
  488. package/src/suppression/__tests__/manager.test.ts +415 -0
  489. package/src/suppression/config-loader.ts +462 -0
  490. package/src/suppression/hash.ts +95 -0
  491. package/src/suppression/index.ts +51 -0
  492. package/src/suppression/inline-parser.ts +273 -0
  493. package/src/suppression/manager.ts +379 -0
  494. package/src/suppression/types.ts +174 -0
  495. package/src/tiers.ts +45 -9
  496. package/src/types.ts +212 -8
  497. package/src/utils/__tests__/code-analysis.test.ts +165 -0
  498. package/src/utils/__tests__/parsed-file.test.ts +124 -0
  499. package/src/utils/code-analysis.ts +179 -0
  500. package/src/utils/comment-analyzer.ts +249 -0
  501. package/src/utils/context-helpers.ts +421 -11
  502. package/src/utils/environment-context.ts +304 -0
  503. package/src/utils/intent-detector.ts +318 -0
  504. package/src/utils/parsed-file.ts +103 -0
  505. package/src/utils/route-hierarchy.ts +250 -0
  506. package/src/utils/schema-semantics.ts +233 -0
  507. package/dist/layer2/dangerous-functions.d.ts +0 -7
  508. package/dist/layer2/dangerous-functions.d.ts.map +0 -1
  509. package/dist/layer2/dangerous-functions.js +0 -1701
  510. package/dist/layer2/dangerous-functions.js.map +0 -1
  511. package/dist/layer3/anthropic.d.ts +0 -87
  512. package/dist/layer3/anthropic.d.ts.map +0 -1
  513. package/dist/layer3/anthropic.js +0 -1948
  514. package/dist/layer3/anthropic.js.map +0 -1
  515. package/dist/layer3/openai.d.ts +0 -25
  516. package/dist/layer3/openai.d.ts.map +0 -1
  517. package/dist/layer3/openai.js +0 -238
  518. package/dist/layer3/openai.js.map +0 -1
  519. package/src/layer2/dangerous-functions.ts +0 -1940
  520. package/src/layer3/anthropic.ts +0 -2257
@@ -0,0 +1,789 @@
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 type { ParsedFile } from '../../utils/parsed-file'
14
+ import { extractFunctionContext } from './utils/control-flow'
15
+
16
+ /**
17
+ * Check if Math.random() is used in a jitter/backoff/retry context
18
+ * These are legitimate uses of Math.random() for network resilience,
19
+ * not security-sensitive randomness.
20
+ *
21
+ * Examples:
22
+ * const delay = baseDelay + Math.random() * jitter
23
+ * setTimeout(retry, delay * Math.random())
24
+ * await sleep(backoff * (1 + Math.random() * 0.1))
25
+ *
26
+ * @param content - Full file content
27
+ * @param lineNumber - The 0-indexed line number where Math.random() was found
28
+ */
29
+ export function isJitterOrBackoffContext(
30
+ content: string,
31
+ lineNumber: number,
32
+ lines?: string[]
33
+ ): boolean {
34
+ const _lines = lines ?? content.split('\n')
35
+ const start = Math.max(0, lineNumber - 10)
36
+ const end = Math.min(_lines.length, lineNumber + 5)
37
+ const context = _lines.slice(start, end).join('\n')
38
+
39
+ // Patterns indicating jitter/backoff/retry context
40
+ const jitterPatterns = [
41
+ // Direct keyword matches
42
+ /\b(jitter|backoff|retry|retries|exponential)\b/i,
43
+ // Delay/timeout with random
44
+ /setTimeout.*Math\.random/i,
45
+ /setInterval.*Math\.random/i,
46
+ /sleep.*Math\.random/i,
47
+ /await.*delay.*Math\.random/i,
48
+ // Common backoff patterns
49
+ /\* Math\.random\(\).*delay/i,
50
+ /delay\s*\*\s*Math\.random/i,
51
+ /Math\.random\(\)\s*\*\s*\d+.*delay/i,
52
+ // Retry-related function names
53
+ /function\s+(retry|withRetry|backoff|withBackoff|exponentialBackoff)/i,
54
+ // Common retry library patterns
55
+ /retryPolicy|retryConfig|retryOptions|maxRetries|retryCount/i,
56
+ // Network resilience patterns
57
+ /\b(throttle|debounce|rateLimit)\b.*Math\.random/i,
58
+ // Sampling/probability for non-security uses
59
+ /sampleRate|samplingRate|probability\s*[<>]=?\s*Math\.random/i,
60
+ ]
61
+
62
+ return jitterPatterns.some(p => p.test(context))
63
+ }
64
+
65
+ /**
66
+ * Check if Math.random() is used in a React key prop context
67
+ * This is a common pattern to force re-renders, not a security issue.
68
+ *
69
+ * Examples:
70
+ * key={Math.random()}
71
+ * key={`prefix-${Math.random()}`}
72
+ * key={Math.random().toString()}
73
+ *
74
+ * @param lineContent - The line of code to check
75
+ * @param filePath - The file path (only check JSX/TSX files)
76
+ */
77
+ export function isReactKeyPattern(lineContent: string, filePath: string): boolean {
78
+ // Only check in JSX/TSX files
79
+ if (!/\.[jt]sx$/.test(filePath)) {
80
+ return false
81
+ }
82
+
83
+ // Pattern: key={...Math.random()...}
84
+ // Matches:
85
+ // key={Math.random()}
86
+ // key={`foo-${Math.random()}`}
87
+ // key={Math.random().toString()}
88
+ // key={`${Math.random()}-bar`}
89
+ // key={something + Math.random()}
90
+ const keyPattern = /key\s*=\s*\{[^}]*Math\.random\(\)/
91
+ return keyPattern.test(lineContent)
92
+ }
93
+
94
+ /**
95
+ * Check if Math.random() is used for cosmetic/UI purposes (not security)
96
+ * Cosmetic uses: CSS values, animations, UI variations, demo data
97
+ * Security uses: tokens, IDs, cryptographic operations, session management
98
+ */
99
+ export function isCosmeticMathRandom(
100
+ lineContent: string,
101
+ content: string,
102
+ lineNumber: number,
103
+ lines?: string[]
104
+ ): boolean {
105
+ const _lines = lines ?? content.split('\n')
106
+
107
+ // Check the line itself for cosmetic indicators
108
+ const cosmeticLinePatterns = [
109
+ // CSS/style values
110
+ /['"`]\s*\$\{.*Math\.random.*\}\s*%['"`]/, // `${Math.random() * 40 + 50}%`
111
+ /Math\.random.*\s*\+\s*['"`]%['"`]/, // Math.random() * 40 + '%'
112
+ /Math\.random.*\)\s*\*\s*\d+\s*\+\s*\d+\s*\}\s*%/, // }) * 40 + 50}%
113
+ /return\s+`.*Math\.random.*%`/, // return `${...}%`
114
+ /width:\s*['"`].*Math\.random/i, // width: `${Math.random()...}%`
115
+ /height:\s*['"`].*Math\.random/i, // height: `${Math.random()...}%`
116
+ /opacity:\s*['"`]?.*Math\.random/i, // opacity: Math.random()
117
+ /transform:\s*['"`]?.*Math\.random/i, // transform: translate(...)
118
+ /rotate\(.*Math\.random/i, // rotate(Math.random() * 360)
119
+ /translate\(.*Math\.random/i, // translate(Math.random() * 100)
120
+ /scale\(.*Math\.random/i, // scale(Math.random() * 2)
121
+ // Color/animation values
122
+ /rgba?\(.*Math\.random/i, // rgb(Math.random() * 255, ...)
123
+ /hsl\(.*Math\.random/i, // hsl(Math.random() * 360, ...)
124
+ /Math\.random.*\*\s*360/, // Math.random() * 360 (degrees/hue)
125
+ /Math\.random.*\*\s*255/, // Math.random() * 255 (RGB values)
126
+ // Array/list randomization for UI
127
+ /Math\.floor\(Math\.random.*\.length\)/, // Math.floor(Math.random() * array.length)
128
+ /\[Math\.floor\(Math\.random/, // array[Math.floor(Math.random()...)]
129
+ // Demo/placeholder data
130
+ /Math\.random.*\*\s*\d+\s*\+\s*\d+.*\bpx\b/i, // Math.random() * 100 + 50 + 'px'
131
+ /Math\.random.*\*\s*\d+\s*\+\s*\d+.*\bms\b/i, // Math.random() * 1000 + 500 + 'ms'
132
+ /Math\.random.*\*\s*\d+\s*\+\s*\d+.*\bs\b/i, // Math.random() * 5 + 2 + 's'
133
+ // NOTE: toString patterns removed - now handled by analyzeToStringPattern()
134
+ // which provides more granular severity classification (info/low/medium/high)
135
+ // based on truncation length and context
136
+ ]
137
+
138
+ if (cosmeticLinePatterns.some(p => p.test(lineContent))) {
139
+ return true
140
+ }
141
+
142
+ // Check surrounding context (5 lines before and after)
143
+ const contextStart = Math.max(0, lineNumber - 5)
144
+ const contextEnd = Math.min(_lines.length, lineNumber + 5)
145
+ const context = _lines.slice(contextStart, contextEnd).join('\n')
146
+
147
+ // Context indicators of cosmetic use
148
+ const cosmeticContextPatterns = [
149
+ // UI component files - REMOVED, let severity classification handle these
150
+ // Style-related variables/functions
151
+ /\b(style|styles|css|className|animation|transition)/i,
152
+ /\b(width|height|opacity|color|transform|rotate|scale|translate)/i,
153
+ // Demo/example data
154
+ /\b(demo|example|placeholder|mock|fake|sample|test)Data/i,
155
+ /\b(random|shuffle|pick|choose).*\b(color|item|element|option)/i,
156
+ // Animation/timing
157
+ /setTimeout.*Math\.random/i,
158
+ /setInterval.*Math\.random/i,
159
+ /delay.*Math\.random/i,
160
+ /duration.*Math\.random/i,
161
+ // UI state variations
162
+ /\b(variant|theme|layout|position).*Math\.random/i,
163
+ // NOTE: Removed UI identifier patterns (key, id, tempId, etc.) - these should be
164
+ // classified with info/low severity by the severity classification logic, not skipped entirely
165
+ ]
166
+
167
+ if (cosmeticContextPatterns.some(p => p.test(context))) {
168
+ return true
169
+ }
170
+
171
+ // Security-sensitive patterns that override cosmetic detection
172
+ const securityPatterns = [
173
+ /\b(token|secret|key|password|credential|signature)/i,
174
+ /\b(auth|crypto|encrypt|decrypt|hash)/i,
175
+ /\b(session|nonce|salt)\b/i,
176
+ /Math\.random.*\*\s*1e\d+/, // Math.random() * 1e16 (large numbers for IDs)
177
+ ]
178
+
179
+ if (securityPatterns.some(p => p.test(lineContent) || p.test(context))) {
180
+ return false // Not cosmetic - this is security-sensitive
181
+ }
182
+
183
+ // Check for .toString(36) WITHOUT substring/slice/substr (security token pattern)
184
+ // If it has substring/slice/substr, it's already caught by cosmeticLinePatterns above
185
+ const hasToString36WithoutTruncation =
186
+ /Math\.random\(\)\.toString\(36\)/.test(lineContent) &&
187
+ !/\.(substring|substr|slice)\(/.test(lineContent)
188
+
189
+ const hasToString16WithoutTruncation =
190
+ /Math\.random\(\)\.toString\(16\)/.test(lineContent) &&
191
+ !/\.(substring|substr|slice)\(/.test(lineContent)
192
+
193
+ if (hasToString36WithoutTruncation || hasToString16WithoutTruncation) {
194
+ return false // Full-length toString() without truncation - likely security token
195
+ }
196
+
197
+ return false // Default to flagging if unclear
198
+ }
199
+
200
+ /**
201
+ * Classify function intent based on function name
202
+ * Used to determine if Math.random() usage is legitimate
203
+ */
204
+ export function classifyFunctionIntent(
205
+ functionName: string | null
206
+ ): 'uuid' | 'captcha' | 'demo' | 'security' | 'unknown' {
207
+ if (!functionName) return 'unknown'
208
+
209
+ const lower = functionName.toLowerCase()
210
+
211
+ // UUID/ID generation (UI correlation, not security)
212
+ // Check for specific UUID patterns and generic ID generation functions
213
+ const uuidPatterns = ['uuid', 'guid', 'uniqueid', 'correlationid', 'tempid', 'temp_id']
214
+ // Match patterns like generateId, generateTempId, createId, etc.
215
+ const idGenerationPatterns = /^(generate|create|make|build)(\w*)?(id|identifier)$/i
216
+ if (
217
+ uuidPatterns.some(p => lower.includes(p)) ||
218
+ idGenerationPatterns.test(lower)
219
+ ) {
220
+ return 'uuid'
221
+ }
222
+
223
+ // CAPTCHA/puzzle generation (legitimate non-security)
224
+ const captchaPatterns = ['captcha', 'puzzle', 'mathproblem']
225
+ // Also check for 'challenge' but only if not in security context
226
+ if (captchaPatterns.some(p => lower.includes(p))) return 'captcha'
227
+ if (lower.includes('challenge') && !lower.includes('auth')) return 'captcha'
228
+
229
+ // Demo/seed/fixture data
230
+ const demoPatterns = ['seed', 'fixture', 'demo', 'mock', 'fake']
231
+ if (demoPatterns.some(p => lower.includes(p))) return 'demo'
232
+
233
+ // Security-sensitive (check this after id generation to avoid false positives)
234
+ const securityPatterns = [
235
+ 'token',
236
+ 'secret',
237
+ 'key',
238
+ 'password',
239
+ 'credential',
240
+ 'signature',
241
+ ]
242
+ // Also match generate/create + security term combinations
243
+ const securityFunctionPattern =
244
+ /^(generate|create|make)(token|secret|key|session|password|credential)/i
245
+ if (
246
+ securityPatterns.some(p => lower.includes(p)) ||
247
+ securityFunctionPattern.test(lower)
248
+ ) {
249
+ return 'security'
250
+ }
251
+
252
+ return 'unknown'
253
+ }
254
+
255
+ /**
256
+ * Analyze toString() pattern in Math.random() usage
257
+ * Determines intent based on base and truncation length
258
+ */
259
+ export function analyzeToStringPattern(lineContent: string): {
260
+ hasToString: boolean
261
+ base: number | null
262
+ isTruncated: boolean
263
+ truncationLength: number | null
264
+ intent: 'short-ui-id' | 'business-id' | 'full-token' | 'unknown'
265
+ } {
266
+ const toString36Match = lineContent.match(/Math\.random\(\)\.toString\(36\)/)
267
+ const toString16Match = lineContent.match(/Math\.random\(\)\.toString\(16\)/)
268
+
269
+ if (!toString36Match && !toString16Match) {
270
+ return {
271
+ hasToString: false,
272
+ base: null,
273
+ isTruncated: false,
274
+ truncationLength: null,
275
+ intent: 'unknown',
276
+ }
277
+ }
278
+
279
+ const base = toString36Match ? 36 : 16
280
+
281
+ // Check for truncation methods
282
+ const substringMatch = lineContent.match(
283
+ /\.substring\((\d+)(?:,\s*(\d+))?\)/
284
+ )
285
+ const sliceMatch = lineContent.match(/\.slice\((\d+)(?:,\s*(\d+))?\)/)
286
+ const substrMatch = lineContent.match(/\.substr\((\d+)(?:,\s*(\d+))?\)/)
287
+
288
+ const truncMatch = substringMatch || sliceMatch || substrMatch
289
+
290
+ if (!truncMatch) {
291
+ return {
292
+ hasToString: true,
293
+ base,
294
+ isTruncated: false,
295
+ truncationLength: null,
296
+ intent: 'full-token',
297
+ }
298
+ }
299
+
300
+ // Calculate truncation length
301
+ const start = parseInt(truncMatch[1])
302
+ const end = truncMatch[2] ? parseInt(truncMatch[2]) : null
303
+
304
+ // If no end specified (e.g., .substring(7)), the result is from start to end of string
305
+ // Math.random().toString(36) produces ~11 chars like "0.abc123def"
306
+ // .substring(2) gives ~9 chars, .substring(7) gives ~4 chars
307
+ // Estimate remaining length: ~11 - start
308
+ const estimatedFullLength = 11
309
+ const length = end ? end - start : (start >= 2 ? estimatedFullLength - start : null)
310
+
311
+ // Classify intent by length
312
+ // Short (2-9 chars): UI correlation IDs, React keys
313
+ // Medium (10-15 chars): Business IDs, order numbers
314
+ if (length && length <= 9) {
315
+ return {
316
+ hasToString: true,
317
+ base,
318
+ isTruncated: true,
319
+ truncationLength: length,
320
+ intent: 'short-ui-id',
321
+ }
322
+ } else if (length && length <= 15) {
323
+ return {
324
+ hasToString: true,
325
+ base,
326
+ isTruncated: true,
327
+ truncationLength: length,
328
+ intent: 'business-id',
329
+ }
330
+ } else {
331
+ return {
332
+ hasToString: true,
333
+ base,
334
+ isTruncated: true,
335
+ truncationLength: length,
336
+ intent: 'business-id',
337
+ }
338
+ }
339
+ }
340
+
341
+ /**
342
+ * Extract variable name from Math.random() assignment
343
+ * Examples:
344
+ * const token = Math.random() -> "token"
345
+ * const businessId = Math.random().toString(36) -> "businessId"
346
+ * return Math.random() -> null (no variable)
347
+ */
348
+ export function extractMathRandomVariableName(
349
+ lineContent: string
350
+ ): string | null {
351
+ // const/let/var variableName = Math.random...
352
+ const assignmentMatch = lineContent.match(
353
+ /(?:const|let|var)\s+(\w+)\s*=.*Math\.random/
354
+ )
355
+ if (assignmentMatch) return assignmentMatch[1]
356
+
357
+ // object.property = Math.random...
358
+ const propertyMatch = lineContent.match(/(\w+)\s*[:=]\s*Math\.random/)
359
+ if (propertyMatch) return propertyMatch[1]
360
+
361
+ // function parameter default: functionName(param = Math.random())
362
+ const paramMatch = lineContent.match(/(\w+)\s*=\s*Math\.random/)
363
+ if (paramMatch) return paramMatch[1]
364
+
365
+ return null // No variable name found
366
+ }
367
+
368
+ /**
369
+ * Classify variable name security risk based on naming patterns
370
+ *
371
+ * High risk: Security-sensitive names (token, secret, key, etc.)
372
+ * Medium risk: Unclear context
373
+ * Low risk: Non-security names (id, businessId, orderId, etc.)
374
+ */
375
+ export function classifyVariableNameRisk(
376
+ varName: string | null
377
+ ): 'high' | 'medium' | 'low' {
378
+ if (!varName) return 'medium' // Unknown usage, moderate risk
379
+
380
+ const lower = varName.toLowerCase()
381
+
382
+ // High risk: security-sensitive variable names
383
+ // Note: 'key' alone is NOT included - it often means React key, not crypto key
384
+ // Instead, we match specific security key patterns
385
+ const highRiskPatterns = [
386
+ 'token',
387
+ 'secret',
388
+ 'password',
389
+ 'credential',
390
+ 'signature',
391
+ 'salt',
392
+ 'nonce',
393
+ 'session',
394
+ 'csrf',
395
+ 'auth',
396
+ 'apikey',
397
+ 'secretkey',
398
+ 'privatekey',
399
+ 'encryptionkey',
400
+ 'accesstoken',
401
+ 'refreshtoken',
402
+ 'jwt',
403
+ 'bearer',
404
+ 'oauth',
405
+ 'sessionid',
406
+ ]
407
+ if (highRiskPatterns.some(p => lower.includes(p))) {
408
+ return 'high'
409
+ }
410
+
411
+ // Low risk: clearly non-security contexts
412
+ const lowRiskPatterns = [
413
+ // Business identifiers
414
+ 'id',
415
+ 'uid',
416
+ 'guid',
417
+ 'business',
418
+ 'order',
419
+ 'invoice',
420
+ 'customer',
421
+ 'user',
422
+ 'product',
423
+ 'item',
424
+ 'transaction',
425
+ 'request',
426
+ 'reference',
427
+ 'tracking',
428
+ 'confirmation',
429
+ // Test/demo data
430
+ 'test',
431
+ 'mock',
432
+ 'demo',
433
+ 'sample',
434
+ 'example',
435
+ 'fixture',
436
+ 'random',
437
+ 'temp',
438
+ 'temporary',
439
+ 'generated',
440
+ 'dummy',
441
+ // UI identifiers (checked after high-risk, so 'apikey' etc. already caught)
442
+ 'key',
443
+ 'toast',
444
+ 'notification',
445
+ 'element',
446
+ 'component',
447
+ 'widget',
448
+ 'modal',
449
+ 'dialog',
450
+ 'popup',
451
+ 'unique',
452
+ 'react',
453
+ // Non-security randomness usage (backoff/sampling/experiments)
454
+ 'jitter',
455
+ 'retry',
456
+ 'backoff',
457
+ 'delay',
458
+ 'timeout',
459
+ 'latency',
460
+ 'sample',
461
+ 'sampling',
462
+ 'probability',
463
+ 'chance',
464
+ 'rollout',
465
+ 'experiment',
466
+ 'abtest',
467
+ 'cohort',
468
+ 'bucket',
469
+ 'variant',
470
+ ]
471
+ if (lowRiskPatterns.some(p => lower.includes(p))) {
472
+ return 'low'
473
+ }
474
+
475
+ return 'medium' // Unclear context, moderate risk
476
+ }
477
+
478
+ /**
479
+ * Analyze surrounding code context for security signals
480
+ * Returns context type and description for severity classification
481
+ */
482
+ export function analyzeMathRandomContext(
483
+ content: string,
484
+ filePath: string,
485
+ lineNumber: number,
486
+ lines?: string[]
487
+ ): {
488
+ inSecurityContext: boolean
489
+ inTestContext: boolean
490
+ inUIContext: boolean
491
+ inBusinessLogicContext: boolean
492
+ contextDescription: string
493
+ } {
494
+ const _lines = lines ?? content.split('\n')
495
+ const start = Math.max(0, lineNumber - 10)
496
+ const end = Math.min(_lines.length, lineNumber + 5)
497
+ const context = _lines.slice(start, end).join('\n')
498
+
499
+ // Security context indicators (functions, imports, comments)
500
+ const securityPatterns = [
501
+ /\b(generate|create)(Token|Secret|Key|Password|Nonce|Salt|Session|Signature)/i,
502
+ /\b(auth|crypto|encrypt|decrypt|hash|sign)\b/i,
503
+ /function\s+.*(?:token|secret|key|auth|crypto)/i,
504
+ /\bimport.*(?:crypto|jsonwebtoken|bcrypt|argon2|jose)/i,
505
+ /\/\*.*(?:security|authentication|cryptograph|authorization)/i,
506
+ /\/\/.*(?:security|auth|crypto|token|secret)/i,
507
+ ]
508
+ const inSecurityContext = securityPatterns.some(p => p.test(context))
509
+
510
+ // Test context
511
+ const testFilePatterns = /\.(test|spec)\.(ts|tsx|js|jsx)$/i
512
+ const testContextPatterns = [
513
+ /\b(describe|it|test|expect|mock|jest|vitest|mocha|chai)\b/i,
514
+ /\b(beforeEach|afterEach|beforeAll|afterAll)\b/i,
515
+ /\b(fixture|stub|spy)\b/i,
516
+ ]
517
+ const inTestContext =
518
+ testFilePatterns.test(filePath) ||
519
+ testContextPatterns.some(p => p.test(context))
520
+
521
+ // UI/cosmetic context (reuse existing logic)
522
+ const lineContent = _lines[lineNumber]
523
+ const inUIContext = isCosmeticMathRandom(lineContent, content, lineNumber, _lines)
524
+
525
+ // Business logic context (non-security ID generation)
526
+ // Note: UUID/CAPTCHA patterns excluded - handled by functionIntent classification
527
+ const businessLogicPatterns = [
528
+ /\b(business|order|invoice|customer|product|transaction)Id\b/i,
529
+ /\b(reference|tracking|confirmation)Number\b/i,
530
+ /\b(backoff|retry|jitter|delay|timeout|latency)\b/i,
531
+ /\b(sample|sampling|probability|chance|rollout|experiment|abtest|cohort|bucket|variant)\b/i,
532
+ // Load balancing and selection patterns
533
+ /mode\s*===?\s*['"]random['"]/i, // mode === 'random'
534
+ /\.\w*index\s*%/i, // round-robin patterns
535
+ /keys?\[.*Math\.random/i, // keys[Math.floor(Math.random() * keys.length)]
536
+ /\[\s*Math\.floor\s*\(\s*Math\.random/i, // array[Math.floor(Math.random()...)]
537
+ /shuffle/i, // shuffle functions
538
+ /pickRandom/i, // pickRandom helpers
539
+ /randomElement/i, // randomElement helpers
540
+ ]
541
+ const inBusinessLogicContext =
542
+ businessLogicPatterns.some(p => p.test(context)) && !inSecurityContext
543
+
544
+ // Determine context description
545
+ let contextDescription = 'unknown context'
546
+ if (inSecurityContext) {
547
+ contextDescription = 'security-sensitive function'
548
+ } else if (inTestContext) {
549
+ contextDescription = 'test/mock data generation'
550
+ } else if (inUIContext) {
551
+ contextDescription = 'UI/cosmetic usage'
552
+ } else if (inBusinessLogicContext) {
553
+ contextDescription = 'non-security usage'
554
+ }
555
+
556
+ return {
557
+ inSecurityContext,
558
+ inTestContext,
559
+ inUIContext,
560
+ inBusinessLogicContext,
561
+ contextDescription,
562
+ }
563
+ }
564
+
565
+ /**
566
+ * Check if file is an animation/motion component based on file name
567
+ * Files with animation-related names typically use Math.random for visual effects
568
+ */
569
+ export function isAnimationFile(filePath: string): boolean {
570
+ const animationPatterns = [
571
+ /animated[-_]/i, // animated-document-scanner.tsx
572
+ /[-_]animation/i, // document-animation.tsx
573
+ /motion[-_]/i, // motion-component.tsx
574
+ /[-_]motion/i, // scroll-motion.tsx
575
+ /particles?[-_]/i, // particles-background.tsx
576
+ /confetti/i, // confetti.tsx
577
+ /[-_]effect/i, // hover-effect.tsx
578
+ /transition[-_]/i, // transition-wrapper.tsx
579
+ /visual[-_]/i, // visual-effects.tsx
580
+ /canvas[-_]/i, // canvas-animation.tsx
581
+ ]
582
+ return animationPatterns.some(p => p.test(filePath))
583
+ }
584
+
585
+ /**
586
+ * Check if Math.random() is used for animation/motion coordinates
587
+ * Common in animation libraries like framer-motion, react-spring, Three.js, etc.
588
+ */
589
+ export function isAnimationCoordinateUsage(lineContent: string, context: string): boolean {
590
+ // Object property assignments for coordinates
591
+ const coordinatePatterns = [
592
+ /\bx:\s*Math\.random/i, // x: Math.random()
593
+ /\by:\s*Math\.random/i, // y: Math.random()
594
+ /\bz:\s*Math\.random/i, // z: Math.random()
595
+ /\bleft:\s*.*Math\.random/i, // left: Math.random()
596
+ /\btop:\s*.*Math\.random/i, // top: Math.random()
597
+ /\bright:\s*.*Math\.random/i, // right: Math.random()
598
+ /\bbottom:\s*.*Math\.random/i, // bottom: Math.random()
599
+ /\brotation:\s*.*Math\.random/i, // rotation: Math.random()
600
+ /\brotateX:\s*.*Math\.random/i, // rotateX: Math.random()
601
+ /\brotateY:\s*.*Math\.random/i, // rotateY: Math.random()
602
+ /\brotateZ:\s*.*Math\.random/i, // rotateZ: Math.random()
603
+ /\bscaleX?:\s*.*Math\.random/i, // scale/scaleX: Math.random()
604
+ /\bscaleY:\s*.*Math\.random/i, // scaleY: Math.random()
605
+ /\bopacity:\s*.*Math\.random/i, // opacity: Math.random()
606
+ /\bduration:\s*.*Math\.random/i, // duration: Math.random()
607
+ /\bdelay:\s*.*Math\.random/i, // delay: Math.random()
608
+ // 3D/Three.js specific patterns
609
+ /\boffset\s*=.*Math\.random/i, // offset = Math.random()
610
+ /useMemo\s*\(\s*\(\s*\)\s*=>\s*Math\.random/i, // useMemo(() => Math.random(), [])
611
+ /\bphase\s*[:=].*Math\.random/i, // phase: Math.random() or phase = Math.random()
612
+ /\bspeed\s*[:=].*Math\.random/i, // speed: Math.random()
613
+ /\bangle\s*[:=].*Math\.random/i, // angle: Math.random()
614
+ ]
615
+
616
+ if (coordinatePatterns.some(p => p.test(lineContent))) {
617
+ return true
618
+ }
619
+
620
+ // Motion/animation library context patterns
621
+ const motionLibraryPatterns = [
622
+ /framer-motion/i,
623
+ /react-spring/i,
624
+ /react-motion/i,
625
+ /gsap/i,
626
+ /animejs/i,
627
+ /popmotion/i,
628
+ /motion\.div/i,
629
+ /useSpring/i,
630
+ /useAnimation/i,
631
+ /animate\s*\(/i,
632
+ /keyframes/i,
633
+ // Three.js and React Three Fiber patterns
634
+ /three/i,
635
+ /useFrame/i,
636
+ /@react-three/i,
637
+ /Canvas/i, // React Three Fiber Canvas
638
+ /mesh/i, // Three.js mesh
639
+ /geometry/i, // Three.js geometry
640
+ /material/i, // Three.js material
641
+ ]
642
+
643
+ return motionLibraryPatterns.some(p => p.test(context))
644
+ }
645
+
646
+ /**
647
+ * Check if Math.random() is used in a template placeholder generator context
648
+ * Template systems often use random generators for placeholder values
649
+ *
650
+ * Examples:
651
+ * const templates = { random: () => Math.random().toString() }
652
+ * random_hex: () => Math.random().toString(16)
653
+ * {{random}} placeholder generation
654
+ */
655
+ export function isTemplatePlaceholderGenerator(
656
+ line: string,
657
+ content: string,
658
+ lineNumber: number,
659
+ lines?: string[]
660
+ ): boolean {
661
+ const _lines = lines ?? content.split('\n')
662
+ const contextStart = Math.max(0, lineNumber - 10)
663
+ const contextEnd = Math.min(_lines.length, lineNumber + 5)
664
+ const context = _lines.slice(contextStart, contextEnd).join('\n')
665
+
666
+ const templatePatterns = [
667
+ /\{\{random\w*\}\}/i, // {{random}}, {{random_hex}}, etc.
668
+ /random:\s*\(\s*\)\s*=>\s*Math\.random/i, // random: () => Math.random()
669
+ /random_\w+:\s*\(\s*\)\s*=>/i, // random_int: () => ...
670
+ /placeholder.*random/i, // placeholder context
671
+ /templates?\s*[=:]\s*\{/i, // templates = { or template: {
672
+ /generatePlaceholder/i, // generatePlaceholder function
673
+ /placeholder\s*[:=]/i, // placeholder: or placeholder =
674
+ ]
675
+
676
+ return templatePatterns.some(p => p.test(context) || p.test(line))
677
+ }
678
+
679
+ /**
680
+ * Check if Math.random() should be skipped entirely
681
+ * Returns true for seed files, test fixtures, captcha/puzzle, uuid, React keys, jitter/backoff, and pure cosmetic uses
682
+ */
683
+ export function shouldSkipMathRandom(
684
+ content: string,
685
+ filePath: string,
686
+ lineNumber: number,
687
+ options?: { parsed?: ParsedFile }
688
+ ): boolean {
689
+ // Seed/data generation files - skip entirely
690
+ if (isSeedOrDataGenFile(filePath)) {
691
+ return true
692
+ }
693
+
694
+ // Animation/motion component files - skip entirely
695
+ // These use Math.random for visual effects, not security
696
+ if (isAnimationFile(filePath)) {
697
+ return true
698
+ }
699
+
700
+ // Educational/intentional vulnerability files - skip entirely
701
+ // These include OWASP Juice Shop, intentionally-vulnerable examples, etc.
702
+ if (isEducationalVulnerabilityFile(filePath)) {
703
+ return true
704
+ }
705
+
706
+ // Check for React key pattern - this is a common pattern to force re-renders
707
+ // It's not a security issue, just a way to reset component state
708
+ const lines = options?.parsed?.lines ?? content.split('\n')
709
+ const lineContent = lines[lineNumber] || ''
710
+ if (isReactKeyPattern(lineContent, filePath)) {
711
+ return true
712
+ }
713
+
714
+ // Template placeholder generators - skip entirely
715
+ // These generate placeholder values for templates, not security tokens
716
+ if (isTemplatePlaceholderGenerator(lineContent, content, lineNumber, lines)) {
717
+ return true
718
+ }
719
+
720
+ // Jitter/backoff/retry patterns - legitimate non-security use of randomness
721
+ // Used for network resilience, rate limiting, exponential backoff, etc.
722
+ if (isJitterOrBackoffContext(content, lineNumber, lines)) {
723
+ return true
724
+ }
725
+
726
+ // Test files with test fixture patterns
727
+ if (isTestOrMockFile(filePath)) {
728
+ const line = lines[lineNumber]
729
+ // If in a test file and generating test data, skip
730
+ if (
731
+ /\b(mock|fake|fixture|test)Data/i.test(line) ||
732
+ /\b(it|test|describe)\s*\(/.test(line)
733
+ ) {
734
+ return true
735
+ }
736
+ }
737
+
738
+ // Pure cosmetic usage (CSS values, animations)
739
+ if (isCosmeticMathRandom(lineContent, content, lineNumber, lines)) {
740
+ // Additional check: if this is for animation/style, truly skip
741
+ const pureStylePatterns = [
742
+ /\.style\./,
743
+ /animation/i,
744
+ /transform/i,
745
+ /opacity/i,
746
+ /\brgb/i,
747
+ /\bhsl/i,
748
+ ]
749
+ if (pureStylePatterns.some(p => p.test(lineContent))) {
750
+ return true
751
+ }
752
+ }
753
+
754
+ // Animation coordinate usage (x, y, rotation, etc.)
755
+ // Get surrounding context for animation library detection
756
+ const contextStart = Math.max(0, lineNumber - 15)
757
+ const contextEnd = Math.min(lines.length, lineNumber + 5)
758
+ const animContext = lines.slice(contextStart, contextEnd).join('\n')
759
+ if (isAnimationCoordinateUsage(lineContent, animContext)) {
760
+ return true
761
+ }
762
+
763
+ // Check function context for demo/seed/captcha/uuid functions
764
+ const functionName = extractFunctionContext(content, lineNumber)
765
+ const functionIntent = classifyFunctionIntent(functionName)
766
+
767
+ // Skip demo, captcha, and uuid functions entirely - these are legitimate uses
768
+ if (functionIntent === 'demo' || functionIntent === 'captcha' || functionIntent === 'uuid') {
769
+ return true
770
+ }
771
+
772
+ // Check for fallback pattern: crypto.randomUUID?.() ?? Math.random()
773
+ // When a secure primary method is used with Math.random as fallback,
774
+ // the code is safe (Math.random only runs in environments without crypto API)
775
+ const prevLines = lines.slice(Math.max(0, lineNumber - 2), lineNumber + 1).join(' ')
776
+ const multiLineFallbackPatterns = [
777
+ /crypto\??\.?\s*randomUUID\??\.?\s*\(\s*\)\s*\?\?/i, // crypto.randomUUID() ??
778
+ /globalThis\.crypto\??\.?\s*randomUUID\??\.?\s*\(/i, // globalThis.crypto?.randomUUID?.()
779
+ /window\.crypto\??\.?\s*randomUUID\??\.?\s*\(/i, // window.crypto?.randomUUID?.()
780
+ /\?\.\s*randomUUID\??\.?\s*\(\s*\)\s*\?\?/i, // ?.randomUUID?.() ??
781
+ /crypto\??\.?\s*getRandomValues\s*\(/i, // crypto.getRandomValues()
782
+ /randomUUID\??\.?\s*\(\s*\)\s*\?\?/i, // randomUUID?.() ?? (generic)
783
+ ]
784
+ if (multiLineFallbackPatterns.some(p => p.test(prevLines))) {
785
+ return true // Skip - Math.random is only a fallback for missing crypto API
786
+ }
787
+
788
+ return false
789
+ }