@oculum/scanner 1.0.9 → 1.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (365) hide show
  1. package/dist/baseline/diff.d.ts +32 -0
  2. package/dist/baseline/diff.d.ts.map +1 -0
  3. package/dist/baseline/diff.js +119 -0
  4. package/dist/baseline/diff.js.map +1 -0
  5. package/dist/baseline/index.d.ts +9 -0
  6. package/dist/baseline/index.d.ts.map +1 -0
  7. package/dist/baseline/index.js +19 -0
  8. package/dist/baseline/index.js.map +1 -0
  9. package/dist/baseline/manager.d.ts +67 -0
  10. package/dist/baseline/manager.d.ts.map +1 -0
  11. package/dist/baseline/manager.js +180 -0
  12. package/dist/baseline/manager.js.map +1 -0
  13. package/dist/baseline/types.d.ts +91 -0
  14. package/dist/baseline/types.d.ts.map +1 -0
  15. package/dist/baseline/types.js +12 -0
  16. package/dist/baseline/types.js.map +1 -0
  17. package/dist/formatters/cli-terminal.d.ts +38 -0
  18. package/dist/formatters/cli-terminal.d.ts.map +1 -1
  19. package/dist/formatters/cli-terminal.js +365 -42
  20. package/dist/formatters/cli-terminal.js.map +1 -1
  21. package/dist/formatters/github-comment.d.ts +1 -1
  22. package/dist/formatters/github-comment.d.ts.map +1 -1
  23. package/dist/formatters/github-comment.js +75 -11
  24. package/dist/formatters/github-comment.js.map +1 -1
  25. package/dist/formatters/index.d.ts +1 -1
  26. package/dist/formatters/index.d.ts.map +1 -1
  27. package/dist/formatters/index.js +4 -1
  28. package/dist/formatters/index.js.map +1 -1
  29. package/dist/index.d.ts +7 -0
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +155 -16
  32. package/dist/index.js.map +1 -1
  33. package/dist/layer1/config-audit.d.ts.map +1 -1
  34. package/dist/layer1/config-audit.js +20 -3
  35. package/dist/layer1/config-audit.js.map +1 -1
  36. package/dist/layer1/config-mcp-audit.d.ts +20 -0
  37. package/dist/layer1/config-mcp-audit.d.ts.map +1 -0
  38. package/dist/layer1/config-mcp-audit.js +239 -0
  39. package/dist/layer1/config-mcp-audit.js.map +1 -0
  40. package/dist/layer1/index.d.ts +1 -0
  41. package/dist/layer1/index.d.ts.map +1 -1
  42. package/dist/layer1/index.js +9 -1
  43. package/dist/layer1/index.js.map +1 -1
  44. package/dist/layer2/ai-agent-tools.d.ts.map +1 -1
  45. package/dist/layer2/ai-agent-tools.js +303 -0
  46. package/dist/layer2/ai-agent-tools.js.map +1 -1
  47. package/dist/layer2/ai-endpoint-protection.d.ts.map +1 -1
  48. package/dist/layer2/ai-endpoint-protection.js +17 -3
  49. package/dist/layer2/ai-endpoint-protection.js.map +1 -1
  50. package/dist/layer2/ai-execution-sinks.d.ts.map +1 -1
  51. package/dist/layer2/ai-execution-sinks.js +462 -12
  52. package/dist/layer2/ai-execution-sinks.js.map +1 -1
  53. package/dist/layer2/ai-fingerprinting.d.ts.map +1 -1
  54. package/dist/layer2/ai-fingerprinting.js +3 -0
  55. package/dist/layer2/ai-fingerprinting.js.map +1 -1
  56. package/dist/layer2/ai-mcp-security.d.ts +17 -0
  57. package/dist/layer2/ai-mcp-security.d.ts.map +1 -0
  58. package/dist/layer2/ai-mcp-security.js +679 -0
  59. package/dist/layer2/ai-mcp-security.js.map +1 -0
  60. package/dist/layer2/ai-package-hallucination.d.ts +19 -0
  61. package/dist/layer2/ai-package-hallucination.d.ts.map +1 -0
  62. package/dist/layer2/ai-package-hallucination.js +696 -0
  63. package/dist/layer2/ai-package-hallucination.js.map +1 -0
  64. package/dist/layer2/ai-prompt-hygiene.d.ts.map +1 -1
  65. package/dist/layer2/ai-prompt-hygiene.js +495 -9
  66. package/dist/layer2/ai-prompt-hygiene.js.map +1 -1
  67. package/dist/layer2/ai-rag-safety.d.ts.map +1 -1
  68. package/dist/layer2/ai-rag-safety.js +372 -1
  69. package/dist/layer2/ai-rag-safety.js.map +1 -1
  70. package/dist/layer2/auth-antipatterns.d.ts.map +1 -1
  71. package/dist/layer2/auth-antipatterns.js +4 -0
  72. package/dist/layer2/auth-antipatterns.js.map +1 -1
  73. package/dist/layer2/byok-patterns.d.ts.map +1 -1
  74. package/dist/layer2/byok-patterns.js +3 -0
  75. package/dist/layer2/byok-patterns.js.map +1 -1
  76. package/dist/layer2/dangerous-functions/child-process.d.ts +16 -0
  77. package/dist/layer2/dangerous-functions/child-process.d.ts.map +1 -0
  78. package/dist/layer2/dangerous-functions/child-process.js +74 -0
  79. package/dist/layer2/dangerous-functions/child-process.js.map +1 -0
  80. package/dist/layer2/dangerous-functions/dom-xss.d.ts +29 -0
  81. package/dist/layer2/dangerous-functions/dom-xss.d.ts.map +1 -0
  82. package/dist/layer2/dangerous-functions/dom-xss.js +179 -0
  83. package/dist/layer2/dangerous-functions/dom-xss.js.map +1 -0
  84. package/dist/layer2/dangerous-functions/index.d.ts +13 -0
  85. package/dist/layer2/dangerous-functions/index.d.ts.map +1 -0
  86. package/dist/layer2/dangerous-functions/index.js +621 -0
  87. package/dist/layer2/dangerous-functions/index.js.map +1 -0
  88. package/dist/layer2/dangerous-functions/json-parse.d.ts +31 -0
  89. package/dist/layer2/dangerous-functions/json-parse.d.ts.map +1 -0
  90. package/dist/layer2/dangerous-functions/json-parse.js +319 -0
  91. package/dist/layer2/dangerous-functions/json-parse.js.map +1 -0
  92. package/dist/layer2/dangerous-functions/math-random.d.ts +61 -0
  93. package/dist/layer2/dangerous-functions/math-random.d.ts.map +1 -0
  94. package/dist/layer2/dangerous-functions/math-random.js +459 -0
  95. package/dist/layer2/dangerous-functions/math-random.js.map +1 -0
  96. package/dist/layer2/dangerous-functions/patterns.d.ts +21 -0
  97. package/dist/layer2/dangerous-functions/patterns.d.ts.map +1 -0
  98. package/dist/layer2/dangerous-functions/patterns.js +161 -0
  99. package/dist/layer2/dangerous-functions/patterns.js.map +1 -0
  100. package/dist/layer2/dangerous-functions/request-validation.d.ts +13 -0
  101. package/dist/layer2/dangerous-functions/request-validation.d.ts.map +1 -0
  102. package/dist/layer2/dangerous-functions/request-validation.js +119 -0
  103. package/dist/layer2/dangerous-functions/request-validation.js.map +1 -0
  104. package/dist/layer2/dangerous-functions/utils/control-flow.d.ts +23 -0
  105. package/dist/layer2/dangerous-functions/utils/control-flow.d.ts.map +1 -0
  106. package/dist/layer2/dangerous-functions/utils/control-flow.js +149 -0
  107. package/dist/layer2/dangerous-functions/utils/control-flow.js.map +1 -0
  108. package/dist/layer2/dangerous-functions/utils/helpers.d.ts +31 -0
  109. package/dist/layer2/dangerous-functions/utils/helpers.d.ts.map +1 -0
  110. package/dist/layer2/dangerous-functions/utils/helpers.js +124 -0
  111. package/dist/layer2/dangerous-functions/utils/helpers.js.map +1 -0
  112. package/dist/layer2/dangerous-functions/utils/index.d.ts +9 -0
  113. package/dist/layer2/dangerous-functions/utils/index.d.ts.map +1 -0
  114. package/dist/layer2/dangerous-functions/utils/index.js +23 -0
  115. package/dist/layer2/dangerous-functions/utils/index.js.map +1 -0
  116. package/dist/layer2/dangerous-functions/utils/schema-validation.d.ts +22 -0
  117. package/dist/layer2/dangerous-functions/utils/schema-validation.d.ts.map +1 -0
  118. package/dist/layer2/dangerous-functions/utils/schema-validation.js +89 -0
  119. package/dist/layer2/dangerous-functions/utils/schema-validation.js.map +1 -0
  120. package/dist/layer2/data-exposure.d.ts.map +1 -1
  121. package/dist/layer2/data-exposure.js +3 -0
  122. package/dist/layer2/data-exposure.js.map +1 -1
  123. package/dist/layer2/framework-checks.d.ts.map +1 -1
  124. package/dist/layer2/framework-checks.js +3 -0
  125. package/dist/layer2/framework-checks.js.map +1 -1
  126. package/dist/layer2/index.d.ts +3 -0
  127. package/dist/layer2/index.d.ts.map +1 -1
  128. package/dist/layer2/index.js +61 -2
  129. package/dist/layer2/index.js.map +1 -1
  130. package/dist/layer2/logic-gates.d.ts.map +1 -1
  131. package/dist/layer2/logic-gates.js +4 -0
  132. package/dist/layer2/logic-gates.js.map +1 -1
  133. package/dist/layer2/model-supply-chain.d.ts +20 -0
  134. package/dist/layer2/model-supply-chain.d.ts.map +1 -0
  135. package/dist/layer2/model-supply-chain.js +376 -0
  136. package/dist/layer2/model-supply-chain.js.map +1 -0
  137. package/dist/layer2/risky-imports.d.ts.map +1 -1
  138. package/dist/layer2/risky-imports.js +4 -0
  139. package/dist/layer2/risky-imports.js.map +1 -1
  140. package/dist/layer2/variables.d.ts.map +1 -1
  141. package/dist/layer2/variables.js +4 -0
  142. package/dist/layer2/variables.js.map +1 -1
  143. package/dist/layer3/anthropic/auto-dismiss.d.ts +24 -0
  144. package/dist/layer3/anthropic/auto-dismiss.d.ts.map +1 -0
  145. package/dist/layer3/anthropic/auto-dismiss.js +188 -0
  146. package/dist/layer3/anthropic/auto-dismiss.js.map +1 -0
  147. package/dist/layer3/anthropic/clients.d.ts +44 -0
  148. package/dist/layer3/anthropic/clients.d.ts.map +1 -0
  149. package/dist/layer3/anthropic/clients.js +81 -0
  150. package/dist/layer3/anthropic/clients.js.map +1 -0
  151. package/dist/layer3/anthropic/index.d.ts +41 -0
  152. package/dist/layer3/anthropic/index.d.ts.map +1 -0
  153. package/dist/layer3/anthropic/index.js +141 -0
  154. package/dist/layer3/anthropic/index.js.map +1 -0
  155. package/dist/layer3/anthropic/prompts/index.d.ts +8 -0
  156. package/dist/layer3/anthropic/prompts/index.d.ts.map +1 -0
  157. package/dist/layer3/anthropic/prompts/index.js +14 -0
  158. package/dist/layer3/anthropic/prompts/index.js.map +1 -0
  159. package/dist/layer3/anthropic/prompts/semantic-analysis.d.ts +15 -0
  160. package/dist/layer3/anthropic/prompts/semantic-analysis.d.ts.map +1 -0
  161. package/dist/layer3/anthropic/prompts/semantic-analysis.js +169 -0
  162. package/dist/layer3/anthropic/prompts/semantic-analysis.js.map +1 -0
  163. package/dist/layer3/anthropic/prompts/validation.d.ts +12 -0
  164. package/dist/layer3/anthropic/prompts/validation.d.ts.map +1 -0
  165. package/dist/layer3/anthropic/prompts/validation.js +421 -0
  166. package/dist/layer3/anthropic/prompts/validation.js.map +1 -0
  167. package/dist/layer3/anthropic/providers/anthropic.d.ts +21 -0
  168. package/dist/layer3/anthropic/providers/anthropic.d.ts.map +1 -0
  169. package/dist/layer3/anthropic/providers/anthropic.js +266 -0
  170. package/dist/layer3/anthropic/providers/anthropic.js.map +1 -0
  171. package/dist/layer3/anthropic/providers/index.d.ts +8 -0
  172. package/dist/layer3/anthropic/providers/index.d.ts.map +1 -0
  173. package/dist/layer3/anthropic/providers/index.js +15 -0
  174. package/dist/layer3/anthropic/providers/index.js.map +1 -0
  175. package/dist/layer3/anthropic/providers/openai.d.ts +18 -0
  176. package/dist/layer3/anthropic/providers/openai.d.ts.map +1 -0
  177. package/dist/layer3/anthropic/providers/openai.js +340 -0
  178. package/dist/layer3/anthropic/providers/openai.js.map +1 -0
  179. package/dist/layer3/anthropic/request-builder.d.ts +20 -0
  180. package/dist/layer3/anthropic/request-builder.d.ts.map +1 -0
  181. package/dist/layer3/anthropic/request-builder.js +134 -0
  182. package/dist/layer3/anthropic/request-builder.js.map +1 -0
  183. package/dist/layer3/anthropic/types.d.ts +88 -0
  184. package/dist/layer3/anthropic/types.d.ts.map +1 -0
  185. package/dist/layer3/anthropic/types.js +38 -0
  186. package/dist/layer3/anthropic/types.js.map +1 -0
  187. package/dist/layer3/anthropic/utils/index.d.ts +9 -0
  188. package/dist/layer3/anthropic/utils/index.d.ts.map +1 -0
  189. package/dist/layer3/anthropic/utils/index.js +24 -0
  190. package/dist/layer3/anthropic/utils/index.js.map +1 -0
  191. package/dist/layer3/anthropic/utils/path-helpers.d.ts +21 -0
  192. package/dist/layer3/anthropic/utils/path-helpers.d.ts.map +1 -0
  193. package/dist/layer3/anthropic/utils/path-helpers.js +69 -0
  194. package/dist/layer3/anthropic/utils/path-helpers.js.map +1 -0
  195. package/dist/layer3/anthropic/utils/response-parser.d.ts +40 -0
  196. package/dist/layer3/anthropic/utils/response-parser.d.ts.map +1 -0
  197. package/dist/layer3/anthropic/utils/response-parser.js +285 -0
  198. package/dist/layer3/anthropic/utils/response-parser.js.map +1 -0
  199. package/dist/layer3/anthropic/utils/retry.d.ts +15 -0
  200. package/dist/layer3/anthropic/utils/retry.d.ts.map +1 -0
  201. package/dist/layer3/anthropic/utils/retry.js +62 -0
  202. package/dist/layer3/anthropic/utils/retry.js.map +1 -0
  203. package/dist/layer3/index.d.ts +1 -0
  204. package/dist/layer3/index.d.ts.map +1 -1
  205. package/dist/layer3/index.js +16 -6
  206. package/dist/layer3/index.js.map +1 -1
  207. package/dist/layer3/osv-check.d.ts +75 -0
  208. package/dist/layer3/osv-check.d.ts.map +1 -0
  209. package/dist/layer3/osv-check.js +308 -0
  210. package/dist/layer3/osv-check.js.map +1 -0
  211. package/dist/rules/framework-fixes.d.ts +48 -0
  212. package/dist/rules/framework-fixes.d.ts.map +1 -0
  213. package/dist/rules/framework-fixes.js +439 -0
  214. package/dist/rules/framework-fixes.js.map +1 -0
  215. package/dist/rules/index.d.ts +8 -0
  216. package/dist/rules/index.d.ts.map +1 -0
  217. package/dist/rules/index.js +18 -0
  218. package/dist/rules/index.js.map +1 -0
  219. package/dist/rules/metadata.d.ts +43 -0
  220. package/dist/rules/metadata.d.ts.map +1 -0
  221. package/dist/rules/metadata.js +734 -0
  222. package/dist/rules/metadata.js.map +1 -0
  223. package/dist/suppression/config-loader.d.ts +74 -0
  224. package/dist/suppression/config-loader.d.ts.map +1 -0
  225. package/dist/suppression/config-loader.js +424 -0
  226. package/dist/suppression/config-loader.js.map +1 -0
  227. package/dist/suppression/hash.d.ts +48 -0
  228. package/dist/suppression/hash.d.ts.map +1 -0
  229. package/dist/suppression/hash.js +88 -0
  230. package/dist/suppression/hash.js.map +1 -0
  231. package/dist/suppression/index.d.ts +11 -0
  232. package/dist/suppression/index.d.ts.map +1 -0
  233. package/dist/suppression/index.js +39 -0
  234. package/dist/suppression/index.js.map +1 -0
  235. package/dist/suppression/inline-parser.d.ts +39 -0
  236. package/dist/suppression/inline-parser.d.ts.map +1 -0
  237. package/dist/suppression/inline-parser.js +218 -0
  238. package/dist/suppression/inline-parser.js.map +1 -0
  239. package/dist/suppression/manager.d.ts +94 -0
  240. package/dist/suppression/manager.d.ts.map +1 -0
  241. package/dist/suppression/manager.js +292 -0
  242. package/dist/suppression/manager.js.map +1 -0
  243. package/dist/suppression/types.d.ts +151 -0
  244. package/dist/suppression/types.d.ts.map +1 -0
  245. package/dist/suppression/types.js +28 -0
  246. package/dist/suppression/types.js.map +1 -0
  247. package/dist/tiers.d.ts +1 -1
  248. package/dist/tiers.d.ts.map +1 -1
  249. package/dist/tiers.js +27 -0
  250. package/dist/tiers.js.map +1 -1
  251. package/dist/types.d.ts +62 -1
  252. package/dist/types.d.ts.map +1 -1
  253. package/dist/types.js.map +1 -1
  254. package/dist/utils/context-helpers.d.ts +4 -0
  255. package/dist/utils/context-helpers.d.ts.map +1 -1
  256. package/dist/utils/context-helpers.js +13 -9
  257. package/dist/utils/context-helpers.js.map +1 -1
  258. package/package.json +4 -2
  259. package/src/__tests__/benchmark/fixtures/layer1/mcp-config-audit.json +31 -0
  260. package/src/__tests__/benchmark/fixtures/layer2/ai-execution-sinks.ts +1489 -82
  261. package/src/__tests__/benchmark/fixtures/layer2/ai-mcp-security.ts +495 -0
  262. package/src/__tests__/benchmark/fixtures/layer2/ai-package-hallucination.ts +255 -0
  263. package/src/__tests__/benchmark/fixtures/layer2/ai-prompt-hygiene.ts +300 -1
  264. package/src/__tests__/benchmark/fixtures/layer2/ai-rag-safety.ts +139 -0
  265. package/src/__tests__/benchmark/fixtures/layer2/byok-patterns.ts +7 -0
  266. package/src/__tests__/benchmark/fixtures/layer2/data-exposure.ts +63 -0
  267. package/src/__tests__/benchmark/fixtures/layer2/excessive-agency.ts +221 -0
  268. package/src/__tests__/benchmark/fixtures/layer2/index.ts +18 -0
  269. package/src/__tests__/benchmark/fixtures/layer2/model-supply-chain.ts +204 -0
  270. package/src/__tests__/benchmark/fixtures/layer2/phase1-enhancements.ts +157 -0
  271. package/src/__tests__/snapshots/__snapshots__/anthropic-validation-refactor.test.ts.snap +758 -0
  272. package/src/__tests__/snapshots/__snapshots__/dangerous-functions-refactor.test.ts.snap +503 -0
  273. package/src/__tests__/snapshots/anthropic-validation-refactor.test.ts +321 -0
  274. package/src/__tests__/snapshots/dangerous-functions-refactor.test.ts +439 -0
  275. package/src/baseline/__tests__/diff.test.ts +261 -0
  276. package/src/baseline/__tests__/manager.test.ts +225 -0
  277. package/src/baseline/diff.ts +135 -0
  278. package/src/baseline/index.ts +29 -0
  279. package/src/baseline/manager.ts +230 -0
  280. package/src/baseline/types.ts +97 -0
  281. package/src/formatters/cli-terminal.ts +444 -41
  282. package/src/formatters/github-comment.ts +79 -11
  283. package/src/formatters/index.ts +4 -0
  284. package/src/index.ts +197 -14
  285. package/src/layer1/config-audit.ts +24 -3
  286. package/src/layer1/config-mcp-audit.ts +276 -0
  287. package/src/layer1/index.ts +16 -6
  288. package/src/layer2/ai-agent-tools.ts +336 -0
  289. package/src/layer2/ai-endpoint-protection.ts +16 -3
  290. package/src/layer2/ai-execution-sinks.ts +516 -12
  291. package/src/layer2/ai-fingerprinting.ts +5 -1
  292. package/src/layer2/ai-mcp-security.ts +730 -0
  293. package/src/layer2/ai-package-hallucination.ts +791 -0
  294. package/src/layer2/ai-prompt-hygiene.ts +547 -9
  295. package/src/layer2/ai-rag-safety.ts +382 -3
  296. package/src/layer2/auth-antipatterns.ts +5 -0
  297. package/src/layer2/byok-patterns.ts +5 -1
  298. package/src/layer2/dangerous-functions/child-process.ts +98 -0
  299. package/src/layer2/dangerous-functions/dom-xss.ts +220 -0
  300. package/src/layer2/dangerous-functions/index.ts +949 -0
  301. package/src/layer2/dangerous-functions/json-parse.ts +385 -0
  302. package/src/layer2/dangerous-functions/math-random.ts +537 -0
  303. package/src/layer2/dangerous-functions/patterns.ts +174 -0
  304. package/src/layer2/dangerous-functions/request-validation.ts +145 -0
  305. package/src/layer2/dangerous-functions/utils/control-flow.ts +162 -0
  306. package/src/layer2/dangerous-functions/utils/helpers.ts +170 -0
  307. package/src/layer2/dangerous-functions/utils/index.ts +25 -0
  308. package/src/layer2/dangerous-functions/utils/schema-validation.ts +91 -0
  309. package/src/layer2/data-exposure.ts +5 -1
  310. package/src/layer2/framework-checks.ts +5 -0
  311. package/src/layer2/index.ts +63 -1
  312. package/src/layer2/logic-gates.ts +5 -0
  313. package/src/layer2/model-supply-chain.ts +456 -0
  314. package/src/layer2/risky-imports.ts +5 -0
  315. package/src/layer2/variables.ts +5 -0
  316. package/src/layer3/__tests__/osv-check.test.ts +384 -0
  317. package/src/layer3/anthropic/auto-dismiss.ts +212 -0
  318. package/src/layer3/anthropic/clients.ts +84 -0
  319. package/src/layer3/anthropic/index.ts +170 -0
  320. package/src/layer3/anthropic/prompts/index.ts +14 -0
  321. package/src/layer3/anthropic/prompts/semantic-analysis.ts +173 -0
  322. package/src/layer3/anthropic/prompts/validation.ts +419 -0
  323. package/src/layer3/anthropic/providers/anthropic.ts +310 -0
  324. package/src/layer3/anthropic/providers/index.ts +8 -0
  325. package/src/layer3/anthropic/providers/openai.ts +384 -0
  326. package/src/layer3/anthropic/request-builder.ts +150 -0
  327. package/src/layer3/anthropic/types.ts +148 -0
  328. package/src/layer3/anthropic/utils/index.ts +26 -0
  329. package/src/layer3/anthropic/utils/path-helpers.ts +68 -0
  330. package/src/layer3/anthropic/utils/response-parser.ts +322 -0
  331. package/src/layer3/anthropic/utils/retry.ts +75 -0
  332. package/src/layer3/index.ts +18 -5
  333. package/src/layer3/osv-check.ts +420 -0
  334. package/src/rules/__tests__/framework-fixes.test.ts +689 -0
  335. package/src/rules/__tests__/metadata.test.ts +218 -0
  336. package/src/rules/framework-fixes.ts +470 -0
  337. package/src/rules/index.ts +21 -0
  338. package/src/rules/metadata.ts +831 -0
  339. package/src/suppression/__tests__/config-loader.test.ts +382 -0
  340. package/src/suppression/__tests__/hash.test.ts +166 -0
  341. package/src/suppression/__tests__/inline-parser.test.ts +212 -0
  342. package/src/suppression/__tests__/manager.test.ts +415 -0
  343. package/src/suppression/config-loader.ts +462 -0
  344. package/src/suppression/hash.ts +95 -0
  345. package/src/suppression/index.ts +51 -0
  346. package/src/suppression/inline-parser.ts +273 -0
  347. package/src/suppression/manager.ts +379 -0
  348. package/src/suppression/types.ts +174 -0
  349. package/src/tiers.ts +36 -0
  350. package/src/types.ts +90 -0
  351. package/src/utils/context-helpers.ts +13 -9
  352. package/dist/layer2/dangerous-functions.d.ts +0 -7
  353. package/dist/layer2/dangerous-functions.d.ts.map +0 -1
  354. package/dist/layer2/dangerous-functions.js +0 -1701
  355. package/dist/layer2/dangerous-functions.js.map +0 -1
  356. package/dist/layer3/anthropic.d.ts +0 -87
  357. package/dist/layer3/anthropic.d.ts.map +0 -1
  358. package/dist/layer3/anthropic.js +0 -1948
  359. package/dist/layer3/anthropic.js.map +0 -1
  360. package/dist/layer3/openai.d.ts +0 -25
  361. package/dist/layer3/openai.d.ts.map +0 -1
  362. package/dist/layer3/openai.js +0 -238
  363. package/dist/layer3/openai.js.map +0 -1
  364. package/src/layer2/dangerous-functions.ts +0 -1940
  365. package/src/layer3/anthropic.ts +0 -2257
