@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,385 @@
1
+ /**
2
+ * JSON.parse Detection
3
+ *
4
+ * Source-aware detection of JSON.parse usage with severity classification
5
+ * based on the data source and error handling context.
6
+ */
7
+
8
+ import type { Vulnerability, VulnerabilitySeverity } from '../../types'
9
+ import { isComment, isTestOrMockFile } from '../../utils/context-helpers'
10
+ import { isInsideTryCatch, hasTryCatchNearby } from './utils/control-flow'
11
+ import { hasSchemaValidationNearby } from './utils/schema-validation'
12
+
13
+ /**
14
+ * JSON.parse source classification
15
+ * Determines if the input is user-controlled or internal data
16
+ */
17
+ export type JSONParseSource =
18
+ | 'user_input'
19
+ | 'local_storage'
20
+ | 'database'
21
+ | 'config'
22
+ | 'migration'
23
+ | 'internal'
24
+ | 'test_fixture'
25
+ | 'ui_state'
26
+ | 'unknown'
27
+
28
+ /**
29
+ * Check if file path indicates a low-risk context for JSON.parse
30
+ */
31
+ export function isLowRiskJSONParseFile(filePath: string): JSONParseSource | null {
32
+ // Test/mock files - skip or info only
33
+ if (isTestOrMockFile(filePath)) {
34
+ return 'test_fixture'
35
+ }
36
+
37
+ // Settings/preferences components - internal UI state
38
+ if (/\/(components|pages)\/(settings|preferences|config)/i.test(filePath)) {
39
+ return 'ui_state'
40
+ }
41
+
42
+ // Provider/context files - typically storing state in localStorage
43
+ if (/Provider\.(ts|tsx|js|jsx)$/i.test(filePath)) {
44
+ return 'ui_state'
45
+ }
46
+
47
+ // Modal/Dialog components - typically internal state
48
+ if (/(Modal|Dialog|Settings|Preferences)\.(ts|tsx|js|jsx)$/i.test(filePath)) {
49
+ return 'ui_state'
50
+ }
51
+
52
+ // __mocks__ directory
53
+ if (/__mocks__/i.test(filePath)) {
54
+ return 'test_fixture'
55
+ }
56
+
57
+ // fixtures directory
58
+ if (/\/(fixtures?|stubs?|mocks?)\//i.test(filePath)) {
59
+ return 'test_fixture'
60
+ }
61
+
62
+ // scripts/tools directories (internal tooling)
63
+ if (/\/(scripts?|tools?|cli)\//i.test(filePath)) {
64
+ return 'internal'
65
+ }
66
+
67
+ // Migration files
68
+ if (/migration/i.test(filePath)) {
69
+ return 'migration'
70
+ }
71
+
72
+ // Config files
73
+ if (/\/(config|settings|constants)\.(ts|js)/i.test(filePath)) {
74
+ return 'config'
75
+ }
76
+
77
+ return null
78
+ }
79
+
80
+ /**
81
+ * Check if JSON.parse is parsing a trusted SDK response
82
+ * These are well-defined responses from known APIs and are safe to parse
83
+ */
84
+ export function isTrustedSDKResponse(lineContent: string, content: string): boolean {
85
+ const trustedPatterns = [
86
+ // OpenAI SDK responses
87
+ /JSON\.parse\s*\(\s*(?:response|completion|result|message)\.(?:content|text|data)/i,
88
+ /JSON\.parse\s*\(\s*(?:openai|anthropic|client)\./i,
89
+ // Fetch response.json() result (already parsed by fetch)
90
+ /JSON\.parse\s*\(\s*await\s+.*\.json\s*\(\s*\)\s*\)/i,
91
+ // SDK method results
92
+ /JSON\.parse\s*\(\s*(?:result|response)\.(?:choices|content|data|body)\[/i,
93
+ // AI SDK streaming results
94
+ /JSON\.parse\s*\(\s*(?:chunk|delta|part)\.(?:content|text)/i,
95
+ ]
96
+
97
+ if (trustedPatterns.some(p => p.test(lineContent))) {
98
+ return true
99
+ }
100
+
101
+ // Check surrounding context for SDK usage
102
+ const sdkContextPatterns = [
103
+ /openai\..*\.create/i,
104
+ /anthropic\..*\.create/i,
105
+ /\.chat\.completions/i,
106
+ /\.messages\.create/i,
107
+ ]
108
+
109
+ return sdkContextPatterns.some(p => p.test(content))
110
+ }
111
+
112
+ /**
113
+ * Classify the source of data being passed to JSON.parse
114
+ */
115
+ export function classifyJSONParseSource(
116
+ lineContent: string,
117
+ filePath: string
118
+ ): JSONParseSource {
119
+ // First check file path for low-risk contexts
120
+ const fileBasedSource = isLowRiskJSONParseFile(filePath)
121
+ if (fileBasedSource) {
122
+ return fileBasedSource
123
+ }
124
+
125
+ // User input - potentially dangerous
126
+ const userInputPatterns = [
127
+ /JSON\.parse\s*\(\s*(req|request)\.(body|query|params)/i,
128
+ /JSON\.parse\s*\(\s*event\.(body|queryStringParameters)/i, // AWS Lambda
129
+ /JSON\.parse\s*\(\s*ctx\.(request|body|query)/i, // Koa
130
+ /JSON\.parse\s*\(\s*(input|userInput|rawInput|payload)/i,
131
+ /JSON\.parse\s*\(\s*body\b/i, // Generic 'body' often means request body
132
+ ]
133
+ if (userInputPatterns.some(p => p.test(lineContent))) {
134
+ return 'user_input'
135
+ }
136
+
137
+ // localStorage/sessionStorage - client-side storage
138
+ const storagePatterns = [
139
+ /JSON\.parse\s*\(\s*localStorage\.getItem/i,
140
+ /JSON\.parse\s*\(\s*sessionStorage\.getItem/i,
141
+ /JSON\.parse\s*\(\s*window\.localStorage/i,
142
+ /JSON\.parse\s*\(\s*storage\.get/i,
143
+ /JSON\.parse\s*\(\s*saved\b/i, // Common pattern: const saved = localStorage.getItem(...); JSON.parse(saved)
144
+ /JSON\.parse\s*\(\s*stored\b/i,
145
+ ]
146
+ if (storagePatterns.some(p => p.test(lineContent))) {
147
+ return 'local_storage'
148
+ }
149
+
150
+ // Database results - internal data
151
+ const databasePatterns = [
152
+ /JSON\.parse\s*\(\s*(row|result|record|doc|document)\./i,
153
+ /JSON\.parse\s*\(\s*\w+\.(data|json|metadata|embedding)\)/i,
154
+ /JSON\.parse\s*\(\s*\w+\[['"]?\w+['"]?\]\.(data|json|embedding)/i,
155
+ /JSON\.parse\s*\(\s*item\.\w+\)/i, // ORM iteration: items.map(item => JSON.parse(item.field))
156
+ /JSON\.parse\s*\(\s*\w+\.content\)/i, // Parsing content field from DB
157
+ ]
158
+ if (databasePatterns.some(p => p.test(lineContent))) {
159
+ return 'database'
160
+ }
161
+
162
+ // Editor state, internal caches, UI state
163
+ const internalPatterns = [
164
+ /JSON\.parse\s*\(\s*(state|cache|stored|saved|cached)/i,
165
+ /JSON\.parse\s*\(\s*this\.(state|cache|data)/i,
166
+ /JSON\.parse\s*\(\s*\w+State\)/i,
167
+ /JSON\.parse\s*\(\s*editorState/i,
168
+ /JSON\.parse\s*\(\s*parsed\b/i, // JSON.parse(parsed) - likely already validated
169
+ /JSON\.parse\s*\(\s*settings\b/i, // Settings data
170
+ /JSON\.parse\s*\(\s*preferences\b/i,
171
+ ]
172
+ if (internalPatterns.some(p => p.test(lineContent))) {
173
+ return 'internal'
174
+ }
175
+
176
+ // Node content in editor apps (e.g., noda-os nodes have JSON content)
177
+ if (
178
+ /JSON\.parse\s*\(\s*(node|note|document|entry)\.(content|body|data)\)/i.test(
179
+ lineContent
180
+ )
181
+ ) {
182
+ return 'database'
183
+ }
184
+
185
+ return 'unknown'
186
+ }
187
+
188
+ /**
189
+ * Detect JSON.parse usage with source-aware severity
190
+ * Much smarter than simple pattern matching - considers try/catch and data source
191
+ */
192
+ export function detectJSONParseSafe(
193
+ content: string,
194
+ filePath: string,
195
+ isTestFile: boolean,
196
+ vulnerabilities: Vulnerability[]
197
+ ): void {
198
+ const lines = content.split('\n')
199
+ const jsonParsePattern = /JSON\.parse\s*\(/gi
200
+
201
+ // Track instances per file to aggregate noisy patterns
202
+ const instances: {
203
+ lineNumber: number
204
+ lineContent: string
205
+ source: JSONParseSource
206
+ }[] = []
207
+
208
+ lines.forEach((line, index) => {
209
+ if (isComment(line)) return
210
+
211
+ jsonParsePattern.lastIndex = 0
212
+ if (!jsonParsePattern.test(line)) return
213
+
214
+ const jsonSource = classifyJSONParseSource(line, filePath)
215
+
216
+ // Skip migration files entirely - they're internal tooling
217
+ if (jsonSource === 'migration') return
218
+
219
+ // Skip test fixtures entirely - they're intentionally parsing test data
220
+ if (jsonSource === 'test_fixture') return
221
+
222
+ // Skip trusted SDK responses - these are well-defined and safe to parse
223
+ if (isTrustedSDKResponse(line, content)) return
224
+
225
+ // Check if JSON.parse is inside a try-catch block
226
+ const insideTryCatch =
227
+ isInsideTryCatch(content, index) || hasTryCatchNearby(content, index)
228
+
229
+ // Check if schema validation is applied after JSON.parse
230
+ const hasSchemaValidation = hasSchemaValidationNearby(content, index)
231
+
232
+ // If inside try-catch with safe source, suppress entirely - this is perfectly fine
233
+ if (
234
+ insideTryCatch &&
235
+ ['local_storage', 'database', 'config', 'internal', 'ui_state'].includes(
236
+ jsonSource
237
+ )
238
+ ) {
239
+ return
240
+ }
241
+
242
+ // If schema validation is present, this is properly handled
243
+ if (hasSchemaValidation) {
244
+ return
245
+ }
246
+
247
+ // UI state (settings, providers, modals) - very low risk, aggregate or skip
248
+ if (jsonSource === 'ui_state') {
249
+ // Only track for aggregation, don't report individually
250
+ instances.push({
251
+ lineNumber: index + 1,
252
+ lineContent: line.trim(),
253
+ source: jsonSource,
254
+ })
255
+ return
256
+ }
257
+
258
+ // Determine severity based on source and error handling
259
+ let severity: VulnerabilitySeverity
260
+ let description: string
261
+ let suggestedFix: string
262
+ let confidence: 'high' | 'medium' | 'low' = 'medium'
263
+
264
+ if (insideTryCatch) {
265
+ // Already has error handling
266
+ switch (jsonSource) {
267
+ case 'user_input':
268
+ severity = 'low'
269
+ description =
270
+ 'JSON.parse on user input is wrapped in try-catch. Consider adding schema validation (zod/yup) to validate the parsed structure.'
271
+ suggestedFix =
272
+ 'Add schema validation after parsing: const validated = schema.parse(JSON.parse(input))'
273
+ confidence = 'low'
274
+ break
275
+ default:
276
+ // With try-catch and non-user source, this is fine - don't report
277
+ return
278
+ }
279
+ } else {
280
+ // No try-catch
281
+ switch (jsonSource) {
282
+ case 'user_input':
283
+ severity = 'medium'
284
+ description =
285
+ 'JSON.parse on user input without schema validation. Malformed input will crash; malicious input may have unexpected shape.'
286
+ suggestedFix =
287
+ 'Use a schema validation library (zod, yup, joi): try { const data = schema.parse(JSON.parse(body)) } catch (e) { return 400 }'
288
+ confidence = 'high'
289
+ break
290
+ case 'local_storage':
291
+ severity = 'info'
292
+ description =
293
+ 'JSON.parse on localStorage data. Consider adding try-catch for robustness against corrupted data.'
294
+ suggestedFix =
295
+ 'Wrap in try-catch to handle corrupted localStorage gracefully.'
296
+ confidence = 'low'
297
+ break
298
+ case 'database':
299
+ // Database content parsing is very common and low-risk
300
+ instances.push({
301
+ lineNumber: index + 1,
302
+ lineContent: line.trim(),
303
+ source: jsonSource,
304
+ })
305
+ return // Will be aggregated below
306
+ case 'config':
307
+ case 'internal':
308
+ severity = 'info'
309
+ description = `JSON.parse on ${jsonSource.replace('_', ' ')} data without error handling. Low risk but consider defensive coding.`
310
+ suggestedFix = 'Consider adding try-catch for robustness.'
311
+ confidence = 'low'
312
+ break
313
+ default:
314
+ // Unknown source - track for potential aggregation
315
+ instances.push({
316
+ lineNumber: index + 1,
317
+ lineContent: line.trim(),
318
+ source: jsonSource,
319
+ })
320
+ return // Will be evaluated below based on aggregation
321
+ }
322
+ }
323
+
324
+ // Downgrade test files
325
+ if (isTestFile) {
326
+ severity = 'info'
327
+ confidence = 'low'
328
+ description += ' (in test file)'
329
+ }
330
+
331
+ vulnerabilities.push({
332
+ id: `json-parse-${filePath}-${index + 1}`,
333
+ filePath,
334
+ lineNumber: index + 1,
335
+ lineContent: line.trim(),
336
+ severity,
337
+ category: 'dangerous_function',
338
+ title: 'JSON.parse usage',
339
+ description,
340
+ suggestedFix,
341
+ confidence,
342
+ layer: 2,
343
+ })
344
+ })
345
+
346
+ // Aggregate low-risk JSON.parse instances if there are many
347
+ if (instances.length >= 3) {
348
+ // Create single aggregated finding instead of N individual findings
349
+ const lineNumbers = instances.map(i => i.lineNumber).slice(0, 5)
350
+ const moreText =
351
+ instances.length > 5 ? `... (${instances.length} total)` : ''
352
+
353
+ vulnerabilities.push({
354
+ id: `json-parse-aggregated-${filePath}`,
355
+ filePath,
356
+ lineNumber: instances[0].lineNumber,
357
+ lineContent: `${instances.length} instances across this file`,
358
+ severity: 'info',
359
+ category: 'dangerous_function',
360
+ title: `JSON.parse usage (${instances.length} instances)`,
361
+ description: `JSON.parse detected. Consider adding error handling and schema validation if parsing user input.${isTestFile ? ' (in test file)' : ''}\n\nFound ${instances.length} occurrences at lines: ${lineNumbers.join(', ')}${moreText}`,
362
+ suggestedFix:
363
+ 'Add try-catch for error handling. If parsing user input, add schema validation.',
364
+ confidence: 'low',
365
+ layer: 2,
366
+ })
367
+ } else if (instances.length > 0 && instances.length < 3) {
368
+ // Report individually for small counts
369
+ for (const instance of instances) {
370
+ vulnerabilities.push({
371
+ id: `json-parse-${filePath}-${instance.lineNumber}`,
372
+ filePath,
373
+ lineNumber: instance.lineNumber,
374
+ lineContent: instance.lineContent,
375
+ severity: 'info',
376
+ category: 'dangerous_function',
377
+ title: 'JSON.parse usage',
378
+ description: `JSON.parse on ${instance.source.replace('_', ' ')} data without error handling. Low risk but consider defensive coding.${isTestFile ? ' (in test file)' : ''}`,
379
+ suggestedFix: 'Consider adding try-catch for robustness.',
380
+ confidence: 'low',
381
+ layer: 2,
382
+ })
383
+ }
384
+ }
385
+ }