@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,531 @@
1
+ /**
2
+ * Layer 2: Model Supply Chain Security Detection
3
+ * Detects unsafe model loading patterns that can lead to arbitrary code execution
4
+ *
5
+ * Covers AI Detection Roadmap Phase 2:
6
+ * - Pickle/joblib deserialization RCE
7
+ * - torch.load without weights_only=True
8
+ * - Unverified model sources
9
+ * - Unsafe fine-tuning on user data
10
+ *
11
+ * References:
12
+ * - OWASP LLM05: Supply Chain Vulnerabilities
13
+ * - CWE-502: Deserialization of Untrusted Data
14
+ */
15
+
16
+ import type { Vulnerability, VulnerabilitySeverity, VulnerabilityCategory } from '../types'
17
+ import type { ParsedFile } from '../utils/parsed-file'
18
+ import {
19
+ isComment,
20
+ isTestOrMockFile,
21
+ isScannerOrFixtureFile,
22
+ isExampleDirectory,
23
+ isLibraryCode,
24
+ } from '../utils/context-helpers'
25
+
26
+ // ============================================================================
27
+ // Context Detection
28
+ // ============================================================================
29
+
30
+ /**
31
+ * Check if file is in an ML/model context based on path and content
32
+ */
33
+ function isMLContextFile(filePath: string, content: string): boolean {
34
+ // File path indicators
35
+ const mlPathPatterns = [
36
+ /\/(models?|ml|training|inference|weights|checkpoints)\//i,
37
+ /\/(transformers|huggingface|pytorch|tensorflow|keras)\//i,
38
+ /(train|model|inference|fine[-_]?tune).*\.(py|ts|js)$/i,
39
+ ]
40
+
41
+ if (mlPathPatterns.some(p => p.test(filePath))) {
42
+ return true
43
+ }
44
+
45
+ // Content patterns suggesting ML usage
46
+ const mlContentPatterns = [
47
+ /import\s+(?:torch|tensorflow|keras|transformers|joblib|pickle|dill|cloudpickle|onnx)/i,
48
+ /from\s+(?:torch|tensorflow|keras|transformers|joblib|pickle|dill|cloudpickle|onnx)\s+import/i,
49
+ /\.load_model\s*\(/i,
50
+ /\.from_pretrained\s*\(/i,
51
+ /torch\.load\s*\(/i,
52
+ /torch\.jit\.load\s*\(/i,
53
+ /pickle\.load/i,
54
+ /joblib\.load/i,
55
+ /dill\.load/i,
56
+ /cloudpickle\.load/i,
57
+ /onnx\.load/i,
58
+ /numpy\.load.*allow_pickle/i,
59
+ /np\.load.*allow_pickle/i,
60
+ /yaml\.(?:unsafe_load|full_load|load)/i,
61
+ /Trainer|TrainingArguments/i,
62
+ /model\.save|model\.load/i,
63
+ ]
64
+
65
+ return mlContentPatterns.some(p => p.test(content))
66
+ }
67
+
68
+ // ============================================================================
69
+ // Safe Pattern Detection
70
+ // ============================================================================
71
+
72
+ /**
73
+ * Check if torch.load has weights_only=True (safe mode)
74
+ */
75
+ function hasTorchWeightsOnly(lineContent: string, surroundingContext: string): boolean {
76
+ const fullContext = lineContent + '\n' + surroundingContext
77
+ return /weights_only\s*=\s*True/i.test(fullContext)
78
+ }
79
+
80
+ /**
81
+ * Check if TensorFlow/Keras load has safe_mode=True
82
+ */
83
+ function hasKerasSafeMode(lineContent: string, surroundingContext: string): boolean {
84
+ const fullContext = lineContent + '\n' + surroundingContext
85
+ return /safe_mode\s*=\s*True/i.test(fullContext)
86
+ }
87
+
88
+ /**
89
+ * Check if model source is from a trusted provider
90
+ */
91
+ function isTrustedModelSource(lineContent: string): boolean {
92
+ const trustedPatterns = [
93
+ // Official Hugging Face repos
94
+ /huggingface\.co\/(meta-llama|openai|anthropic|google|microsoft|facebook|EleutherAI)/i,
95
+ // Specific trusted model IDs (no http prefix)
96
+ /['"`](meta-llama|openai|anthropic|google|microsoft|facebook)\//i,
97
+ // Local file paths (not URLs)
98
+ /['"`]\.\/|['"`]\.\.\/|['"`]\//,
99
+ // Environment variables for paths
100
+ /os\.environ|process\.env/i,
101
+ ]
102
+
103
+ return trustedPatterns.some(p => p.test(lineContent))
104
+ }
105
+
106
+ /**
107
+ * Check if integrity verification is present
108
+ */
109
+ function hasIntegrityCheck(content: string, lineNumber: number): boolean {
110
+ const lines = content.split('\n')
111
+ const contextStart = Math.max(0, lineNumber - 20)
112
+ const contextEnd = Math.min(lines.length, lineNumber + 10)
113
+ const context = lines.slice(contextStart, contextEnd).join('\n')
114
+
115
+ const integrityPatterns = [
116
+ /checksum|sha256|sha512|md5|verify_hash|hash_check/i,
117
+ /verify.*integrity|integrity.*verify/i,
118
+ /revision\s*=\s*['"`][a-f0-9]{40}/i, // Git SHA pinning
119
+ /safetensors/i, // SafeTensors format (safe by design)
120
+ /\.ckpt\.sha256|\.bin\.sha256/i, // Hash files
121
+ ]
122
+
123
+ return integrityPatterns.some(p => p.test(context))
124
+ }
125
+
126
+ /**
127
+ * Check if using SafeTensors format (safe by design)
128
+ */
129
+ function usesSafeTensors(lineContent: string, surroundingContext: string): boolean {
130
+ const fullContext = lineContent + '\n' + surroundingContext
131
+ return /safetensors|\.safetensors|from_safetensors|load_safetensors/i.test(fullContext)
132
+ }
133
+
134
+ /**
135
+ * Check if data validation is present for training
136
+ */
137
+ function hasDataValidation(content: string, lineNumber: number): boolean {
138
+ const lines = content.split('\n')
139
+ const contextStart = Math.max(0, lineNumber - 30)
140
+ const contextEnd = Math.min(lines.length, lineNumber + 10)
141
+ const context = lines.slice(contextStart, contextEnd).join('\n')
142
+
143
+ const validationPatterns = [
144
+ /validate|sanitize|clean|filter/i,
145
+ /schema\.(parse|validate)/i,
146
+ /content_moderation|moderate_content/i,
147
+ /review.*data|data.*review/i,
148
+ /verified.*dataset|trusted.*data/i,
149
+ ]
150
+
151
+ return validationPatterns.some(p => p.test(context))
152
+ }
153
+
154
+ // ============================================================================
155
+ // Pattern Definitions
156
+ // ============================================================================
157
+
158
+ interface ModelSupplyChainPattern {
159
+ name: string
160
+ pattern: RegExp
161
+ category: VulnerabilityCategory
162
+ baseSeverity: VulnerabilitySeverity
163
+ description: string
164
+ suggestedFix: string
165
+ checkSafeMode?: 'torch' | 'keras'
166
+ checkTrustedSource?: boolean
167
+ checkIntegrity?: boolean
168
+ checkDataValidation?: boolean
169
+ }
170
+
171
+ const MODEL_SUPPLY_CHAIN_PATTERNS: ModelSupplyChainPattern[] = [
172
+ // ========== Pickle Deserialization (RCE) ==========
173
+ {
174
+ name: 'Pickle deserialization',
175
+ pattern: /pickle\.load\s*\(|pickle\.loads\s*\(/gi,
176
+ category: 'ai_unsafe_model_load',
177
+ baseSeverity: 'critical',
178
+ description: 'pickle.load() executes arbitrary Python code embedded in pickle files. Attackers can craft malicious pickle files that execute code when loaded.',
179
+ suggestedFix: 'Use SafeTensors format for ML models. For other data, use JSON or a safe serialization format. If pickle is unavoidable, only load from trusted, verified sources.',
180
+ },
181
+ {
182
+ name: 'Joblib deserialization',
183
+ pattern: /joblib\.load\s*\(/gi,
184
+ category: 'ai_unsafe_model_load',
185
+ baseSeverity: 'critical',
186
+ description: 'joblib.load() uses pickle internally and can execute arbitrary code. This is commonly used for sklearn models but is unsafe for untrusted files.',
187
+ suggestedFix: 'Use ONNX format for sklearn models. Alternatively, use skops.io which provides secure model persistence. Only load from verified sources.',
188
+ },
189
+
190
+ // ========== Extended Pickle Variants (RCE) ==========
191
+ {
192
+ name: 'Dill deserialization',
193
+ pattern: /\bdill\.(load|loads|load_session)\s*\(/gi,
194
+ category: 'ai_unsafe_model_load',
195
+ baseSeverity: 'critical',
196
+ description: 'dill can execute arbitrary code during deserialization, similar to pickle but with extended capabilities including serializing lambdas and closures.',
197
+ suggestedFix: 'Use SafeTensors format or JSON serialization instead of dill. If dill is unavoidable, only load from trusted, verified sources.',
198
+ },
199
+ {
200
+ name: 'Cloudpickle deserialization',
201
+ pattern: /\bcloudpickle\.(load|loads)\s*\(/gi,
202
+ category: 'ai_unsafe_model_load',
203
+ baseSeverity: 'critical',
204
+ description: 'cloudpickle can serialize and execute arbitrary functions, enabling remote code execution during deserialization.',
205
+ suggestedFix: 'Use SafeTensors format or explicitly define functions instead of deserializing them. Avoid cloudpickle for untrusted data.',
206
+ },
207
+
208
+ // ========== YAML Unsafe Loading (RCE) ==========
209
+ {
210
+ name: 'YAML unsafe deserialization',
211
+ pattern: /\byaml\.(unsafe_load|full_load|UnsafeLoader)\s*\(/gi,
212
+ category: 'ai_unsafe_model_load',
213
+ baseSeverity: 'critical',
214
+ description: 'yaml.unsafe_load() and yaml.full_load() can instantiate arbitrary Python objects, enabling remote code execution.',
215
+ suggestedFix: 'Use yaml.safe_load() instead of yaml.unsafe_load() or yaml.full_load(). SafeLoader only loads basic Python types.',
216
+ },
217
+ {
218
+ name: 'YAML load without explicit Loader',
219
+ pattern: /\byaml\.load\s*\(\s*[^,)]+\s*\)(?!\s*,)/gi,
220
+ category: 'ai_unsafe_model_load',
221
+ baseSeverity: 'medium',
222
+ description: 'yaml.load() without explicit Loader argument may use unsafe loading in older PyYAML versions (< 5.1).',
223
+ suggestedFix: 'Use yaml.safe_load() or explicitly specify Loader=yaml.SafeLoader: yaml.load(file, Loader=yaml.SafeLoader)',
224
+ },
225
+
226
+ // ========== NumPy Pickle Loading (RCE) ==========
227
+ {
228
+ name: 'NumPy pickle loading',
229
+ pattern: /\b(?:np|numpy)\.load\s*\([^)]*allow_pickle\s*=\s*True/gi,
230
+ category: 'ai_unsafe_model_load',
231
+ baseSeverity: 'high',
232
+ description: 'numpy.load() with allow_pickle=True can execute arbitrary code embedded in .npy/.npz files via pickle.',
233
+ suggestedFix: 'Use allow_pickle=False (default in numpy >= 1.16.3) or use SafeTensors format. Only allow_pickle from verified sources.',
234
+ },
235
+
236
+ // ========== TorchScript Loading (RCE) ==========
237
+ {
238
+ name: 'TorchScript model loading',
239
+ pattern: /\btorch\.jit\.load\s*\(/gi,
240
+ category: 'ai_unsafe_model_load',
241
+ baseSeverity: 'high',
242
+ description: 'torch.jit.load() can execute arbitrary code embedded in TorchScript models. TorchScript files can contain custom operators with native code.',
243
+ suggestedFix: 'Use SafeTensors format or verify model source and integrity before loading. Pin to specific model revisions with checksums.',
244
+ },
245
+
246
+ // ========== ONNX Model Loading (Code Execution Risk) ==========
247
+ {
248
+ name: 'ONNX model loading',
249
+ pattern: /\bonnx\.load\s*\(/gi,
250
+ category: 'ai_unsafe_model_load',
251
+ baseSeverity: 'medium',
252
+ description: 'ONNX models with custom operators can execute arbitrary code. Custom ops are loaded as shared libraries.',
253
+ suggestedFix: 'Verify ONNX model source and check for custom operators before loading. Use onnx.checker.check_model() and inspect custom ops.',
254
+ },
255
+
256
+ // ========== PyTorch Loading ==========
257
+ {
258
+ name: 'torch.load without weights_only',
259
+ pattern: /torch\.load\s*\([^)]*\)/gi,
260
+ category: 'ai_unsafe_model_load',
261
+ baseSeverity: 'high',
262
+ description: 'torch.load() without weights_only=True can execute arbitrary code embedded in model files via pickle.',
263
+ suggestedFix: 'Use torch.load(path, weights_only=True) to load only tensor data safely. Or use SafeTensors format: from safetensors.torch import load_file',
264
+ checkSafeMode: 'torch',
265
+ },
266
+
267
+ // ========== TensorFlow/Keras Loading ==========
268
+ {
269
+ name: 'Keras load_model without safe_mode',
270
+ pattern: /(?:keras\.models\.)?load_model\s*\([^)]*\)/gi,
271
+ category: 'ai_unsafe_model_load',
272
+ baseSeverity: 'high',
273
+ description: 'Keras load_model() can execute arbitrary code from Lambda layers or custom objects in model files.',
274
+ suggestedFix: 'Use tf.keras.models.load_model(path, safe_mode=True) in TensorFlow 2.13+. Alternatively, save/load only weights with model.save_weights()/load_weights().',
275
+ checkSafeMode: 'keras',
276
+ },
277
+
278
+ // ========== Unverified Model Sources ==========
279
+ {
280
+ name: 'Model from HTTP URL',
281
+ pattern: /from_pretrained\s*\(\s*['"`]https?:\/\/[^'"`)]+['"`]/gi,
282
+ category: 'ai_unverified_model',
283
+ baseSeverity: 'high',
284
+ description: 'Loading models directly from HTTP URLs bypasses the Hugging Face Hub\'s verification. Attackers could serve malicious models via MITM attacks.',
285
+ suggestedFix: 'Load from Hugging Face Hub by model ID instead of direct URL. Pin to specific revision: from_pretrained("org/model", revision="abc123")',
286
+ checkTrustedSource: true,
287
+ },
288
+ {
289
+ name: 'trust_remote_code=True',
290
+ pattern: /trust_remote_code\s*=\s*True/gi,
291
+ category: 'ai_unsafe_model_load',
292
+ baseSeverity: 'high',
293
+ description: 'trust_remote_code=True allows model repos to execute arbitrary Python code during loading. Malicious repos could compromise your system.',
294
+ suggestedFix: 'Avoid trust_remote_code=True. Use models that don\'t require custom code. If necessary, audit the model repo code before enabling.',
295
+ },
296
+ {
297
+ name: 'Model download without verification',
298
+ pattern: /(?:urllib|requests|wget|curl).*(?:\.pth|\.pt|\.bin|\.ckpt|\.h5|\.keras|model)/gi,
299
+ category: 'ai_unverified_model',
300
+ baseSeverity: 'medium',
301
+ description: 'Downloading model files without integrity verification. Attackers could serve modified files via compromised mirrors or MITM.',
302
+ suggestedFix: 'Verify downloaded files against known checksums: sha256sum file.pth. Use official download APIs (transformers, torch.hub) which include verification.',
303
+ checkIntegrity: true,
304
+ },
305
+
306
+ // ========== Unsafe Fine-tuning ==========
307
+ {
308
+ name: 'Training on user uploads',
309
+ pattern: /(?:trainer|model)\.(?:train|fit|fine_tune)\s*\([^)]*(?:user_uploads?|user_data|uploaded|untrusted)/gi,
310
+ category: 'ai_unsafe_finetuning',
311
+ baseSeverity: 'high',
312
+ description: 'Training/fine-tuning directly on user-uploaded data without validation enables data poisoning attacks.',
313
+ suggestedFix: 'Validate and sanitize all training data. Implement content moderation. Use separate data pipelines for user content with review steps.',
314
+ checkDataValidation: true,
315
+ },
316
+ {
317
+ name: 'Trainer with user data',
318
+ pattern: /Trainer\s*\([^)]*(?:train_dataset|eval_dataset)\s*=\s*(?:user_uploads?|user_data|uploaded_data|untrusted_data)/gi,
319
+ category: 'ai_unsafe_finetuning',
320
+ baseSeverity: 'high',
321
+ description: 'Trainer initialized with user-uploaded data without validation. Data poisoning attacks can manipulate model behavior.',
322
+ suggestedFix: 'Validate and sanitize all training data before passing to Trainer. Implement content moderation and review pipelines.',
323
+ checkDataValidation: true,
324
+ },
325
+ {
326
+ name: 'Fine-tuning with external dataset',
327
+ pattern: /(?:load_dataset|datasets\.load)\s*\([^)]*(?:path|url|http)/gi,
328
+ category: 'ai_unsafe_finetuning',
329
+ baseSeverity: 'medium',
330
+ description: 'Loading training datasets from external sources without verification. Data could be poisoned.',
331
+ suggestedFix: 'Use verified datasets from trusted sources. Implement data validation pipelines. Consider dataset hashing/signing.',
332
+ checkDataValidation: true,
333
+ },
334
+ {
335
+ name: 'Training config from user input',
336
+ pattern: /TrainingArguments\s*\([^)]*(?:request|user|input|body)\./gi,
337
+ category: 'ai_unsafe_finetuning',
338
+ baseSeverity: 'medium',
339
+ description: 'Training arguments derived from user input. Attackers could manipulate training hyperparameters to compromise model behavior.',
340
+ suggestedFix: 'Validate and sanitize all training arguments. Use allowlists for hyperparameter values. Don\'t allow users to specify output paths.',
341
+ },
342
+
343
+ // ========== TensorFlow Specific ==========
344
+ {
345
+ name: 'TensorFlow SavedModel from path',
346
+ pattern: /tf\.saved_model\.load\s*\([^)]*(?:http|ftp|user|upload)/gi,
347
+ category: 'ai_unverified_model',
348
+ baseSeverity: 'high',
349
+ description: 'Loading TensorFlow SavedModel from untrusted path. SavedModels can contain arbitrary ops that execute code.',
350
+ suggestedFix: 'Only load SavedModels from trusted, verified sources. Use TF Serving with model verification for production.',
351
+ checkTrustedSource: true,
352
+ },
353
+ ]
354
+
355
+ // ============================================================================
356
+ // Helper Functions
357
+ // ============================================================================
358
+
359
+ /**
360
+ * Get surrounding context for analysis
361
+ */
362
+ function getSurroundingContext(content: string, lineIndex: number, windowSize: number = 15): string {
363
+ const lines = content.split('\n')
364
+ const start = Math.max(0, lineIndex - windowSize)
365
+ const end = Math.min(lines.length, lineIndex + windowSize)
366
+ return lines.slice(start, end).join('\n')
367
+ }
368
+
369
+ /**
370
+ * Calculate severity based on mitigations
371
+ */
372
+ function calculateSeverity(
373
+ baseSeverity: VulnerabilitySeverity,
374
+ isMitigated: boolean,
375
+ isPartiallyMitigated: boolean,
376
+ isTestFile: boolean,
377
+ isExample: boolean,
378
+ isLibrary: boolean
379
+ ): VulnerabilitySeverity {
380
+ if (isTestFile || isExample || isLibrary) {
381
+ return 'info'
382
+ }
383
+
384
+ if (isMitigated) {
385
+ return 'info'
386
+ }
387
+
388
+ if (isPartiallyMitigated) {
389
+ if (baseSeverity === 'critical') return 'high'
390
+ if (baseSeverity === 'high') return 'medium'
391
+ if (baseSeverity === 'medium') return 'low'
392
+ }
393
+
394
+ return baseSeverity
395
+ }
396
+
397
+ // ============================================================================
398
+ // Main Detection Function
399
+ // ============================================================================
400
+
401
+ /**
402
+ * Main detection function for model supply chain security issues
403
+ */
404
+ export function detectModelSupplyChain(
405
+ content: string,
406
+ filePath: string,
407
+ options?: { parsed?: ParsedFile }
408
+ ): Vulnerability[] {
409
+ const vulnerabilities: Vulnerability[] = []
410
+
411
+ // Skip non-applicable files
412
+ if (isScannerOrFixtureFile(filePath)) return vulnerabilities
413
+
414
+ // Only scan files that appear to be in ML context
415
+ if (!isMLContextFile(filePath, content)) {
416
+ return vulnerabilities
417
+ }
418
+
419
+ const lines = options?.parsed?.lines ?? content.split('\n')
420
+ const isTestFile = isTestOrMockFile(filePath)
421
+ const isExample = isExampleDirectory(filePath)
422
+ const isLibrary = isLibraryCode(filePath)
423
+
424
+ for (const pattern of MODEL_SUPPLY_CHAIN_PATTERNS) {
425
+ const regex = new RegExp(pattern.pattern.source, pattern.pattern.flags)
426
+ let match
427
+
428
+ while ((match = regex.exec(content)) !== null) {
429
+ const lineNumber = content.substring(0, match.index).split('\n').length
430
+ const lineContent = lines[lineNumber - 1]?.trim() || ''
431
+
432
+ // Skip comments
433
+ if (isComment(lineContent)) continue
434
+
435
+ const surroundingContext = getSurroundingContext(content, lineNumber - 1)
436
+
437
+ // Check for mitigations
438
+ let isMitigated = false
439
+ let isPartiallyMitigated = false
440
+ let description = pattern.description
441
+
442
+ // Check SafeTensors usage (mitigates most pickle/torch issues)
443
+ if (usesSafeTensors(lineContent, surroundingContext)) {
444
+ isMitigated = true
445
+ description += ' (SafeTensors format detected - safe.)'
446
+ }
447
+
448
+ // Check torch weights_only
449
+ if (pattern.checkSafeMode === 'torch') {
450
+ if (hasTorchWeightsOnly(lineContent, surroundingContext)) {
451
+ isMitigated = true
452
+ description += ' (weights_only=True detected - safe.)'
453
+ }
454
+ }
455
+
456
+ // Check keras safe_mode
457
+ if (pattern.checkSafeMode === 'keras') {
458
+ if (hasKerasSafeMode(lineContent, surroundingContext)) {
459
+ isMitigated = true
460
+ description += ' (safe_mode=True detected - safe.)'
461
+ }
462
+ }
463
+
464
+ // Check trusted source
465
+ if (pattern.checkTrustedSource) {
466
+ if (isTrustedModelSource(lineContent)) {
467
+ isPartiallyMitigated = true
468
+ description += ' (Trusted source detected.)'
469
+ }
470
+ }
471
+
472
+ // Check integrity verification
473
+ if (pattern.checkIntegrity) {
474
+ if (hasIntegrityCheck(content, lineNumber)) {
475
+ isMitigated = true
476
+ description += ' (Integrity verification detected.)'
477
+ }
478
+ }
479
+
480
+ // Check data validation for training
481
+ if (pattern.checkDataValidation) {
482
+ if (hasDataValidation(content, lineNumber)) {
483
+ isPartiallyMitigated = true
484
+ description += ' (Data validation detected nearby.)'
485
+ }
486
+ }
487
+
488
+ // Skip if fully mitigated
489
+ if (isMitigated) continue
490
+
491
+ // Calculate final severity
492
+ const severity = calculateSeverity(
493
+ pattern.baseSeverity,
494
+ isMitigated,
495
+ isPartiallyMitigated,
496
+ isTestFile,
497
+ isExample,
498
+ isLibrary
499
+ )
500
+
501
+ // Add context notes
502
+ if (isTestFile) {
503
+ description += ' (In test file.)'
504
+ } else if (isExample) {
505
+ description += ' (In example/demo directory.)'
506
+ } else if (isLibrary) {
507
+ description += ' (Library code.)'
508
+ }
509
+
510
+ // Skip info-level in non-ML focused files to reduce noise
511
+ if (severity === 'info' && !isMLContextFile(filePath, content)) continue
512
+
513
+ vulnerabilities.push({
514
+ id: `model-supply-${filePath}-${lineNumber}-${pattern.name.replace(/\s+/g, '-')}`,
515
+ filePath,
516
+ lineNumber,
517
+ lineContent,
518
+ severity,
519
+ category: pattern.category,
520
+ title: pattern.name,
521
+ description,
522
+ suggestedFix: pattern.suggestedFix,
523
+ confidence: severity === 'info' ? 'low' : 'high',
524
+ layer: 2,
525
+ requiresAIValidation: severity !== 'info' && severity !== 'low',
526
+ })
527
+ }
528
+ }
529
+
530
+ return vulnerabilities
531
+ }
@@ -4,6 +4,8 @@
4
4
  */
5
5
 
6
6
  import type { Vulnerability, VulnerabilitySeverity } from '../types'
7
+ import type { ParsedFile } from '../utils/parsed-file'
8
+ import { isScannerOrFixtureFile } from '../utils/context-helpers'
7
9
 
8
10
  interface RiskyPackage {
9
11
  name: string
@@ -151,10 +153,15 @@ function isComment(line: string): boolean {
151
153
 
152
154
  export function detectRiskyImports(
153
155
  content: string,
154
- filePath: string
156
+ filePath: string,
157
+ options?: { parsed?: ParsedFile }
155
158
  ): Vulnerability[] {
156
159
  const vulnerabilities: Vulnerability[] = []
157
- const lines = content.split('\n')
160
+
161
+ // Skip scanner/fixture files to avoid self-detection
162
+ if (isScannerOrFixtureFile(filePath)) return vulnerabilities
163
+
164
+ const lines = options?.parsed?.lines ?? content.split('\n')
158
165
 
159
166
  lines.forEach((line, index) => {
160
167
  // Skip comment lines
@@ -4,6 +4,8 @@
4
4
  */
5
5
 
6
6
  import type { Vulnerability, SensitiveVariablePattern } from '../types'
7
+ import type { ParsedFile } from '../utils/parsed-file'
8
+ import { isScannerOrFixtureFile } from '../utils/context-helpers'
7
9
 
8
10
  // Patterns for sensitive variable names
9
11
  export const SENSITIVE_VARIABLE_PATTERNS: SensitiveVariablePattern[] = [
@@ -119,10 +121,15 @@ function isTypeDefinition(line: string): boolean {
119
121
 
120
122
  export function detectSensitiveVariables(
121
123
  content: string,
122
- filePath: string
124
+ filePath: string,
125
+ options?: { parsed?: ParsedFile }
123
126
  ): Vulnerability[] {
124
127
  const vulnerabilities: Vulnerability[] = []
125
- const lines = content.split('\n')
128
+
129
+ // Skip scanner/fixture files to avoid self-detection
130
+ if (isScannerOrFixtureFile(filePath)) return vulnerabilities
131
+
132
+ const lines = options?.parsed?.lines ?? content.split('\n')
126
133
 
127
134
  lines.forEach((line, index) => {
128
135
  // Skip comments