@@ -0,0 +1,696 @@
1
+ "use strict";
2
+ /**
3
+ * Layer 2: AI Package Hallucination Detection
4
+ * Detects AI-hallucinated and potentially fake package names in imports
5
+ *
6
+ * Background: USENIX research shows ~20% of AI-generated code references
7
+ * packages that don't exist, creating supply chain attack vectors. Attackers
8
+ * can register these fake package names and inject malicious code.
9
+ *
10
+ * Detection Strategy:
11
+ * 1. Known hallucinations database (verified fake packages)
12
+ * 2. Heuristic patterns (suspicious naming conventions)
13
+ * 3. Generic unscoped names that are too vague to be real
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.detectAIPackageHallucination = detectAIPackageHallucination;
17
+ const context_helpers_1 = require("../utils/context-helpers");
18
+ // ============================================================================
19
+ // Known Hallucinated Package Database
20
+ // ============================================================================
21
+ /**
22
+ * Verified fake package names from research and real-world observations
23
+ * These are packages that LLMs frequently suggest but don't exist (or are typosquats)
24
+ */
25
+ const KNOWN_HALLUCINATED_PACKAGES = new Set([
26
+ // JavaScript/TypeScript - from USENIX research and observation
27
+ 'react-charts', // Real: recharts, react-chartjs-2
28
+ 'mongo-client', // Real: mongodb
29
+ 'postgres-client', // Real: pg, postgres
30
+ 'fast-json', // Real: fast-json-stringify
31
+ 'node-helpers', // Doesn't exist
32
+ 'node-utils', // Doesn't exist
33
+ 'easy-utils', // Doesn't exist
34
+ 'simple-tools', // Doesn't exist
35
+ 'csv-parser-pro', // Real: csv-parser, papaparse
36
+ 'express-jwt-auth', // Real: express-jwt, passport-jwt
37
+ 'mongoose-connect', // Real: mongoose
38
+ 'redis-connect', // Real: redis, ioredis
39
+ 'graphql-tools-schema', // Real: @graphql-tools/schema
40
+ 'aws-s3-client', // Real: @aws-sdk/client-s3
41
+ 'google-cloud-storage', // Real: @google-cloud/storage (scoped)
42
+ 'firebase-auth-client', // Real: firebase, firebase-admin
43
+ 'stripe-payments', // Real: stripe
44
+ 'twilio-sms', // Real: twilio
45
+ 'sendgrid-email', // Real: @sendgrid/mail
46
+ 'mailchimp-api', // Real: @mailchimp/mailchimp_marketing
47
+ 'slack-bot', // Real: @slack/bolt, @slack/web-api
48
+ 'discord-bot', // Real: discord.js
49
+ 'telegram-bot', // Real: telegraf, node-telegram-bot-api
50
+ 'jwt-decode-verify', // Real: jsonwebtoken, jose
51
+ 'bcrypt-hash', // Real: bcrypt, bcryptjs
52
+ 'uuid-generate', // Real: uuid
53
+ 'date-formatter', // Real: date-fns, dayjs, moment
54
+ 'image-resize', // Real: sharp, jimp
55
+ 'pdf-generator', // Real: pdfkit, pdf-lib
56
+ 'excel-parser', // Real: xlsx, exceljs
57
+ 'xml-parser-pro', // Real: fast-xml-parser, xml2js
58
+ 'yaml-parser', // Real: js-yaml, yaml
59
+ // Python hallucinated packages
60
+ 'easy-flask', // Real: flask
61
+ 'simple-api', // Real: fastapi, flask
62
+ 'fast-db', // Real: sqlalchemy, databases
63
+ 'python-helpers', // Doesn't exist
64
+ 'django-helpers', // Doesn't exist
65
+ 'flask-helpers', // Doesn't exist
66
+ 'numpy-utils', // Doesn't exist
67
+ 'pandas-helpers', // Doesn't exist
68
+ 'data-parser', // Real: pandas
69
+ 'ml-utils', // Doesn't exist
70
+ 'ai-tools', // Doesn't exist
71
+ ]);
72
+ /**
73
+ * Well-known legitimate packages to avoid false positives
74
+ */
75
+ const KNOWN_LEGITIMATE_PACKAGES = new Set([
76
+ // Core/popular JS packages
77
+ 'react', 'vue', 'angular', 'svelte', 'solid-js',
78
+ 'express', 'fastify', 'hono', 'koa', 'nest',
79
+ 'next', 'nuxt', 'remix', 'astro', 'gatsby',
80
+ 'axios', 'fetch', 'got', 'ky', 'superagent',
81
+ 'lodash', 'underscore', 'radash', 'ramda',
82
+ 'zod', 'joi', 'yup', 'ajv', 'valibot',
83
+ 'dayjs', 'date-fns', 'moment', 'luxon',
84
+ 'mongodb', 'mongoose', 'pg', 'mysql2', 'better-sqlite3',
85
+ 'prisma', 'drizzle-orm', 'typeorm', 'sequelize', 'knex',
86
+ 'redis', 'ioredis',
87
+ 'bcrypt', 'bcryptjs', 'argon2',
88
+ 'jsonwebtoken', 'jose', 'passport',
89
+ 'uuid', 'nanoid', 'cuid', 'ulid',
90
+ 'sharp', 'jimp', 'canvas',
91
+ 'pdfkit', 'pdf-lib',
92
+ 'xlsx', 'exceljs',
93
+ 'cheerio', 'puppeteer', 'playwright',
94
+ 'winston', 'pino', 'bunyan',
95
+ 'dotenv', 'config', 'convict',
96
+ 'chalk', 'picocolors', 'kleur',
97
+ 'commander', 'yargs', 'meow', 'cac',
98
+ 'inquirer', 'prompts',
99
+ 'glob', 'fast-glob', 'globby',
100
+ 'chokidar', 'nodemon',
101
+ 'esbuild', 'vite', 'webpack', 'rollup', 'parcel',
102
+ 'jest', 'vitest', 'mocha', 'ava', 'tape',
103
+ 'eslint', 'prettier', 'biome',
104
+ 'typescript', 'ts-node', 'tsx',
105
+ 'openai', 'anthropic',
106
+ 'stripe', 'paypal',
107
+ 'twilio', 'nodemailer',
108
+ 'aws-sdk',
109
+ 'firebase', 'firebase-admin',
110
+ 'supabase',
111
+ 'graphql', 'apollo-server', 'urql',
112
+ 'socket.io', 'ws',
113
+ 'bullmq', 'bee-queue',
114
+ 'csv-parser', 'papaparse',
115
+ 'fast-xml-parser', 'xml2js',
116
+ 'js-yaml', 'yaml',
117
+ // Real 'simple-' packages
118
+ 'simple-git', 'simpl-schema',
119
+ // Real 'fast-' packages
120
+ 'fast-json-stringify', 'fastify', 'fast-glob', 'fast-deep-equal', 'fast-xml-parser',
121
+ // Python packages
122
+ 'flask', 'django', 'fastapi', 'starlette', 'tornado',
123
+ 'requests', 'httpx', 'aiohttp',
124
+ 'numpy', 'pandas', 'scipy', 'matplotlib',
125
+ 'scikit-learn', 'tensorflow', 'pytorch', 'keras',
126
+ 'sqlalchemy', 'alembic', 'psycopg2', 'asyncpg',
127
+ 'celery', 'redis', 'dramatiq',
128
+ 'pydantic', 'marshmallow',
129
+ 'pytest', 'unittest', 'nose',
130
+ 'black', 'flake8', 'mypy', 'ruff',
131
+ 'boto3', 'botocore',
132
+ 'pillow', 'opencv-python',
133
+ 'beautifulsoup4', 'lxml', 'scrapy',
134
+ ]);
135
+ // ============================================================================
136
+ // Typosquatting Detection
137
+ // ============================================================================
138
+ /**
139
+ * Popular packages to check for typosquatting
140
+ */
141
+ const POPULAR_PACKAGES_FOR_TYPOSQUAT = [
142
+ // JavaScript/TypeScript core
143
+ 'react', 'vue', 'angular', 'svelte', 'solid',
144
+ 'express', 'fastify', 'koa', 'hono', 'nest',
145
+ 'next', 'nuxt', 'remix', 'gatsby', 'astro',
146
+ 'lodash', 'axios', 'moment', 'dayjs', 'zod',
147
+ 'mongoose', 'sequelize', 'prisma', 'typeorm', 'knex',
148
+ 'webpack', 'rollup', 'vite', 'esbuild', 'parcel',
149
+ 'jest', 'vitest', 'mocha', 'chai', 'cypress',
150
+ 'typescript', 'eslint', 'prettier', 'babel',
151
+ 'redux', 'mobx', 'zustand', 'jotai', 'recoil',
152
+ 'tailwindcss', 'bootstrap', 'antd', 'material-ui',
153
+ 'socket', 'graphql', 'apollo', 'trpc',
154
+ // Python core
155
+ 'requests', 'flask', 'django', 'fastapi', 'tornado',
156
+ 'numpy', 'pandas', 'scipy', 'matplotlib', 'seaborn',
157
+ 'tensorflow', 'pytorch', 'keras', 'scikit-learn',
158
+ 'sqlalchemy', 'celery', 'redis', 'boto3',
159
+ 'pydantic', 'pytest', 'black', 'ruff',
160
+ ];
161
+ /**
162
+ * Common character substitutions used in typosquatting
163
+ */
164
+ const TYPOSQUAT_SUBSTITUTIONS = [
165
+ ['0', 'o'], ['o', '0'],
166
+ ['1', 'l'], ['l', '1'], ['1', 'i'], ['i', '1'],
167
+ ['5', 's'], ['s', '5'],
168
+ ['a', '@'], ['@', 'a'],
169
+ ['e', '3'], ['3', 'e'],
170
+ ['rn', 'm'], ['m', 'rn'],
171
+ ['vv', 'w'], ['w', 'vv'],
172
+ ['cl', 'd'], ['d', 'cl'],
173
+ ['ii', 'u'], ['u', 'ii'],
174
+ ];
175
+ /**
176
+ * Calculate Levenshtein distance between two strings
177
+ */
178
+ function levenshteinDistance(a, b) {
179
+ const matrix = [];
180
+ for (let i = 0; i <= b.length; i++) {
181
+ matrix[i] = [i];
182
+ }
183
+ for (let j = 0; j <= a.length; j++) {
184
+ matrix[0][j] = j;
185
+ }
186
+ for (let i = 1; i <= b.length; i++) {
187
+ for (let j = 1; j <= a.length; j++) {
188
+ if (b.charAt(i - 1) === a.charAt(j - 1)) {
189
+ matrix[i][j] = matrix[i - 1][j - 1];
190
+ }
191
+ else {
192
+ matrix[i][j] = Math.min(matrix[i - 1][j - 1] + 1, matrix[i][j - 1] + 1, matrix[i - 1][j] + 1);
193
+ }
194
+ }
195
+ }
196
+ return matrix[b.length][a.length];
197
+ }
198
+ /**
199
+ * Check if package name has character substitutions matching a popular package
200
+ */
201
+ function hasCharacterSubstitution(packageName, popularPackage) {
202
+ // Apply each substitution to the popular package and check for match
203
+ for (const [from, to] of TYPOSQUAT_SUBSTITUTIONS) {
204
+ const substituted = popularPackage.replace(new RegExp(from, 'g'), to);
205
+ if (substituted.toLowerCase() === packageName.toLowerCase() && substituted !== popularPackage) {
206
+ return true;
207
+ }
208
+ }
209
+ return false;
210
+ }
211
+ /**
212
+ * Check if package is a potential typosquat of a popular package
213
+ * Returns the popular package it resembles and the reason
214
+ */
215
+ function checkTyposquatting(packageName) {
216
+ const name = packageName.toLowerCase();
217
+ for (const popular of POPULAR_PACKAGES_FOR_TYPOSQUAT) {
218
+ const popularLower = popular.toLowerCase();
219
+ // Skip exact match
220
+ if (name === popularLower)
221
+ continue;
222
+ // Check Levenshtein distance (1-2 chars difference)
223
+ const distance = levenshteinDistance(name, popularLower);
224
+ if (distance === 1) {
225
+ return {
226
+ isTyposquat: true,
227
+ similarTo: popular,
228
+ reason: `differs by only 1 character from "${popular}"`,
229
+ };
230
+ }
231
+ if (distance === 2 && name.length >= 5 && Math.abs(name.length - popularLower.length) <= 1) {
232
+ return {
233
+ isTyposquat: true,
234
+ similarTo: popular,
235
+ reason: `very similar to "${popular}" (2 char difference)`,
236
+ };
237
+ }
238
+ // Check character substitution
239
+ if (hasCharacterSubstitution(name, popularLower)) {
240
+ return {
241
+ isTyposquat: true,
242
+ similarTo: popular,
243
+ reason: `uses character substitution similar to "${popular}" (e.g., 0↔o, 1↔l)`,
244
+ };
245
+ }
246
+ // Check for doubled characters (lodaash vs lodash)
247
+ const doubledPattern = new RegExp(`^${popularLower.split('').join('+')}+$`);
248
+ if (doubledPattern.test(name) && name !== popularLower) {
249
+ return {
250
+ isTyposquat: true,
251
+ similarTo: popular,
252
+ reason: `contains doubled characters similar to "${popular}"`,
253
+ };
254
+ }
255
+ // Check for missing vowels (rqsts vs requests)
256
+ const noVowels = popularLower.replace(/[aeiou]/g, '');
257
+ const nameNoVowels = name.replace(/[aeiou]/g, '');
258
+ if (noVowels === nameNoVowels && noVowels.length >= 4 && name !== popularLower) {
259
+ return {
260
+ isTyposquat: true,
261
+ similarTo: popular,
262
+ reason: `missing vowels similar to "${popular}"`,
263
+ };
264
+ }
265
+ // Check for common prefixes/suffixes that create confusion
266
+ if (name === `${popularLower}-js` || name === `${popularLower}js` ||
267
+ name === `node-${popularLower}` || name === `${popularLower}-node`) {
268
+ return {
269
+ isTyposquat: true,
270
+ similarTo: popular,
271
+ reason: `adds common suffix/prefix that could be confused with "${popular}"`,
272
+ };
273
+ }
274
+ }
275
+ return { isTyposquat: false };
276
+ }
277
+ // ============================================================================
278
+ // Suspicious Pattern Definitions
279
+ // ============================================================================
280
+ /**
281
+ * Unscoped generic names that are too vague to be real packages
282
+ * Real packages have specific names, not generic utility words
283
+ */
284
+ const GENERIC_UNSCOPED_NAMES = new Set([
285
+ 'utils',
286
+ 'helpers',
287
+ 'common',
288
+ 'tools',
289
+ 'shared',
290
+ 'lib',
291
+ 'core',
292
+ 'base',
293
+ 'main',
294
+ 'app',
295
+ 'api',
296
+ 'data',
297
+ 'models',
298
+ 'services',
299
+ 'modules',
300
+ 'components',
301
+ ]);
302
+ /**
303
+ * Prefixes that are frequently hallucinated when combined with generic suffixes
304
+ */
305
+ const SUSPICIOUS_PREFIXES = [
306
+ 'easy-',
307
+ 'simple-',
308
+ 'fast-', // Note: some real packages use this, checked against allowlist
309
+ 'quick-',
310
+ 'basic-',
311
+ 'super-',
312
+ 'mega-',
313
+ 'ultra-',
314
+ 'awesome-',
315
+ 'better-',
316
+ 'node-', // Note: some real packages use this, but often hallucinated for non-core modules
317
+ 'react-', // Note: many real packages, but also many hallucinated
318
+ 'vue-', // Note: many real packages, but also many hallucinated
319
+ 'express-', // Note: many real packages, but also many hallucinated
320
+ 'python-',
321
+ 'django-', // Note: some real, but often hallucinated
322
+ 'flask-', // Note: some real, but often hallucinated
323
+ ];
324
+ /**
325
+ * Suffixes that indicate potential hallucination when combined with suspicious prefixes
326
+ */
327
+ const SUSPICIOUS_SUFFIXES = [
328
+ '-utils',
329
+ '-helpers',
330
+ '-tools',
331
+ '-lib',
332
+ '-client', // Often hallucinated for already-named services
333
+ '-sdk', // Often hallucinated
334
+ '-api',
335
+ '-wrapper',
336
+ '-connector',
337
+ '-adapter',
338
+ '-handler',
339
+ '-manager',
340
+ '-service',
341
+ '-pro',
342
+ '-plus',
343
+ '-enhanced',
344
+ ];
345
+ // ============================================================================
346
+ // Context Detection
347
+ // ============================================================================
348
+ /**
349
+ * Check if package name is scoped (@org/package)
350
+ * Scoped packages are less likely to be hallucinated (requires npm org)
351
+ */
352
+ function isScopedPackage(packageName) {
353
+ return packageName.startsWith('@');
354
+ }
355
+ /**
356
+ * Check if this is a relative import (./path or ../path)
357
+ */
358
+ function isRelativeImport(importPath) {
359
+ return importPath.startsWith('./') || importPath.startsWith('../') || importPath.startsWith('/');
360
+ }
361
+ /**
362
+ * Check if this is an alias import (@/, ~/, #)
363
+ */
364
+ function isAliasImport(importPath) {
365
+ return /^[@~#]\//.test(importPath);
366
+ }
367
+ /**
368
+ * Check if this is a Node.js built-in module
369
+ */
370
+ function isNodeBuiltin(packageName) {
371
+ const builtins = new Set([
372
+ 'fs', 'path', 'http', 'https', 'crypto', 'os', 'url', 'util', 'stream',
373
+ 'events', 'buffer', 'querystring', 'child_process', 'cluster', 'dgram',
374
+ 'dns', 'net', 'readline', 'repl', 'tls', 'tty', 'v8', 'vm', 'zlib',
375
+ 'assert', 'async_hooks', 'console', 'constants', 'domain', 'inspector',
376
+ 'module', 'perf_hooks', 'process', 'punycode', 'string_decoder',
377
+ 'timers', 'trace_events', 'worker_threads',
378
+ // Node: prefixed
379
+ 'node:fs', 'node:path', 'node:http', 'node:https', 'node:crypto',
380
+ 'node:os', 'node:url', 'node:util', 'node:stream', 'node:events',
381
+ 'node:buffer', 'node:querystring', 'node:child_process', 'node:test',
382
+ ]);
383
+ return builtins.has(packageName) || packageName.startsWith('node:');
384
+ }
385
+ /**
386
+ * Check if file is a package manifest
387
+ */
388
+ function isPackageManifest(filePath) {
389
+ const manifestFiles = [
390
+ 'package.json',
391
+ 'requirements.txt',
392
+ 'Pipfile',
393
+ 'pyproject.toml',
394
+ 'setup.py',
395
+ 'Gemfile',
396
+ 'go.mod',
397
+ 'Cargo.toml',
398
+ 'composer.json',
399
+ ];
400
+ return manifestFiles.some(f => filePath.endsWith(f));
401
+ }
402
+ /**
403
+ * Check if package name matches suspicious patterns
404
+ */
405
+ function isSuspiciousPattern(packageName) {
406
+ // Check known hallucinated packages first
407
+ if (KNOWN_HALLUCINATED_PACKAGES.has(packageName)) {
408
+ return { suspicious: true, reason: 'Known hallucinated package from research' };
409
+ }
410
+ // Skip known legitimate packages
411
+ if (KNOWN_LEGITIMATE_PACKAGES.has(packageName)) {
412
+ return { suspicious: false, reason: '' };
413
+ }
414
+ // Check unscoped generic names
415
+ if (GENERIC_UNSCOPED_NAMES.has(packageName)) {
416
+ return { suspicious: true, reason: 'Generic unscoped name - real packages have specific names' };
417
+ }
418
+ // Check suspicious prefix + suffix combinations
419
+ for (const prefix of SUSPICIOUS_PREFIXES) {
420
+ if (packageName.startsWith(prefix)) {
421
+ // Check if it has a suspicious suffix too
422
+ for (const suffix of SUSPICIOUS_SUFFIXES) {
423
+ if (packageName.endsWith(suffix)) {
424
+ // Double suspicious - prefix AND suffix
425
+ return {
426
+ suspicious: true,
427
+ reason: `Suspicious pattern: "${prefix}" prefix with "${suffix}" suffix`,
428
+ };
429
+ }
430
+ }
431
+ // Just prefix is lower confidence
432
+ const baseName = packageName.slice(prefix.length);
433
+ if (GENERIC_UNSCOPED_NAMES.has(baseName) || baseName.length < 3) {
434
+ return {
435
+ suspicious: true,
436
+ reason: `Suspicious pattern: "${prefix}" prefix with generic name`,
437
+ };
438
+ }
439
+ }
440
+ }
441
+ // Check if it's just prefix + generic suffix
442
+ for (const suffix of SUSPICIOUS_SUFFIXES) {
443
+ if (packageName.endsWith(suffix)) {
444
+ const baseName = packageName.slice(0, -suffix.length);
445
+ // If the base is very short or generic, flag it
446
+ if (baseName.length <= 2 || GENERIC_UNSCOPED_NAMES.has(baseName)) {
447
+ return {
448
+ suspicious: true,
449
+ reason: `Suspicious pattern: generic name with "${suffix}" suffix`,
450
+ };
451
+ }
452
+ }
453
+ }
454
+ return { suspicious: false, reason: '' };
455
+ }
456
+ /**
457
+ * Extract package name from import/require path
458
+ */
459
+ function extractPackageName(importPath) {
460
+ // Skip relative and alias imports
461
+ if (isRelativeImport(importPath) || isAliasImport(importPath)) {
462
+ return null;
463
+ }
464
+ // Handle scoped packages (@org/package)
465
+ if (importPath.startsWith('@')) {
466
+ const parts = importPath.split('/');
467
+ if (parts.length >= 2) {
468
+ return `${parts[0]}/${parts[1]}`;
469
+ }
470
+ return null;
471
+ }
472
+ // Regular package - get the first part before any /
473
+ const parts = importPath.split('/');
474
+ return parts[0];
475
+ }
476
+ /**
477
+ * Extract imports from JavaScript/TypeScript code
478
+ */
479
+ function extractJSImports(content) {
480
+ const imports = [];
481
+ const lines = content.split('\n');
482
+ // ES6 import patterns
483
+ const es6ImportRegex = /import\s+(?:(?:\{[^}]*\}|\*\s+as\s+\w+|\w+)\s+from\s+)?['"]([^'"]+)['"]/g;
484
+ // require() patterns
485
+ const requireRegex = /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
486
+ // Dynamic import
487
+ const dynamicImportRegex = /import\s*\(\s*['"]([^'"]+)['"]\s*\)/g;
488
+ let match;
489
+ while ((match = es6ImportRegex.exec(content)) !== null) {
490
+ const lineNumber = content.substring(0, match.index).split('\n').length;
491
+ const packageName = extractPackageName(match[1]);
492
+ if (packageName && !isNodeBuiltin(packageName)) {
493
+ imports.push({
494
+ packageName,
495
+ lineNumber,
496
+ lineContent: lines[lineNumber - 1]?.trim() || '',
497
+ });
498
+ }
499
+ }
500
+ while ((match = requireRegex.exec(content)) !== null) {
501
+ const lineNumber = content.substring(0, match.index).split('\n').length;
502
+ const packageName = extractPackageName(match[1]);
503
+ if (packageName && !isNodeBuiltin(packageName)) {
504
+ imports.push({
505
+ packageName,
506
+ lineNumber,
507
+ lineContent: lines[lineNumber - 1]?.trim() || '',
508
+ });
509
+ }
510
+ }
511
+ while ((match = dynamicImportRegex.exec(content)) !== null) {
512
+ const lineNumber = content.substring(0, match.index).split('\n').length;
513
+ const packageName = extractPackageName(match[1]);
514
+ if (packageName && !isNodeBuiltin(packageName)) {
515
+ imports.push({
516
+ packageName,
517
+ lineNumber,
518
+ lineContent: lines[lineNumber - 1]?.trim() || '',
519
+ });
520
+ }
521
+ }
522
+ return imports;
523
+ }
524
+ /**
525
+ * Extract dependencies from package.json
526
+ */
527
+ function extractPackageJsonDeps(content, lines) {
528
+ const imports = [];
529
+ try {
530
+ const pkg = JSON.parse(content);
531
+ const allDeps = {
532
+ ...pkg.dependencies,
533
+ ...pkg.devDependencies,
534
+ ...pkg.peerDependencies,
535
+ ...pkg.optionalDependencies,
536
+ };
537
+ for (const packageName of Object.keys(allDeps)) {
538
+ // Find the line number where this package appears
539
+ const lineIndex = lines.findIndex(line => line.includes(`"${packageName}"`));
540
+ if (lineIndex !== -1) {
541
+ imports.push({
542
+ packageName,
543
+ lineNumber: lineIndex + 1,
544
+ lineContent: lines[lineIndex].trim(),
545
+ });
546
+ }
547
+ }
548
+ }
549
+ catch {
550
+ // Invalid JSON, skip
551
+ }
552
+ return imports;
553
+ }
554
+ /**
555
+ * Extract dependencies from requirements.txt
556
+ */
557
+ function extractRequirementsDeps(_content, lines) {
558
+ const imports = [];
559
+ for (let i = 0; i < lines.length; i++) {
560
+ const line = lines[i].trim();
561
+ // Skip comments and empty lines
562
+ if (!line || line.startsWith('#') || line.startsWith('-'))
563
+ continue;
564
+ // Extract package name (before ==, >=, <=, ~=, etc.)
565
+ const match = line.match(/^([a-zA-Z0-9_-]+)/);
566
+ if (match) {
567
+ imports.push({
568
+ packageName: match[1].toLowerCase().replace(/_/g, '-'),
569
+ lineNumber: i + 1,
570
+ lineContent: line,
571
+ });
572
+ }
573
+ }
574
+ return imports;
575
+ }
576
+ // ============================================================================
577
+ // Main Detection Function
578
+ // ============================================================================
579
+ /**
580
+ * Main detection function for AI package hallucination
581
+ */
582
+ function detectAIPackageHallucination(content, filePath) {
583
+ const vulnerabilities = [];
584
+ // Skip non-applicable files
585
+ if ((0, context_helpers_1.isScannerOrFixtureFile)(filePath))
586
+ return vulnerabilities;
587
+ if ((0, context_helpers_1.isDocumentationFile)(filePath))
588
+ return vulnerabilities;
589
+ const lines = content.split('\n');
590
+ const isTestFile = (0, context_helpers_1.isTestOrMockFile)(filePath);
591
+ const isExample = (0, context_helpers_1.isExampleDirectory)(filePath);
592
+ const isManifest = isPackageManifest(filePath);
593
+ // Extract imports based on file type
594
+ let imports = [];
595
+ if (filePath.endsWith('package.json')) {
596
+ imports = extractPackageJsonDeps(content, lines);
597
+ }
598
+ else if (filePath.endsWith('requirements.txt')) {
599
+ imports = extractRequirementsDeps(content, lines);
600
+ }
601
+ else if (/\.(js|jsx|ts|tsx|mjs|cjs)$/.test(filePath)) {
602
+ imports = extractJSImports(content);
603
+ }
604
+ else {
605
+ // Not a file we can analyze for imports
606
+ return vulnerabilities;
607
+ }
608
+ // Track already-flagged packages to avoid duplicates
609
+ const flaggedPackages = new Set();
610
+ for (const imp of imports) {
611
+ // Skip if we've already flagged this package
612
+ if (flaggedPackages.has(imp.packageName))
613
+ continue;
614
+ // Skip scoped packages (less likely to be hallucinated)
615
+ if (isScopedPackage(imp.packageName))
616
+ continue;
617
+ // Skip comments
618
+ if ((0, context_helpers_1.isComment)(imp.lineContent))
619
+ continue;
620
+ // Skip known legitimate packages for typosquat check
621
+ if (KNOWN_LEGITIMATE_PACKAGES.has(imp.packageName))
622
+ continue;
623
+ // Check for typosquatting first (higher priority - supply chain attack)
624
+ const typosquatResult = checkTyposquatting(imp.packageName);
625
+ if (typosquatResult.isTyposquat) {
626
+ flaggedPackages.add(imp.packageName);
627
+ let severity = 'high'; // Typosquats are always high priority
628
+ // Package manifests in production are critical
629
+ if (isManifest) {
630
+ severity = 'critical';
631
+ }
632
+ // Test files and examples get downgraded
633
+ if (isTestFile || isExample) {
634
+ severity = 'low';
635
+ }
636
+ const description = `Package "${imp.packageName}" ${typosquatResult.reason}. This could be a typosquatting attack where attackers register similar package names to steal credentials or inject malicious code.`;
637
+ const suggestedFix = `Verify you meant to use "${typosquatResult.similarTo}". Run "npm view ${imp.packageName}" to check if this package exists. If it doesn't, update to "${typosquatResult.similarTo}".`;
638
+ vulnerabilities.push({
639
+ id: `ai-pkg-typosquat-${filePath}-${imp.lineNumber}-${imp.packageName}`,
640
+ filePath,
641
+ lineNumber: imp.lineNumber,
642
+ lineContent: imp.lineContent,
643
+ severity,
644
+ category: 'ai_package_typosquat',
645
+ title: `Potential typosquat: ${imp.packageName} (similar to ${typosquatResult.similarTo})`,
646
+ description,
647
+ suggestedFix,
648
+ confidence: 'high',
649
+ layer: 2,
650
+ requiresAIValidation: false, // Typosquats don't need AI validation - pattern is clear
651
+ });
652
+ continue; // Don't also flag as hallucination
653
+ }
654
+ // Check if package is suspicious (hallucination patterns)
655
+ const { suspicious, reason } = isSuspiciousPattern(imp.packageName);
656
+ if (suspicious) {
657
+ flaggedPackages.add(imp.packageName);
658
+ // Determine severity based on context
659
+ let severity = 'medium';
660
+ // Known hallucinations are higher severity
661
+ if (KNOWN_HALLUCINATED_PACKAGES.has(imp.packageName)) {
662
+ severity = 'high';
663
+ }
664
+ // Package manifests are higher severity (direct dependency)
665
+ if (isManifest && severity === 'medium') {
666
+ severity = 'high';
667
+ }
668
+ // Test files and examples get downgraded
669
+ if (isTestFile || isExample) {
670
+ severity = 'info';
671
+ }
672
+ const description = KNOWN_HALLUCINATED_PACKAGES.has(imp.packageName)
673
+ ? `Package "${imp.packageName}" is a known AI-hallucinated package that doesn't exist. This creates a supply chain attack vector where attackers register the fake package name.`
674
+ : `Package "${imp.packageName}" matches suspicious hallucination patterns: ${reason}. Verify this package exists on npm/PyPI before using.`;
675
+ const suggestedFix = KNOWN_HALLUCINATED_PACKAGES.has(imp.packageName)
676
+ ? `Remove "${imp.packageName}" and use the correct package. Search npm/PyPI for the real package that provides this functionality.`
677
+ : `Verify "${imp.packageName}" exists: run "npm view ${imp.packageName}" or check https://www.npmjs.com/package/${imp.packageName}. If it doesn't exist, find the correct package name.`;
678
+ vulnerabilities.push({
679
+ id: `ai-pkg-hallucination-${filePath}-${imp.lineNumber}-${imp.packageName}`,
680
+ filePath,
681
+ lineNumber: imp.lineNumber,
682
+ lineContent: imp.lineContent,
683
+ severity,
684
+ category: 'ai_package_hallucination',
685
+ title: `Potentially hallucinated package: ${imp.packageName}`,
686
+ description,
687
+ suggestedFix,
688
+ confidence: KNOWN_HALLUCINATED_PACKAGES.has(imp.packageName) ? 'high' : 'medium',
689
+ layer: 2,
690
+ requiresAIValidation: severity !== 'info' && !KNOWN_HALLUCINATED_PACKAGES.has(imp.packageName),
691
+ });
692
+ }
693
+ }
694
+ return vulnerabilities;
695
+ }
696
+ //# sourceMappingURL=ai-package-hallucination.js.map