@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
@@ -4,6 +4,15 @@
4
4
  */
5
5
 
6
6
  import type { Vulnerability } from '../types'
7
+ import type { ParsedFile } from '../utils/parsed-file'
8
+ import { isTestConfigFile, isPythonFile, isInsidePythonDocstring } from '../utils/context-helpers'
9
+ import {
10
+ getEnvironmentContext,
11
+ isInPlaceholderAttribute,
12
+ isDefaultParameterValue,
13
+ getLocalhostSeverity,
14
+ } from '../utils/environment-context'
15
+ import { getRouteProtectionContext } from '../utils/route-hierarchy'
7
16
 
8
17
  // Check if file is documentation/README/example
9
18
  function isDocumentationFile(filePath: string): boolean {
@@ -26,6 +35,50 @@ function isDocumentationFile(filePath: string): boolean {
26
35
  return docPatterns.some(p => p.test(filePath))
27
36
  }
28
37
 
38
+ /**
39
+ * Check if file path indicates it's inside an authenticated route group
40
+ * Modern frameworks use route groups/layouts that handle auth at the layout level
41
+ *
42
+ * Examples:
43
+ * - Next.js: (authenticated)/dashboard/page.tsx, (admin)/users/page.tsx
44
+ * - Remix: _authenticated+/dashboard.tsx
45
+ * - SvelteKit: (protected)/+page.svelte
46
+ */
47
+ function isInsideAuthenticatedRouteGroup(filePath: string): boolean {
48
+ const authRoutePatterns = [
49
+ // Next.js App Router - route groups with auth-related names
50
+ /\/\(authenticated\)\//i,
51
+ /\/\(protected\)\//i,
52
+ /\/\(auth\)\//i,
53
+ /\/\(admin\)\//i,
54
+ /\/\(dashboard\)\//i,
55
+ /\/\(private\)\//i,
56
+ /\/\(secure\)\//i,
57
+ /\/\(user\)\//i,
58
+ /\/\(account\)\//i,
59
+ /\/\(settings\)\//i,
60
+ /\/\(app\)\//i, // Common pattern for authenticated app routes
61
+
62
+ // Remix - authenticated route conventions
63
+ /\/_authenticated\+\//i,
64
+ /\/_protected\+\//i,
65
+ /\/_auth\+\//i,
66
+ /\/__authenticated\//i,
67
+
68
+ // Generic patterns that indicate auth-protected sections
69
+ /\/dashboard\//i,
70
+ /\/admin\//i,
71
+ /\/account\//i,
72
+ /\/settings\//i,
73
+ /\/profile\//i,
74
+ /\/my-/i, // /my-account/, /my-orders/
75
+ /\/user\//i,
76
+ /\/users\/\[/i, // /users/[userId]/ - user-specific routes
77
+ ]
78
+
79
+ return authRoutePatterns.some(p => p.test(filePath))
80
+ }
81
+
29
82
  // Check if file is a config/constants file where localhost is expected
30
83
  function isDevConfigFile(filePath: string): boolean {
31
84
  const devConfigPatterns = [
@@ -44,6 +97,37 @@ function isDevConfigFile(filePath: string): boolean {
44
97
  return devConfigPatterns.some(p => p.test(filePath))
45
98
  }
46
99
 
100
+ // Check if file is a locale/i18n file where URLs are example placeholders
101
+ function isLocaleFile(filePath: string): boolean {
102
+ const localePatterns = [
103
+ /\/locales?\//i, // /locale/ or /locales/
104
+ /\/i18n\//i, // /i18n/
105
+ /\/translations?\//i, // /translation/ or /translations/
106
+ /\/lang\//i, // /lang/
107
+ /\/languages?\//i, // /language/ or /languages/
108
+ /\.\w{2}(-\w{2})?\.json$/i, // .en.json, .zh-CN.json, etc.
109
+ ]
110
+ return localePatterns.some(p => p.test(filePath))
111
+ }
112
+
113
+ // Check if line contains URL placeholder/example text
114
+ function isUrlPlaceholderText(line: string): boolean {
115
+ const placeholderPatterns = [
116
+ /placeholder['"]\s*:/i, // "placeholder": "http://..."
117
+ /example['"]\s*:/i, // "example": "http://..."
118
+ /e\.g\./i, // e.g. http://localhost
119
+ /for\s+example/i, // for example http://...
120
+ /such\s+as/i, // such as http://localhost
121
+ /like\s+http/i, // like http://localhost
122
+ /格式.*http/i, // Chinese: format http://...
123
+ /例如.*http/i, // Chinese: for example http://...
124
+ /beispiel.*http/i, // German: example http://...
125
+ /ejemplo.*http/i, // Spanish: example http://...
126
+ /exemple.*http/i, // French: example http://...
127
+ ]
128
+ return placeholderPatterns.some(p => p.test(line))
129
+ }
130
+
47
131
  // URL patterns that may indicate security issues
48
132
  const URL_PATTERNS = [
49
133
  // Internal/staging endpoints in production code
@@ -84,18 +168,20 @@ const URL_PATTERNS = [
84
168
  description: 'Hardcoded test environment URL found',
85
169
  },
86
170
 
87
- // Admin/sensitive endpoints - downgraded to info (these are often intentional)
171
+ // Admin/sensitive endpoints - heavily downgraded
172
+ // In most modern frameworks, these are protected by middleware or layout auth
173
+ // Flagging them creates noise when they're inside authenticated route groups
88
174
  {
89
175
  pattern: /['"`]\/admin(?:\/|['"`])/gi,
90
176
  name: 'Admin Endpoint',
91
177
  severity: 'info' as const,
92
- description: 'Admin endpoint path found - verify access control',
178
+ description: 'Admin endpoint path found - typically protected by auth middleware',
93
179
  },
94
180
  {
95
181
  pattern: /['"`]\/api\/admin/gi,
96
182
  name: 'Admin API Endpoint',
97
- severity: 'low' as const, // Downgraded from medium
98
- description: 'Admin API endpoint found - verify access control',
183
+ severity: 'info' as const, // Downgraded from low - usually behind middleware
184
+ description: 'Admin API endpoint found - typically protected by auth middleware',
99
185
  },
100
186
 
101
187
  // API keys in URLs
@@ -178,6 +264,33 @@ function isEnvVarReference(lineContent: string): boolean {
178
264
  lineContent.includes('import.meta.env')
179
265
  }
180
266
 
267
+ /**
268
+ * Check if localhost URL is used as a fallback default value
269
+ * This is a common safe pattern in development:
270
+ * - process.env.API_URL || 'http://localhost:3000'
271
+ * - baseUrl ?? 'http://localhost:3000'
272
+ * - config.url || 'http://localhost'
273
+ * - config?.url ?? 'http://localhost'
274
+ */
275
+ function isLocalhostFallback(lineContent: string): boolean {
276
+ const fallbackPatterns = [
277
+ // Logical OR fallback: something || 'http://localhost...'
278
+ /\|\|\s*['"`]https?:\/\/(localhost|127\.0\.0\.1)/i,
279
+ // Nullish coalescing fallback: something ?? 'http://localhost...'
280
+ /\?\?\s*['"`]https?:\/\/(localhost|127\.0\.0\.1)/i,
281
+ // Default parameter: = 'http://localhost...'
282
+ /=\s*['"`]https?:\/\/(localhost|127\.0\.0\.1)[^'"]*['"`]\s*(,|\)|$)/i,
283
+ // Ternary with env check: process.env.X ? ... : 'http://localhost'
284
+ /process\.env\.\w+\s*\?\s*[^:]+\s*:\s*['"`]https?:\/\/(localhost|127\.0\.0\.1)/i,
285
+ // Object property default: url: process.env.X || 'http://localhost'
286
+ /:\s*process\.env\.\w+\s*\|\|\s*['"`]https?:\/\/(localhost|127\.0\.0\.1)/i,
287
+ // Import.meta.env fallback
288
+ /import\.meta\.env\.\w+\s*\|\|\s*['"`]https?:\/\/(localhost|127\.0\.0\.1)/i,
289
+ /import\.meta\.env\.\w+\s*\?\?\s*['"`]https?:\/\/(localhost|127\.0\.0\.1)/i,
290
+ ]
291
+ return fallbackPatterns.some(p => p.test(lineContent))
292
+ }
293
+
181
294
  // Get URL context for smarter detection
182
295
  function getURLContext(lineContent: string, filePath: string): {
183
296
  isDevOnly: boolean
@@ -240,7 +353,8 @@ export function aggregateLocalhostFindings(
240
353
 
241
354
  export function detectSensitiveURLs(
242
355
  content: string,
243
- filePath: string
356
+ filePath: string,
357
+ options?: { parsed?: ParsedFile }
244
358
  ): Vulnerability[] {
245
359
  const vulnerabilities: Vulnerability[] = []
246
360
 
@@ -249,9 +363,18 @@ export function detectSensitiveURLs(
249
363
  return vulnerabilities
250
364
  }
251
365
 
252
- const lines = content.split('\n')
366
+ // Get environment context for smart handling
367
+ const envContext = getEnvironmentContext(filePath)
368
+
369
+ // Get route protection context
370
+ const routeHierarchy = getRouteProtectionContext(filePath)
371
+
372
+ const lines = options?.parsed?.lines ?? content.split('\n')
253
373
  const inTestFile = isTestFile(filePath)
254
374
  const inDevConfig = isDevConfigFile(filePath)
375
+ const inTestConfig = isTestConfigFile(filePath)
376
+ const isPython = isPythonFile(filePath)
377
+ const inAuthRoute = isInsideAuthenticatedRouteGroup(filePath) || routeHierarchy.isInProtectedHierarchy
255
378
 
256
379
  for (let i = 0; i < lines.length; i++) {
257
380
  const line = lines[i]
@@ -259,6 +382,11 @@ export function detectSensitiveURLs(
259
382
  // Skip comments
260
383
  if (isComment(line)) continue
261
384
 
385
+ // Skip Python docstrings - they often contain example URLs
386
+ if (isPython && isInsidePythonDocstring(lines, i)) {
387
+ continue
388
+ }
389
+
262
390
  // Get context for this line
263
391
  const context = getURLContext(line, filePath)
264
392
 
@@ -275,14 +403,50 @@ export function detectSensitiveURLs(
275
403
 
276
404
  // Special handling for localhost URLs
277
405
  if (/localhost|127\.0\.0\.1/i.test(url)) {
278
- // Skip localhost in test files, dev-only contexts, or dev config files
279
- if (context.isTestFile || context.isDevOnly || inDevConfig) {
406
+ // Skip localhost as fallback/default values - this is standard practice
407
+ // e.g., process.env.API_URL || 'http://localhost:3000'
408
+ if (isLocalhostFallback(line)) {
409
+ continue
410
+ }
411
+
412
+ // Use environment context for smarter handling
413
+ // Skip localhost in environments where it's expected (templates, tests, tooling)
414
+ if (envContext.allowsLocalhostDefaults) {
415
+ continue
416
+ }
417
+
418
+ // Skip localhost in test files, dev-only contexts, test config files, or dev config files
419
+ if (context.isTestFile || context.isDevOnly || inDevConfig || inTestConfig) {
420
+ continue
421
+ }
422
+
423
+ // Skip localhost in placeholder attributes (placeholder="https://localhost...")
424
+ if (isInPlaceholderAttribute(line)) {
280
425
  continue
281
426
  }
282
427
 
283
- // Only flag localhost in production env files as high, otherwise info
284
- const isProduction = filePath.includes('.env.production')
285
- const adjustedSeverity = isProduction ? 'high' as const : 'info' as const
428
+ // Skip localhost when used as default parameter value
429
+ if (isDefaultParameterValue(line)) {
430
+ continue
431
+ }
432
+
433
+ // Skip localhost in locale/i18n files - these are example placeholders for users
434
+ if (isLocaleFile(filePath)) {
435
+ continue
436
+ }
437
+
438
+ // Skip localhost in placeholder/example text (e.g., "e.g. http://localhost")
439
+ if (isUrlPlaceholderText(line)) {
440
+ continue
441
+ }
442
+
443
+ // Use smart severity determination based on context
444
+ const adjustedSeverity = getLocalhostSeverity(filePath, line)
445
+
446
+ // Skip info-level findings in non-production contexts
447
+ if (adjustedSeverity === 'info' && !filePath.includes('.env.production')) {
448
+ continue
449
+ }
286
450
 
287
451
  vulnerabilities.push({
288
452
  id: `url-${filePath}-${i + 1}-${name}`,
@@ -292,19 +456,29 @@ export function detectSensitiveURLs(
292
456
  severity: adjustedSeverity,
293
457
  category: 'sensitive_url',
294
458
  title: name,
295
- description: description + (isProduction ? ' (in production config!)' : ' (in dev/config file)'),
459
+ description: description + (adjustedSeverity === 'high' ? ' (in production config!)' : ' (in dev/config file)'),
296
460
  suggestedFix: 'Move URLs to environment variables or configuration files. Use process.env.API_URL pattern.',
297
- confidence: isProduction ? 'high' : 'low',
461
+ confidence: adjustedSeverity === 'high' ? 'high' : 'low',
298
462
  layer: 1,
299
463
  })
300
464
  } else {
301
465
  // Normal URL handling (non-localhost)
302
466
  // Lower severity for test files - downgrade more aggressively
303
467
  let adjustedSeverity = severity
468
+ let contextNote = ''
469
+
304
470
  if (inTestFile) {
305
471
  if (severity === 'critical') adjustedSeverity = 'high'
306
472
  else if (severity === 'high') adjustedSeverity = 'low'
307
473
  else adjustedSeverity = 'info'
474
+ contextNote = ' (in test file)'
475
+ }
476
+
477
+ // Downgrade admin/sensitive endpoint findings inside authenticated route groups
478
+ // These routes are already protected by layout/middleware auth
479
+ if (inAuthRoute && (name === 'Admin Endpoint' || name === 'Admin API Endpoint')) {
480
+ adjustedSeverity = 'info'
481
+ contextNote = ' (inside authenticated route group)'
308
482
  }
309
483
 
310
484
  // Non-critical URL findings require AI validation
@@ -318,7 +492,7 @@ export function detectSensitiveURLs(
318
492
  severity: adjustedSeverity,
319
493
  category: 'sensitive_url',
320
494
  title: name,
321
- description: description + (inTestFile ? ' (in test file)' : ''),
495
+ description: description + contextNote,
322
496
  suggestedFix: 'Move URLs to environment variables or configuration files. Use process.env.API_URL pattern.',
323
497
  confidence: inTestFile ? 'low' : 'medium',
324
498
  layer: 1,
@@ -4,6 +4,7 @@
4
4
  */
5
5
 
6
6
  import type { Vulnerability } from '../types'
7
+ import type { ParsedFile } from '../utils/parsed-file'
7
8
 
8
9
  // Weak/deprecated cryptographic patterns
9
10
  const WEAK_CRYPTO_PATTERNS = [
@@ -16,13 +17,34 @@ const WEAK_CRYPTO_PATTERNS = [
16
17
  fix: 'Use SHA-256 or SHA-3 for hashing. For passwords, use bcrypt, scrypt, or Argon2.',
17
18
  contextCheck: (line: string) => {
18
19
  // Only flag as high if used in security context (passwords, tokens, etc.)
19
- // Checksum/etag usage is acceptable for non-security purposes
20
- const securityContexts = [/password/i, /token/i, /secret/i, /credential/i, /auth/i, /session/i, /key/i]
21
- const checksumContexts = [/checksum/i, /hash.*file/i, /file.*hash/i, /etag/i, /content.*hash/i, /integrity/i, /digest/i, /fingerprint/i]
22
-
20
+ // Checksum/etag/cache usage is acceptable for non-security purposes
21
+ const securityContexts = [/password/i, /token/i, /secret/i, /credential/i, /auth/i, /session/i, /key/i, /verify.*user/i, /sign/i]
22
+ const checksumContexts = [
23
+ /checksum/i,
24
+ /hash.*file/i,
25
+ /file.*hash/i,
26
+ /etag/i,
27
+ /content.*hash/i,
28
+ /integrity/i,
29
+ /digest/i,
30
+ /fingerprint/i,
31
+ /cache.*key/i,
32
+ /dedup/i,
33
+ /uniqueId/i,
34
+ /contentId/i,
35
+ /gravatar/i, // Gravatar uses MD5 for email hashing
36
+ /avatar/i, // Avatar URLs often use MD5
37
+ /blob/i, // Blob hashing
38
+ /asset/i, // Asset fingerprinting
39
+ /sprite/i, // Sprite sheet hashing
40
+ /bundle/i, // Bundle hashing
41
+ /chunk/i, // Webpack chunk hashing
42
+ /manifest/i, // Manifest hashing
43
+ ]
44
+
23
45
  const isSecurityContext = securityContexts.some(p => p.test(line))
24
46
  const isChecksumContext = checksumContexts.some(p => p.test(line))
25
-
47
+
26
48
  // If it's clearly a checksum context, don't flag
27
49
  if (isChecksumContext && !isSecurityContext) {
28
50
  return false
@@ -38,14 +60,32 @@ const WEAK_CRYPTO_PATTERNS = [
38
60
  fix: 'Use createHash(\'sha256\') or createHash(\'sha3-256\') instead.',
39
61
  contextCheck: (line: string, _match: RegExpMatchArray, funcName?: string) => {
40
62
  // Check function name and line context for checksum indicators
41
- const checksumIndicators = [/checksum/i, /etag/i, /content.*hash/i, /file.*hash/i, /integrity/i, /digest/i, /fingerprint/i, /verify.*file/i]
42
- const securityIndicators = [/password/i, /token/i, /secret/i, /credential/i, /auth/i, /session/i]
43
-
63
+ const checksumIndicators = [
64
+ /checksum/i,
65
+ /etag/i,
66
+ /content.*hash/i,
67
+ /file.*hash/i,
68
+ /integrity/i,
69
+ /digest/i,
70
+ /fingerprint/i,
71
+ /verify.*file/i,
72
+ /cache/i,
73
+ /dedup/i,
74
+ /gravatar/i,
75
+ /avatar/i,
76
+ /asset/i,
77
+ /bundle/i,
78
+ /chunk/i,
79
+ /manifest/i,
80
+ /sprite/i,
81
+ ]
82
+ const securityIndicators = [/password/i, /token/i, /secret/i, /credential/i, /auth/i, /session/i, /verify.*user/i, /sign/i]
83
+
44
84
  const lineAndFunc = funcName ? `${funcName} ${line}` : line
45
-
85
+
46
86
  const isChecksum = checksumIndicators.some(p => p.test(lineAndFunc))
47
87
  const isSecurity = securityIndicators.some(p => p.test(lineAndFunc))
48
-
88
+
49
89
  // Checksum use without security context = acceptable, don't flag
50
90
  if (isChecksum && !isSecurity) {
51
91
  return false
@@ -75,6 +115,23 @@ const WEAK_CRYPTO_PATTERNS = [
75
115
  severity: 'high' as const,
76
116
  description: 'DES is obsolete and easily broken. Use AES instead.',
77
117
  fix: 'Use AES-256-GCM for symmetric encryption.',
118
+ contextCheck: (line: string) => {
119
+ // DES must appear in crypto-related context, not natural language
120
+ // Common French/Spanish word "des" should not trigger this
121
+ const cryptoContexts = [
122
+ /cipher/i,
123
+ /encrypt/i,
124
+ /decrypt/i,
125
+ /crypto/i,
126
+ /algorithm/i,
127
+ /createCipher/i,
128
+ /\bDES\s*[.(]/i, // DES function call like DES() or DES.encrypt()
129
+ /['"]DES['"]/i, // DES as string literal
130
+ /DES[-_]/i, // DES-CBC, DES_KEY, etc.
131
+ /[-_]DES/i, // 3DES, etc.
132
+ ]
133
+ return cryptoContexts.some(ctx => ctx.test(line))
134
+ },
78
135
  },
79
136
  {
80
137
  pattern: /createCipher(?:iv)?\s*\(\s*['"]des['"]/gi,
@@ -113,6 +170,39 @@ const WEAK_CRYPTO_PATTERNS = [
113
170
  description: 'Math.random() is not cryptographically secure and should not be used for security purposes',
114
171
  fix: 'Use crypto.randomBytes() or crypto.getRandomValues() for cryptographic operations.',
115
172
  contextCheck: (line: string) => {
173
+ // Exclude load balancing/array selection patterns (not security-critical)
174
+ // Pattern: Math.random() * array.length or Math.random() * count
175
+ const loadBalancingPatterns = [
176
+ /Math\.random\s*\(\s*\)\s*\*\s*\w+\.length/i, // * array.length
177
+ /Math\.random\s*\(\s*\)\s*\*\s*\w+\.keyLen/i, // * store.keyLen (API key manager)
178
+ /Math\.random\s*\(\s*\)\s*\*\s*\w+\.size/i, // * collection.size
179
+ /Math\.random\s*\(\s*\)\s*\*\s*\d+\s*\)/, // * literal number in expression
180
+ /Math\.floor\s*\(\s*Math\.random\s*\(\s*\)\s*\*\s*\w+\.length/i, // Math.floor(Math.random() * arr.length)
181
+ /Math\.floor\s*\(\s*Math\.random\s*\(\s*\)\s*\*\s*\w+\.keyLen/i, // Math.floor(Math.random() * store.keyLen)
182
+ /\[\s*Math\.floor\s*\(\s*Math\.random/i, // array[Math.floor(Math.random...)]
183
+ /index\s*=\s*Math\.floor\s*\(\s*Math\.random/i, // index = Math.floor(Math.random...)
184
+ /pick|select|choose|shuffle|sample/i, // Load balancing keywords
185
+ ]
186
+
187
+ if (loadBalancingPatterns.some(p => p.test(line))) {
188
+ return false // Don't flag - this is load balancing, not security
189
+ }
190
+
191
+ // Exclude fallback patterns where crypto is the primary method
192
+ // Pattern: crypto.randomUUID() ?? Math.random() or crypto.getRandomValues() || Math.random()
193
+ const fallbackPatterns = [
194
+ /crypto\??\.\s*randomUUID\s*\(\s*\)\s*\?\?/i, // crypto.randomUUID() ??
195
+ /crypto\??\.\s*getRandomValues\s*\([^)]*\)\s*\?\?/i, // crypto.getRandomValues() ??
196
+ /globalThis\.crypto\??\.\s*randomUUID/i, // globalThis.crypto.randomUUID
197
+ /window\.crypto\??\.\s*randomUUID/i, // window.crypto.randomUUID
198
+ /\?\.\s*randomUUID\s*\(\s*\)\s*\?\?/i, // ?.randomUUID() ??
199
+ /randomUUID\s*\(\s*\)\s*\?\?.*Math\.random/i, // randomUUID() ?? ...Math.random
200
+ ]
201
+
202
+ if (fallbackPatterns.some(p => p.test(line))) {
203
+ return false // Don't flag - Math.random is only a fallback for missing crypto API
204
+ }
205
+
116
206
  // Only flag if it looks like it's being used for security
117
207
  const securityContexts = [
118
208
  /token/i, /secret/i, /key/i, /password/i, /salt/i,
@@ -196,6 +286,20 @@ function isComment(lineContent: string): boolean {
196
286
  )
197
287
  }
198
288
 
289
+ // Check if this is a Python file
290
+ function isPythonFile(filePath: string): boolean {
291
+ return /\.py$/i.test(filePath)
292
+ }
293
+
294
+ /**
295
+ * Check if Python's usedforsecurity=False flag is present
296
+ * Python 3.9+ allows explicitly marking hash usage as non-security
297
+ * Example: hashlib.md5(data, usedforsecurity=False)
298
+ */
299
+ function hasUsedForSecurityFalse(line: string): boolean {
300
+ return /usedforsecurity\s*=\s*False/i.test(line)
301
+ }
302
+
199
303
  // Check if line is a pattern definition (regex or string literal in detector code)
200
304
  function isPatternDefinition(lineContent: string): boolean {
201
305
  const trimmed = lineContent.trim()
@@ -244,6 +348,22 @@ function isTestOrFixtureFile(filePath: string): boolean {
244
348
  )
245
349
  }
246
350
 
351
+ // Check if file is a locale/translation file
352
+ function isLocaleFile(filePath: string): boolean {
353
+ const lowerPath = filePath.toLowerCase()
354
+ return (
355
+ lowerPath.includes('/locales/') ||
356
+ lowerPath.includes('/locale/') ||
357
+ lowerPath.includes('/translations/') ||
358
+ lowerPath.includes('/i18n/') ||
359
+ lowerPath.includes('/lang/') ||
360
+ lowerPath.includes('/languages/') ||
361
+ // Common locale file patterns
362
+ /\/(en|fr|de|es|it|pt|ja|ko|zh|ru|ar|nl|pl|tr|vi|th|id|ms|fil|hi|bn|ta|te|ml|kn|gu|mr|pa|ur|sw|am|or|si|ne|km|my|lo|ka|mk|sr|hr|sl|sk|cs|hu|ro|bg|uk|el|he|fa|ps|ku|ug|yi|mn|bo|dz|dv)[-_][a-z]{2,}\.json$/i.test(lowerPath) ||
363
+ /locale.*\.json$/i.test(lowerPath)
364
+ )
365
+ }
366
+
247
367
  /**
248
368
  * Find the enclosing function name for a given line
249
369
  */
@@ -267,10 +387,11 @@ function findEnclosingFunctionName(lines: string[], lineIndex: number): string |
267
387
 
268
388
  export function detectWeakCrypto(
269
389
  content: string,
270
- filePath: string
390
+ filePath: string,
391
+ options?: { parsed?: ParsedFile }
271
392
  ): Vulnerability[] {
272
393
  const vulnerabilities: Vulnerability[] = []
273
- const lines = content.split('\n')
394
+ const lines = options?.parsed?.lines ?? content.split('\n')
274
395
 
275
396
  // Skip scanner's own detector files to avoid self-detection
276
397
  if (isScannerDetectorFile(filePath)) {
@@ -282,23 +403,54 @@ export function detectWeakCrypto(
282
403
  return vulnerabilities
283
404
  }
284
405
 
406
+ // Skip locale/translation files (natural language text, not crypto code)
407
+ if (isLocaleFile(filePath)) {
408
+ return vulnerabilities
409
+ }
410
+
411
+ const isPython = isPythonFile(filePath)
412
+
285
413
  for (let i = 0; i < lines.length; i++) {
286
414
  const line = lines[i]
287
-
415
+
288
416
  // Skip comments
289
417
  if (isComment(line)) continue
290
-
418
+
291
419
  // Skip pattern definitions (detector rule definitions)
292
420
  if (isPatternDefinition(line)) continue
293
421
 
422
+ // Skip Python code with usedforsecurity=False flag
423
+ // Python 3.9+ allows explicitly marking non-security hash usage
424
+ if (isPython && hasUsedForSecurityFalse(line)) {
425
+ continue
426
+ }
427
+
294
428
  for (const cryptoPattern of WEAK_CRYPTO_PATTERNS) {
295
429
  const { pattern, name, severity, description, fix, contextCheck } = cryptoPattern
296
-
430
+
297
431
  // Reset regex state
298
432
  const regex = new RegExp(pattern.source, pattern.flags)
299
433
  const match = regex.exec(line)
300
-
434
+
301
435
  if (match) {
436
+ // Special handling for Math.random - check multi-line fallback patterns
437
+ if (name === 'Math.random() for Security') {
438
+ // Check previous 2 lines for crypto.randomUUID fallback pattern
439
+ // Pattern: crypto?.randomUUID?.() ?? `...${Math.random()}...`
440
+ const prevLines = lines.slice(Math.max(0, i - 2), i + 1).join(' ')
441
+ const multiLineFallbackPatterns = [
442
+ /crypto\??\.?\s*randomUUID\??\s*\(\s*\)\s*\?\?/i, // crypto.randomUUID() ??
443
+ /globalThis\.crypto\??\.?\s*randomUUID\??\.?\s*\(/i, // globalThis.crypto?.randomUUID?.()
444
+ /window\.crypto\??\.?\s*randomUUID\??\.?\s*\(/i, // window.crypto?.randomUUID?.()
445
+ /\?\.\s*randomUUID\??\.?\s*\(\s*\)\s*\?\?/i, // ?.randomUUID?.() ??
446
+ /crypto\??\.?\s*getRandomValues\s*\(/i, // crypto.getRandomValues()
447
+ /randomUUID\??\.?\s*\(\s*\)\s*\?\?/i, // randomUUID?.() ?? (generic)
448
+ ]
449
+ if (multiLineFallbackPatterns.some(p => p.test(prevLines))) {
450
+ continue // Skip - Math.random is only a fallback for missing crypto API
451
+ }
452
+ }
453
+
302
454
  // If there's a context check, apply it
303
455
  // Pass function name for additional context
304
456
  const funcName = findEnclosingFunctionName(lines, i)