@oculum/scanner 1.0.13 → 1.0.15

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 (1328) hide show
  1. package/dist/detect/ai-code/index.d.ts +6 -11
  2. package/dist/detect/ai-code/index.d.ts.map +1 -1
  3. package/dist/detect/ai-code/index.js +6 -24
  4. package/dist/detect/ai-code/index.js.map +1 -1
  5. package/dist/detect/ast-rules/agent-tools-ast.d.ts +14 -0
  6. package/dist/detect/ast-rules/agent-tools-ast.d.ts.map +1 -0
  7. package/dist/detect/ast-rules/agent-tools-ast.js +809 -0
  8. package/dist/detect/ast-rules/agent-tools-ast.js.map +1 -0
  9. package/dist/detect/ast-rules/ai-fingerprinting-ast.d.ts +14 -0
  10. package/dist/detect/ast-rules/ai-fingerprinting-ast.d.ts.map +1 -0
  11. package/dist/detect/ast-rules/ai-fingerprinting-ast.js +344 -0
  12. package/dist/detect/ast-rules/ai-fingerprinting-ast.js.map +1 -0
  13. package/dist/detect/ast-rules/auth-patterns-ast.d.ts +14 -0
  14. package/dist/detect/ast-rules/auth-patterns-ast.d.ts.map +1 -0
  15. package/dist/detect/ast-rules/auth-patterns-ast.js +280 -0
  16. package/dist/detect/ast-rules/auth-patterns-ast.js.map +1 -0
  17. package/dist/detect/ast-rules/byok-ast.d.ts +13 -0
  18. package/dist/detect/ast-rules/byok-ast.d.ts.map +1 -0
  19. package/dist/detect/ast-rules/byok-ast.js +180 -0
  20. package/dist/detect/ast-rules/byok-ast.js.map +1 -0
  21. package/dist/detect/ast-rules/child-process-ast.d.ts +13 -0
  22. package/dist/detect/ast-rules/child-process-ast.d.ts.map +1 -0
  23. package/dist/detect/ast-rules/child-process-ast.js +252 -0
  24. package/dist/detect/ast-rules/child-process-ast.js.map +1 -0
  25. package/dist/detect/ast-rules/dangerous-eval-ast.d.ts +13 -0
  26. package/dist/detect/ast-rules/dangerous-eval-ast.d.ts.map +1 -0
  27. package/dist/detect/ast-rules/dangerous-eval-ast.js +218 -0
  28. package/dist/detect/ast-rules/dangerous-eval-ast.js.map +1 -0
  29. package/dist/detect/ast-rules/data-exposure-ast.d.ts +13 -0
  30. package/dist/detect/ast-rules/data-exposure-ast.d.ts.map +1 -0
  31. package/dist/detect/ast-rules/data-exposure-ast.js +158 -0
  32. package/dist/detect/ast-rules/data-exposure-ast.js.map +1 -0
  33. package/dist/detect/ast-rules/dom-xss-ast.d.ts +14 -0
  34. package/dist/detect/ast-rules/dom-xss-ast.d.ts.map +1 -0
  35. package/dist/detect/ast-rules/dom-xss-ast.js +217 -0
  36. package/dist/detect/ast-rules/dom-xss-ast.js.map +1 -0
  37. package/dist/detect/ast-rules/endpoint-protection-ast.d.ts +13 -0
  38. package/dist/detect/ast-rules/endpoint-protection-ast.d.ts.map +1 -0
  39. package/dist/detect/ast-rules/endpoint-protection-ast.js +228 -0
  40. package/dist/detect/ast-rules/endpoint-protection-ast.js.map +1 -0
  41. package/dist/detect/ast-rules/entropy-ast.d.ts +17 -0
  42. package/dist/detect/ast-rules/entropy-ast.d.ts.map +1 -0
  43. package/dist/detect/ast-rules/entropy-ast.js +265 -0
  44. package/dist/detect/ast-rules/entropy-ast.js.map +1 -0
  45. package/dist/detect/ast-rules/flask-debug-ast.d.ts +10 -0
  46. package/dist/detect/ast-rules/flask-debug-ast.d.ts.map +1 -0
  47. package/dist/detect/ast-rules/flask-debug-ast.js +125 -0
  48. package/dist/detect/ast-rules/flask-debug-ast.js.map +1 -0
  49. package/dist/detect/ast-rules/framework-checks-ast.d.ts +13 -0
  50. package/dist/detect/ast-rules/framework-checks-ast.d.ts.map +1 -0
  51. package/dist/detect/ast-rules/framework-checks-ast.js +185 -0
  52. package/dist/detect/ast-rules/framework-checks-ast.js.map +1 -0
  53. package/dist/detect/ast-rules/helpers/call-analysis.d.ts +62 -0
  54. package/dist/detect/ast-rules/helpers/call-analysis.d.ts.map +1 -0
  55. package/dist/detect/ast-rules/helpers/call-analysis.js +217 -0
  56. package/dist/detect/ast-rules/helpers/call-analysis.js.map +1 -0
  57. package/dist/detect/ast-rules/helpers/context-detection.d.ts +33 -0
  58. package/dist/detect/ast-rules/helpers/context-detection.d.ts.map +1 -0
  59. package/dist/detect/ast-rules/helpers/context-detection.js +256 -0
  60. package/dist/detect/ast-rules/helpers/context-detection.js.map +1 -0
  61. package/dist/detect/ast-rules/helpers/control-flow.d.ts +40 -0
  62. package/dist/detect/ast-rules/helpers/control-flow.d.ts.map +1 -0
  63. package/dist/detect/ast-rules/helpers/control-flow.js +174 -0
  64. package/dist/detect/ast-rules/helpers/control-flow.js.map +1 -0
  65. package/dist/detect/ast-rules/helpers/import-analysis.d.ts +43 -0
  66. package/dist/detect/ast-rules/helpers/import-analysis.d.ts.map +1 -0
  67. package/dist/detect/ast-rules/helpers/import-analysis.js +149 -0
  68. package/dist/detect/ast-rules/helpers/import-analysis.js.map +1 -0
  69. package/dist/detect/ast-rules/helpers/index.d.ts +16 -0
  70. package/dist/detect/ast-rules/helpers/index.d.ts.map +1 -0
  71. package/dist/detect/ast-rules/helpers/index.js +112 -0
  72. package/dist/detect/ast-rules/helpers/index.js.map +1 -0
  73. package/dist/detect/ast-rules/helpers/python-helpers.d.ts +215 -0
  74. package/dist/detect/ast-rules/helpers/python-helpers.d.ts.map +1 -0
  75. package/dist/detect/ast-rules/helpers/python-helpers.js +935 -0
  76. package/dist/detect/ast-rules/helpers/python-helpers.js.map +1 -0
  77. package/dist/detect/ast-rules/helpers/scope-analysis.d.ts +50 -0
  78. package/dist/detect/ast-rules/helpers/scope-analysis.d.ts.map +1 -0
  79. package/dist/detect/ast-rules/helpers/scope-analysis.js +194 -0
  80. package/dist/detect/ast-rules/helpers/scope-analysis.js.map +1 -0
  81. package/dist/detect/ast-rules/helpers/string-analysis.d.ts +57 -0
  82. package/dist/detect/ast-rules/helpers/string-analysis.d.ts.map +1 -0
  83. package/dist/detect/ast-rules/helpers/string-analysis.js +184 -0
  84. package/dist/detect/ast-rules/helpers/string-analysis.js.map +1 -0
  85. package/dist/detect/ast-rules/helpers/type-extraction.d.ts +44 -0
  86. package/dist/detect/ast-rules/helpers/type-extraction.d.ts.map +1 -0
  87. package/dist/detect/ast-rules/helpers/type-extraction.js +125 -0
  88. package/dist/detect/ast-rules/helpers/type-extraction.js.map +1 -0
  89. package/dist/detect/ast-rules/helpers/user-input.d.ts +35 -0
  90. package/dist/detect/ast-rules/helpers/user-input.d.ts.map +1 -0
  91. package/dist/detect/ast-rules/helpers/user-input.js +243 -0
  92. package/dist/detect/ast-rules/helpers/user-input.js.map +1 -0
  93. package/dist/detect/ast-rules/index.d.ts +112 -0
  94. package/dist/detect/ast-rules/index.d.ts.map +1 -0
  95. package/dist/detect/ast-rules/index.js +232 -0
  96. package/dist/detect/ast-rules/index.js.map +1 -0
  97. package/dist/detect/ast-rules/json-parse-ast.d.ts +13 -0
  98. package/dist/detect/ast-rules/json-parse-ast.d.ts.map +1 -0
  99. package/dist/detect/ast-rules/json-parse-ast.js +143 -0
  100. package/dist/detect/ast-rules/json-parse-ast.js.map +1 -0
  101. package/dist/detect/ast-rules/log-injection-ast.d.ts +14 -0
  102. package/dist/detect/ast-rules/log-injection-ast.d.ts.map +1 -0
  103. package/dist/detect/ast-rules/log-injection-ast.js +235 -0
  104. package/dist/detect/ast-rules/log-injection-ast.js.map +1 -0
  105. package/dist/detect/ast-rules/logic-gates-ast.d.ts +14 -0
  106. package/dist/detect/ast-rules/logic-gates-ast.d.ts.map +1 -0
  107. package/dist/detect/ast-rules/logic-gates-ast.js +312 -0
  108. package/dist/detect/ast-rules/logic-gates-ast.js.map +1 -0
  109. package/dist/detect/ast-rules/mcp-security-ast.d.ts +14 -0
  110. package/dist/detect/ast-rules/mcp-security-ast.d.ts.map +1 -0
  111. package/dist/detect/ast-rules/mcp-security-ast.js +755 -0
  112. package/dist/detect/ast-rules/mcp-security-ast.js.map +1 -0
  113. package/dist/detect/ast-rules/model-supply-chain-ast.d.ts +13 -0
  114. package/dist/detect/ast-rules/model-supply-chain-ast.d.ts.map +1 -0
  115. package/dist/detect/ast-rules/model-supply-chain-ast.js +188 -0
  116. package/dist/detect/ast-rules/model-supply-chain-ast.js.map +1 -0
  117. package/dist/detect/ast-rules/package-hallucination-ast.d.ts +13 -0
  118. package/dist/detect/ast-rules/package-hallucination-ast.d.ts.map +1 -0
  119. package/dist/detect/ast-rules/package-hallucination-ast.js +607 -0
  120. package/dist/detect/ast-rules/package-hallucination-ast.js.map +1 -0
  121. package/dist/detect/ast-rules/prompt-hygiene-ast.d.ts +15 -0
  122. package/dist/detect/ast-rules/prompt-hygiene-ast.d.ts.map +1 -0
  123. package/dist/detect/ast-rules/prompt-hygiene-ast.js +332 -0
  124. package/dist/detect/ast-rules/prompt-hygiene-ast.js.map +1 -0
  125. package/dist/detect/ast-rules/rag-safety-ast.d.ts +18 -0
  126. package/dist/detect/ast-rules/rag-safety-ast.d.ts.map +1 -0
  127. package/dist/detect/ast-rules/rag-safety-ast.js +640 -0
  128. package/dist/detect/ast-rules/rag-safety-ast.js.map +1 -0
  129. package/dist/detect/ast-rules/request-validation-ast.d.ts +13 -0
  130. package/dist/detect/ast-rules/request-validation-ast.d.ts.map +1 -0
  131. package/dist/detect/ast-rules/request-validation-ast.js +116 -0
  132. package/dist/detect/ast-rules/request-validation-ast.js.map +1 -0
  133. package/dist/detect/ast-rules/risky-imports-ast.d.ts +14 -0
  134. package/dist/detect/ast-rules/risky-imports-ast.d.ts.map +1 -0
  135. package/dist/detect/ast-rules/risky-imports-ast.js +114 -0
  136. package/dist/detect/ast-rules/risky-imports-ast.js.map +1 -0
  137. package/dist/detect/ast-rules/schema-validation-ast.d.ts +14 -0
  138. package/dist/detect/ast-rules/schema-validation-ast.d.ts.map +1 -0
  139. package/dist/detect/ast-rules/schema-validation-ast.js +233 -0
  140. package/dist/detect/ast-rules/schema-validation-ast.js.map +1 -0
  141. package/dist/detect/ast-rules/secret-patterns-ast.d.ts +17 -0
  142. package/dist/detect/ast-rules/secret-patterns-ast.d.ts.map +1 -0
  143. package/dist/detect/ast-rules/secret-patterns-ast.js +199 -0
  144. package/dist/detect/ast-rules/secret-patterns-ast.js.map +1 -0
  145. package/dist/detect/ast-rules/security-headers-ast.d.ts +14 -0
  146. package/dist/detect/ast-rules/security-headers-ast.d.ts.map +1 -0
  147. package/dist/detect/ast-rules/security-headers-ast.js +187 -0
  148. package/dist/detect/ast-rules/security-headers-ast.js.map +1 -0
  149. package/dist/detect/ast-rules/sql-injection-ast.d.ts +17 -0
  150. package/dist/detect/ast-rules/sql-injection-ast.d.ts.map +1 -0
  151. package/dist/detect/ast-rules/sql-injection-ast.js +497 -0
  152. package/dist/detect/ast-rules/sql-injection-ast.js.map +1 -0
  153. package/dist/detect/ast-rules/ssrf-ast.d.ts +14 -0
  154. package/dist/detect/ast-rules/ssrf-ast.d.ts.map +1 -0
  155. package/dist/detect/ast-rules/ssrf-ast.js +573 -0
  156. package/dist/detect/ast-rules/ssrf-ast.js.map +1 -0
  157. package/dist/detect/ast-rules/taint-fix-templates.d.ts +18 -0
  158. package/dist/detect/ast-rules/taint-fix-templates.d.ts.map +1 -0
  159. package/dist/detect/ast-rules/taint-fix-templates.js +92 -0
  160. package/dist/detect/ast-rules/taint-fix-templates.js.map +1 -0
  161. package/dist/detect/ast-rules/taint-flow-ast.d.ts +24 -0
  162. package/dist/detect/ast-rules/taint-flow-ast.d.ts.map +1 -0
  163. package/dist/detect/ast-rules/taint-flow-ast.js +340 -0
  164. package/dist/detect/ast-rules/taint-flow-ast.js.map +1 -0
  165. package/dist/detect/ast-rules/variables-ast.d.ts +24 -0
  166. package/dist/detect/ast-rules/variables-ast.d.ts.map +1 -0
  167. package/dist/detect/ast-rules/variables-ast.js +362 -0
  168. package/dist/detect/ast-rules/variables-ast.js.map +1 -0
  169. package/dist/detect/ast-rules/weak-crypto-ast.d.ts +15 -0
  170. package/dist/detect/ast-rules/weak-crypto-ast.d.ts.map +1 -0
  171. package/dist/detect/ast-rules/weak-crypto-ast.js +406 -0
  172. package/dist/detect/ast-rules/weak-crypto-ast.js.map +1 -0
  173. package/dist/detect/ast-rules/xxe-ast.d.ts +13 -0
  174. package/dist/detect/ast-rules/xxe-ast.d.ts.map +1 -0
  175. package/dist/detect/ast-rules/xxe-ast.js +157 -0
  176. package/dist/detect/ast-rules/xxe-ast.js.map +1 -0
  177. package/dist/detect/config/agent-skill-injection.d.ts.map +1 -1
  178. package/dist/detect/config/agent-skill-injection.js +2 -24
  179. package/dist/detect/config/agent-skill-injection.js.map +1 -1
  180. package/dist/detect/config/index.d.ts +1 -0
  181. package/dist/detect/config/index.d.ts.map +1 -1
  182. package/dist/detect/config/index.js +3 -1
  183. package/dist/detect/config/index.js.map +1 -1
  184. package/dist/detect/config/osv-check.d.ts.map +1 -1
  185. package/dist/detect/config/osv-check.js +6 -1
  186. package/dist/detect/config/osv-check.js.map +1 -1
  187. package/dist/detect/config/package-check.d.ts.map +1 -1
  188. package/dist/detect/config/package-check.js +6 -1
  189. package/dist/detect/config/package-check.js.map +1 -1
  190. package/dist/detect/config/rules-file-backdoor.d.ts +36 -0
  191. package/dist/detect/config/rules-file-backdoor.d.ts.map +1 -0
  192. package/dist/detect/config/rules-file-backdoor.js +379 -0
  193. package/dist/detect/config/rules-file-backdoor.js.map +1 -0
  194. package/dist/detect/index.d.ts +43 -6
  195. package/dist/detect/index.d.ts.map +1 -1
  196. package/dist/detect/index.js +70 -7
  197. package/dist/detect/index.js.map +1 -1
  198. package/dist/detect/secrets/config-audit.d.ts +5 -0
  199. package/dist/detect/secrets/config-audit.d.ts.map +1 -1
  200. package/dist/detect/secrets/config-audit.js +131 -3
  201. package/dist/detect/secrets/config-audit.js.map +1 -1
  202. package/dist/detect/secrets/entropy.d.ts.map +1 -1
  203. package/dist/detect/secrets/entropy.js +180 -0
  204. package/dist/detect/secrets/entropy.js.map +1 -1
  205. package/dist/detect/secrets/index.d.ts +0 -2
  206. package/dist/detect/secrets/index.d.ts.map +1 -1
  207. package/dist/detect/secrets/index.js +7 -17
  208. package/dist/detect/secrets/index.js.map +1 -1
  209. package/dist/detect/structural/index.d.ts +15 -28
  210. package/dist/detect/structural/index.d.ts.map +1 -1
  211. package/dist/detect/structural/index.js +20 -497
  212. package/dist/detect/structural/index.js.map +1 -1
  213. package/dist/index.d.ts +3 -0
  214. package/dist/index.d.ts.map +1 -1
  215. package/dist/index.js +9 -1
  216. package/dist/index.js.map +1 -1
  217. package/dist/model/auth-helper-detector.d.ts.map +1 -1
  218. package/dist/model/auth-helper-detector.js +2 -7
  219. package/dist/model/auth-helper-detector.js.map +1 -1
  220. package/dist/model/import-resolver.d.ts.map +1 -1
  221. package/dist/model/import-resolver.js +94 -0
  222. package/dist/model/import-resolver.js.map +1 -1
  223. package/dist/model/imported-auth-detector.js +8 -8
  224. package/dist/model/imported-auth-detector.js.map +1 -1
  225. package/dist/model/index.d.ts +8 -0
  226. package/dist/model/index.d.ts.map +1 -1
  227. package/dist/model/index.js +198 -73
  228. package/dist/model/index.js.map +1 -1
  229. package/dist/model/module-graph.d.ts.map +1 -1
  230. package/dist/model/module-graph.js +22 -9
  231. package/dist/model/module-graph.js.map +1 -1
  232. package/dist/model/project-context.d.ts +1 -1
  233. package/dist/model/project-context.d.ts.map +1 -1
  234. package/dist/model/project-context.js +34 -0
  235. package/dist/model/project-context.js.map +1 -1
  236. package/dist/model/route-auth-resolver.d.ts.map +1 -1
  237. package/dist/model/route-auth-resolver.js +17 -2
  238. package/dist/model/route-auth-resolver.js.map +1 -1
  239. package/dist/model/route-discovery/index.js +1 -1
  240. package/dist/model/route-discovery/index.js.map +1 -1
  241. package/dist/model/route-discovery/nextjs.js +1 -1
  242. package/dist/model/route-discovery/nextjs.js.map +1 -1
  243. package/dist/model/route-discovery/python.d.ts +6 -3
  244. package/dist/model/route-discovery/python.d.ts.map +1 -1
  245. package/dist/model/route-discovery/python.js +132 -9
  246. package/dist/model/route-discovery/python.js.map +1 -1
  247. package/dist/model/route-discovery/types.d.ts +1 -1
  248. package/dist/model/route-discovery/types.d.ts.map +1 -1
  249. package/dist/model/route-discovery/utils.d.ts +8 -0
  250. package/dist/model/route-discovery/utils.d.ts.map +1 -1
  251. package/dist/model/route-discovery/utils.js +70 -0
  252. package/dist/model/route-discovery/utils.js.map +1 -1
  253. package/dist/model/taint-types.d.ts +0 -4
  254. package/dist/model/taint-types.d.ts.map +1 -1
  255. package/dist/parse/ast.d.ts +58 -0
  256. package/dist/parse/ast.d.ts.map +1 -0
  257. package/dist/parse/ast.js +230 -0
  258. package/dist/parse/ast.js.map +1 -0
  259. package/dist/parse/call-graph.d.ts +41 -0
  260. package/dist/parse/call-graph.d.ts.map +1 -0
  261. package/dist/parse/call-graph.js +386 -0
  262. package/dist/parse/call-graph.js.map +1 -0
  263. package/dist/parse/file-classifier.d.ts +11 -0
  264. package/dist/parse/file-classifier.d.ts.map +1 -1
  265. package/dist/parse/file-classifier.js +63 -15
  266. package/dist/parse/file-classifier.js.map +1 -1
  267. package/dist/parse/node-index.d.ts +32 -0
  268. package/dist/parse/node-index.d.ts.map +1 -0
  269. package/dist/parse/node-index.js +103 -0
  270. package/dist/parse/node-index.js.map +1 -0
  271. package/dist/parse/type-extractor.d.ts +50 -0
  272. package/dist/parse/type-extractor.d.ts.map +1 -0
  273. package/dist/parse/type-extractor.js +243 -0
  274. package/dist/parse/type-extractor.js.map +1 -0
  275. package/dist/pipeline/config.d.ts +10 -2
  276. package/dist/pipeline/config.d.ts.map +1 -1
  277. package/dist/pipeline/config.js.map +1 -1
  278. package/dist/pipeline/index.d.ts +3 -3
  279. package/dist/pipeline/index.d.ts.map +1 -1
  280. package/dist/pipeline/index.js +214 -65
  281. package/dist/pipeline/index.js.map +1 -1
  282. package/dist/pipeline/modes/incremental.d.ts.map +1 -1
  283. package/dist/pipeline/modes/incremental.js +2 -7
  284. package/dist/pipeline/modes/incremental.js.map +1 -1
  285. package/dist/postprocess/dedup.d.ts +5 -2
  286. package/dist/postprocess/dedup.d.ts.map +1 -1
  287. package/dist/postprocess/dedup.js +47 -16
  288. package/dist/postprocess/dedup.js.map +1 -1
  289. package/dist/report/build-result.d.ts +9 -4
  290. package/dist/report/build-result.d.ts.map +1 -1
  291. package/dist/report/build-result.js +15 -4
  292. package/dist/report/build-result.js.map +1 -1
  293. package/dist/report/formatters/cli-terminal.d.ts +1 -1
  294. package/dist/report/formatters/cli-terminal.d.ts.map +1 -1
  295. package/dist/report/formatters/cli-terminal.js +434 -231
  296. package/dist/report/formatters/cli-terminal.js.map +1 -1
  297. package/dist/report/sanitize.d.ts +10 -0
  298. package/dist/report/sanitize.d.ts.map +1 -0
  299. package/dist/report/sanitize.js +19 -0
  300. package/dist/report/sanitize.js.map +1 -0
  301. package/dist/score/adjustments.d.ts +20 -2
  302. package/dist/score/adjustments.d.ts.map +1 -1
  303. package/dist/score/adjustments.js +108 -37
  304. package/dist/score/adjustments.js.map +1 -1
  305. package/dist/score/confidence.d.ts +6 -0
  306. package/dist/score/confidence.d.ts.map +1 -1
  307. package/dist/score/confidence.js +10 -4
  308. package/dist/score/confidence.js.map +1 -1
  309. package/dist/score/evidence.d.ts +25 -0
  310. package/dist/score/evidence.d.ts.map +1 -0
  311. package/dist/score/evidence.js +51 -0
  312. package/dist/score/evidence.js.map +1 -0
  313. package/dist/score/index.d.ts +3 -1
  314. package/dist/score/index.d.ts.map +1 -1
  315. package/dist/score/index.js +25 -50
  316. package/dist/score/index.js.map +1 -1
  317. package/dist/score/types.d.ts +5 -1
  318. package/dist/score/types.d.ts.map +1 -1
  319. package/dist/shared/category-filter.d.ts.map +1 -1
  320. package/dist/shared/category-filter.js +12 -0
  321. package/dist/shared/category-filter.js.map +1 -1
  322. package/dist/shared/regex-utils.d.ts +3 -0
  323. package/dist/shared/regex-utils.d.ts.map +1 -0
  324. package/dist/shared/regex-utils.js +8 -0
  325. package/dist/shared/regex-utils.js.map +1 -0
  326. package/dist/shared/registry-clients.d.ts +7 -0
  327. package/dist/shared/registry-clients.d.ts.map +1 -1
  328. package/dist/shared/registry-clients.js +94 -17
  329. package/dist/shared/registry-clients.js.map +1 -1
  330. package/dist/shared/rules/metadata.d.ts.map +1 -1
  331. package/dist/shared/rules/metadata.js +17 -0
  332. package/dist/shared/rules/metadata.js.map +1 -1
  333. package/dist/shared/types.d.ts +60 -16
  334. package/dist/shared/types.d.ts.map +1 -1
  335. package/dist/shared/types.js +38 -21
  336. package/dist/shared/types.js.map +1 -1
  337. package/dist/taint/async-flow.d.ts +44 -0
  338. package/dist/taint/async-flow.d.ts.map +1 -0
  339. package/dist/taint/async-flow.js +271 -0
  340. package/dist/taint/async-flow.js.map +1 -0
  341. package/dist/taint/cfg-builder.d.ts +35 -0
  342. package/dist/taint/cfg-builder.d.ts.map +1 -0
  343. package/dist/taint/cfg-builder.js +980 -0
  344. package/dist/taint/cfg-builder.js.map +1 -0
  345. package/dist/taint/cfg-types.d.ts +76 -0
  346. package/dist/taint/cfg-types.d.ts.map +1 -0
  347. package/dist/taint/cfg-types.js +13 -0
  348. package/dist/taint/cfg-types.js.map +1 -0
  349. package/dist/taint/constant-propagation.d.ts +34 -0
  350. package/dist/taint/constant-propagation.d.ts.map +1 -0
  351. package/dist/taint/constant-propagation.js +164 -0
  352. package/dist/taint/constant-propagation.js.map +1 -0
  353. package/dist/taint/cross-file-analyzer.d.ts +27 -0
  354. package/dist/taint/cross-file-analyzer.d.ts.map +1 -0
  355. package/dist/taint/cross-file-analyzer.js +99 -0
  356. package/dist/taint/cross-file-analyzer.js.map +1 -0
  357. package/dist/taint/cross-file-index.d.ts +59 -0
  358. package/dist/taint/cross-file-index.d.ts.map +1 -0
  359. package/dist/taint/cross-file-index.js +183 -0
  360. package/dist/taint/cross-file-index.js.map +1 -0
  361. package/dist/taint/def-use.d.ts +27 -0
  362. package/dist/taint/def-use.d.ts.map +1 -0
  363. package/dist/taint/def-use.js +519 -0
  364. package/dist/taint/def-use.js.map +1 -0
  365. package/dist/taint/file-analysis-cache.d.ts +47 -0
  366. package/dist/taint/file-analysis-cache.d.ts.map +1 -0
  367. package/dist/taint/file-analysis-cache.js +107 -0
  368. package/dist/taint/file-analysis-cache.js.map +1 -0
  369. package/dist/taint/framework-models.d.ts +77 -0
  370. package/dist/taint/framework-models.d.ts.map +1 -0
  371. package/dist/taint/framework-models.js +258 -0
  372. package/dist/taint/framework-models.js.map +1 -0
  373. package/dist/taint/helpers.d.ts +31 -0
  374. package/dist/taint/helpers.d.ts.map +1 -0
  375. package/dist/taint/helpers.js +130 -0
  376. package/dist/taint/helpers.js.map +1 -0
  377. package/dist/taint/index.d.ts +28 -0
  378. package/dist/taint/index.d.ts.map +1 -0
  379. package/dist/taint/index.js +77 -0
  380. package/dist/taint/index.js.map +1 -0
  381. package/dist/taint/llm-registry.d.ts +47 -0
  382. package/dist/taint/llm-registry.d.ts.map +1 -0
  383. package/dist/taint/llm-registry.js +152 -0
  384. package/dist/taint/llm-registry.js.map +1 -0
  385. package/dist/taint/llm-risk-scoring.d.ts +54 -0
  386. package/dist/taint/llm-risk-scoring.d.ts.map +1 -0
  387. package/dist/taint/llm-risk-scoring.js +376 -0
  388. package/dist/taint/llm-risk-scoring.js.map +1 -0
  389. package/dist/taint/propagation-types.d.ts +104 -0
  390. package/dist/taint/propagation-types.d.ts.map +1 -0
  391. package/dist/taint/propagation-types.js +98 -0
  392. package/dist/taint/propagation-types.js.map +1 -0
  393. package/dist/taint/propagation.d.ts +111 -0
  394. package/dist/taint/propagation.d.ts.map +1 -0
  395. package/dist/taint/propagation.js +1576 -0
  396. package/dist/taint/propagation.js.map +1 -0
  397. package/dist/taint/sanitizer-registry.d.ts +26 -0
  398. package/dist/taint/sanitizer-registry.d.ts.map +1 -0
  399. package/dist/taint/sanitizer-registry.js +422 -0
  400. package/dist/taint/sanitizer-registry.js.map +1 -0
  401. package/dist/taint/sink-classifier.d.ts +27 -0
  402. package/dist/taint/sink-classifier.d.ts.map +1 -0
  403. package/dist/taint/sink-classifier.js +1166 -0
  404. package/dist/taint/sink-classifier.js.map +1 -0
  405. package/dist/taint/source-classifier.d.ts +29 -0
  406. package/dist/taint/source-classifier.d.ts.map +1 -0
  407. package/dist/taint/source-classifier.js +814 -0
  408. package/dist/taint/source-classifier.js.map +1 -0
  409. package/dist/taint/taint-analyzer.d.ts +33 -0
  410. package/dist/taint/taint-analyzer.d.ts.map +1 -0
  411. package/dist/taint/taint-analyzer.js +88 -0
  412. package/dist/taint/taint-analyzer.js.map +1 -0
  413. package/dist/taint/taint-summary.d.ts +37 -0
  414. package/dist/taint/taint-summary.d.ts.map +1 -0
  415. package/dist/taint/taint-summary.js +293 -0
  416. package/dist/taint/taint-summary.js.map +1 -0
  417. package/dist/taint/types.d.ts +47 -0
  418. package/dist/taint/types.d.ts.map +1 -0
  419. package/dist/taint/types.js +19 -0
  420. package/dist/taint/types.js.map +1 -0
  421. package/dist/tiers.d.ts +2 -2
  422. package/dist/tiers.js +1 -1
  423. package/dist/validate/clients.d.ts +2 -1
  424. package/dist/validate/clients.d.ts.map +1 -1
  425. package/dist/validate/clients.js +3 -2
  426. package/dist/validate/clients.js.map +1 -1
  427. package/dist/validate/index.d.ts +5 -6
  428. package/dist/validate/index.d.ts.map +1 -1
  429. package/dist/validate/index.js +22 -21
  430. package/dist/validate/index.js.map +1 -1
  431. package/dist/validate/prompts/modules/ai-patterns.d.ts +1 -1
  432. package/dist/validate/prompts/modules/ai-patterns.d.ts.map +1 -1
  433. package/dist/validate/prompts/modules/ai-patterns.js +16 -0
  434. package/dist/validate/prompts/modules/ai-patterns.js.map +1 -1
  435. package/dist/validate/prompts/modules/common.d.ts +1 -1
  436. package/dist/validate/prompts/modules/common.d.ts.map +1 -1
  437. package/dist/validate/prompts/modules/common.js +12 -3
  438. package/dist/validate/prompts/modules/common.js.map +1 -1
  439. package/dist/validate/providers/anthropic.d.ts +4 -4
  440. package/dist/validate/providers/anthropic.d.ts.map +1 -1
  441. package/dist/validate/providers/anthropic.js +85 -58
  442. package/dist/validate/providers/anthropic.js.map +1 -1
  443. package/dist/validate/providers/openai.d.ts +4 -4
  444. package/dist/validate/providers/openai.d.ts.map +1 -1
  445. package/dist/validate/providers/openai.js +149 -99
  446. package/dist/validate/providers/openai.js.map +1 -1
  447. package/dist/validate/request-builder.d.ts +2 -8
  448. package/dist/validate/request-builder.d.ts.map +1 -1
  449. package/dist/validate/request-builder.js +4 -34
  450. package/dist/validate/request-builder.js.map +1 -1
  451. package/dist/validate/types.d.ts +9 -0
  452. package/dist/validate/types.d.ts.map +1 -1
  453. package/dist/validate/types.js.map +1 -1
  454. package/dist/validate/utils/path-helpers.js +2 -2
  455. package/dist/validate/utils/path-helpers.js.map +1 -1
  456. package/dist/validate/utils/response-parser.d.ts +10 -0
  457. package/dist/validate/utils/response-parser.d.ts.map +1 -1
  458. package/dist/validate/utils/response-parser.js +21 -2
  459. package/dist/validate/utils/response-parser.js.map +1 -1
  460. package/dist/validate/utils/retry.d.ts.map +1 -1
  461. package/dist/validate/utils/retry.js +19 -4
  462. package/dist/validate/utils/retry.js.map +1 -1
  463. package/package.json +7 -4
  464. package/src/__tests__/benchmark/fixtures/layer2/ai-execution-sinks.ts +1 -1
  465. package/src/__tests__/benchmark/planted-benchmark.test.ts +337 -0
  466. package/src/__tests__/benchmark/utils/test-runner.ts +38 -4
  467. package/src/__tests__/category-filter.test.ts +5 -1
  468. package/src/__tests__/context-engine/route-discovery/python.test.ts +726 -0
  469. package/src/__tests__/detect/ast-rules.test.ts +1043 -0
  470. package/src/__tests__/detect/offline-mode.test.ts +147 -0
  471. package/src/__tests__/detect/postinstall-enrichment.test.ts +300 -0
  472. package/src/__tests__/detect/python-ast-rules.test.ts +569 -0
  473. package/src/__tests__/detect/python-helpers.test.ts +536 -0
  474. package/src/__tests__/detect/python-sast-rules.test.ts +453 -0
  475. package/src/__tests__/detect/rules-file-backdoor-decoders.test.ts +151 -0
  476. package/src/__tests__/detect/rules-file-backdoor.test.ts +284 -0
  477. package/src/__tests__/detect/taint-fix-templates.test.ts +150 -0
  478. package/src/__tests__/detect/taint-path-serialization.test.ts +170 -0
  479. package/src/__tests__/parse/call-graph.test.ts +300 -0
  480. package/src/__tests__/parse/python-parser.test.ts +274 -0
  481. package/src/__tests__/regression/known-false-positives.test.ts +491 -9
  482. package/src/__tests__/regression/rules-file-backdoor.test.ts +137 -0
  483. package/src/__tests__/score/adjustments.test.ts +34 -16
  484. package/src/__tests__/score/confidence.test.ts +84 -57
  485. package/src/__tests__/score/evidence-scoring.test.ts +249 -0
  486. package/src/__tests__/score/evidence.test.ts +144 -0
  487. package/src/__tests__/score/scoring-integration.test.ts +56 -34
  488. package/src/__tests__/score/taint-adjustments.test.ts +14 -228
  489. package/src/__tests__/snapshots/__snapshots__/scan-depth.test.ts.snap +65 -59
  490. package/src/__tests__/snapshots/scan-depth.test.ts +39 -7
  491. package/src/__tests__/taint/async-flow.test.ts +247 -0
  492. package/src/__tests__/taint/cfg-builder.test.ts +835 -0
  493. package/src/__tests__/taint/constant-propagation.test.ts +302 -0
  494. package/src/__tests__/taint/cross-file-index.test.ts +683 -0
  495. package/src/__tests__/taint/cross-file-integration.test.ts +275 -0
  496. package/src/__tests__/taint/cross-file-propagation.test.ts +910 -0
  497. package/src/__tests__/taint/def-use.test.ts +132 -0
  498. package/src/__tests__/taint/field-sensitive-sinks.test.ts +179 -0
  499. package/src/__tests__/taint/field-sensitivity.test.ts +342 -0
  500. package/src/__tests__/taint/file-analysis-cache.test.ts +290 -0
  501. package/src/__tests__/taint/framework-models.test.ts +227 -0
  502. package/src/__tests__/taint/llm-flow-graph.test.ts +850 -0
  503. package/src/__tests__/taint/llm-risk-scoring.test.ts +439 -0
  504. package/src/__tests__/taint/performance-parity.test.ts +315 -0
  505. package/src/__tests__/taint/propagation.test.ts +621 -0
  506. package/src/__tests__/taint/python-cross-file.test.ts +494 -0
  507. package/src/__tests__/taint/python-taint.test.ts +1344 -0
  508. package/src/__tests__/taint/sanitizer-registry.test.ts +304 -0
  509. package/src/__tests__/taint/sanitizer-regression.test.ts +111 -0
  510. package/src/__tests__/taint/sink-classifier.test.ts +537 -0
  511. package/src/__tests__/taint/source-classifier.test.ts +367 -0
  512. package/src/__tests__/taint/taint-pipeline.test.ts +418 -0
  513. package/src/__tests__/taint/taint-smoke.test.ts +400 -0
  514. package/src/__tests__/taint/taint-summary.test.ts +472 -0
  515. package/src/detect/ai-code/index.ts +6 -11
  516. package/src/detect/ast-rules/agent-tools-ast.ts +861 -0
  517. package/src/detect/ast-rules/ai-fingerprinting-ast.ts +451 -0
  518. package/src/detect/ast-rules/auth-patterns-ast.ts +304 -0
  519. package/src/detect/ast-rules/byok-ast.ts +195 -0
  520. package/src/detect/ast-rules/child-process-ast.ts +276 -0
  521. package/src/detect/ast-rules/dangerous-eval-ast.ts +227 -0
  522. package/src/detect/ast-rules/data-exposure-ast.ts +162 -0
  523. package/src/detect/ast-rules/dom-xss-ast.ts +260 -0
  524. package/src/detect/ast-rules/endpoint-protection-ast.ts +231 -0
  525. package/src/detect/ast-rules/entropy-ast.ts +268 -0
  526. package/src/detect/ast-rules/flask-debug-ast.ts +148 -0
  527. package/src/detect/ast-rules/framework-checks-ast.ts +200 -0
  528. package/src/detect/ast-rules/helpers/call-analysis.ts +256 -0
  529. package/src/detect/ast-rules/helpers/context-detection.ts +277 -0
  530. package/src/detect/ast-rules/helpers/control-flow.ts +179 -0
  531. package/src/detect/ast-rules/helpers/import-analysis.ts +185 -0
  532. package/src/detect/ast-rules/helpers/index.ts +133 -0
  533. package/src/detect/ast-rules/helpers/python-helpers.ts +1054 -0
  534. package/src/detect/ast-rules/helpers/scope-analysis.ts +224 -0
  535. package/src/detect/ast-rules/helpers/string-analysis.ts +215 -0
  536. package/src/detect/ast-rules/helpers/type-extraction.ts +138 -0
  537. package/src/detect/ast-rules/helpers/user-input.ts +256 -0
  538. package/src/detect/ast-rules/index.ts +311 -0
  539. package/src/detect/ast-rules/json-parse-ast.ts +162 -0
  540. package/src/detect/ast-rules/log-injection-ast.ts +243 -0
  541. package/src/detect/ast-rules/logic-gates-ast.ts +343 -0
  542. package/src/detect/ast-rules/mcp-security-ast.ts +808 -0
  543. package/src/detect/ast-rules/model-supply-chain-ast.ts +202 -0
  544. package/src/detect/ast-rules/package-hallucination-ast.ts +664 -0
  545. package/src/detect/ast-rules/prompt-hygiene-ast.ts +329 -0
  546. package/src/detect/ast-rules/rag-safety-ast.ts +689 -0
  547. package/src/detect/ast-rules/request-validation-ast.ts +122 -0
  548. package/src/detect/ast-rules/risky-imports-ast.ts +133 -0
  549. package/src/detect/ast-rules/schema-validation-ast.ts +244 -0
  550. package/src/detect/ast-rules/secret-patterns-ast.ts +223 -0
  551. package/src/detect/ast-rules/security-headers-ast.ts +206 -0
  552. package/src/detect/ast-rules/sql-injection-ast.ts +614 -0
  553. package/src/detect/ast-rules/ssrf-ast.ts +601 -0
  554. package/src/detect/ast-rules/taint-fix-templates.ts +108 -0
  555. package/src/detect/ast-rules/taint-flow-ast.ts +416 -0
  556. package/src/detect/ast-rules/variables-ast.ts +446 -0
  557. package/src/detect/ast-rules/weak-crypto-ast.ts +441 -0
  558. package/src/detect/ast-rules/xxe-ast.ts +184 -0
  559. package/src/detect/config/agent-skill-injection.ts +2 -24
  560. package/src/detect/config/index.ts +1 -0
  561. package/src/detect/config/osv-check.ts +6 -1
  562. package/src/detect/config/package-check.ts +6 -1
  563. package/src/detect/config/rules-file-backdoor.ts +438 -0
  564. package/src/detect/index.ts +146 -52
  565. package/src/detect/secrets/config-audit.ts +148 -3
  566. package/src/detect/secrets/entropy.ts +195 -0
  567. package/src/detect/secrets/index.ts +7 -16
  568. package/src/detect/structural/index.ts +23 -566
  569. package/src/index.ts +7 -0
  570. package/src/model/auth-helper-detector.ts +1 -7
  571. package/src/model/import-resolver.ts +104 -0
  572. package/src/model/imported-auth-detector.ts +1 -1
  573. package/src/model/index.ts +240 -80
  574. package/src/model/module-graph.ts +17 -5
  575. package/src/model/project-context.ts +28 -1
  576. package/src/model/route-auth-resolver.ts +18 -3
  577. package/src/model/route-discovery/index.ts +1 -1
  578. package/src/model/route-discovery/nextjs.ts +1 -1
  579. package/src/model/route-discovery/python.ts +156 -9
  580. package/src/model/route-discovery/types.ts +1 -1
  581. package/src/model/route-discovery/utils.ts +73 -0
  582. package/src/model/taint-types.ts +1 -6
  583. package/src/parse/ast.ts +271 -0
  584. package/src/parse/call-graph.ts +419 -0
  585. package/src/parse/file-classifier.ts +69 -15
  586. package/src/parse/node-index.ts +118 -0
  587. package/src/parse/type-extractor.ts +293 -0
  588. package/src/pipeline/config.ts +10 -1
  589. package/src/pipeline/index.ts +475 -187
  590. package/src/pipeline/modes/incremental.ts +1 -7
  591. package/src/postprocess/dedup.ts +48 -17
  592. package/src/report/build-result.ts +57 -29
  593. package/src/report/formatters/cli-terminal.ts +731 -415
  594. package/src/report/sanitize.ts +27 -0
  595. package/src/score/adjustments.ts +113 -40
  596. package/src/score/confidence.ts +10 -5
  597. package/src/score/evidence.ts +55 -0
  598. package/src/score/index.ts +27 -55
  599. package/src/score/types.ts +4 -0
  600. package/src/shared/category-filter.ts +12 -0
  601. package/src/shared/regex-utils.ts +4 -0
  602. package/src/shared/registry-clients.ts +106 -18
  603. package/src/shared/rules/__tests__/metadata.test.ts +5 -1
  604. package/src/shared/rules/metadata.ts +19 -0
  605. package/src/shared/types.ts +373 -254
  606. package/src/taint/async-flow.ts +301 -0
  607. package/src/taint/cfg-builder.ts +1127 -0
  608. package/src/taint/cfg-types.ts +110 -0
  609. package/src/taint/constant-propagation.ts +170 -0
  610. package/src/taint/cross-file-analyzer.ts +118 -0
  611. package/src/taint/cross-file-index.ts +275 -0
  612. package/src/taint/def-use.ts +556 -0
  613. package/src/taint/file-analysis-cache.ts +145 -0
  614. package/src/taint/framework-models.ts +313 -0
  615. package/src/taint/helpers.ts +138 -0
  616. package/src/taint/index.ts +71 -0
  617. package/src/taint/llm-registry.ts +174 -0
  618. package/src/taint/llm-risk-scoring.ts +412 -0
  619. package/src/taint/propagation-types.ts +188 -0
  620. package/src/taint/propagation.ts +1750 -0
  621. package/src/taint/sanitizer-registry.ts +490 -0
  622. package/src/taint/sink-classifier.ts +1402 -0
  623. package/src/taint/source-classifier.ts +859 -0
  624. package/src/taint/taint-analyzer.ts +112 -0
  625. package/src/taint/taint-summary.ts +341 -0
  626. package/src/taint/types.ts +86 -0
  627. package/src/tiers.ts +2 -2
  628. package/src/validate/clients.ts +3 -2
  629. package/src/validate/index.ts +89 -53
  630. package/src/validate/prompts/modules/ai-patterns.ts +16 -0
  631. package/src/validate/prompts/modules/common.ts +12 -3
  632. package/src/validate/providers/anthropic.ts +254 -148
  633. package/src/validate/providers/openai.ts +363 -218
  634. package/src/validate/request-builder.ts +2 -45
  635. package/src/validate/types.ts +9 -0
  636. package/src/validate/utils/path-helpers.ts +2 -2
  637. package/src/validate/utils/response-parser.ts +32 -3
  638. package/src/validate/utils/retry.ts +19 -4
  639. package/dist/ai-context/index.d.ts +0 -6
  640. package/dist/ai-context/index.d.ts.map +0 -1
  641. package/dist/ai-context/index.js +0 -13
  642. package/dist/ai-context/index.js.map +0 -1
  643. package/dist/ai-context/manager.d.ts +0 -67
  644. package/dist/ai-context/manager.d.ts.map +0 -1
  645. package/dist/ai-context/manager.js +0 -104
  646. package/dist/ai-context/manager.js.map +0 -1
  647. package/dist/baseline/diff.d.ts +0 -32
  648. package/dist/baseline/diff.d.ts.map +0 -1
  649. package/dist/baseline/diff.js +0 -119
  650. package/dist/baseline/diff.js.map +0 -1
  651. package/dist/baseline/index.d.ts +0 -9
  652. package/dist/baseline/index.d.ts.map +0 -1
  653. package/dist/baseline/index.js +0 -19
  654. package/dist/baseline/index.js.map +0 -1
  655. package/dist/baseline/manager.d.ts +0 -67
  656. package/dist/baseline/manager.d.ts.map +0 -1
  657. package/dist/baseline/manager.js +0 -180
  658. package/dist/baseline/manager.js.map +0 -1
  659. package/dist/baseline/types.d.ts +0 -91
  660. package/dist/baseline/types.d.ts.map +0 -1
  661. package/dist/baseline/types.js +0 -12
  662. package/dist/baseline/types.js.map +0 -1
  663. package/dist/category-filter.d.ts +0 -125
  664. package/dist/category-filter.d.ts.map +0 -1
  665. package/dist/category-filter.js +0 -360
  666. package/dist/category-filter.js.map +0 -1
  667. package/dist/detect/ai-code/agent-tools.d.ts +0 -22
  668. package/dist/detect/ai-code/agent-tools.d.ts.map +0 -1
  669. package/dist/detect/ai-code/agent-tools.js +0 -1509
  670. package/dist/detect/ai-code/agent-tools.js.map +0 -1
  671. package/dist/detect/ai-code/byok-patterns.d.ts +0 -15
  672. package/dist/detect/ai-code/byok-patterns.d.ts.map +0 -1
  673. package/dist/detect/ai-code/byok-patterns.js +0 -313
  674. package/dist/detect/ai-code/byok-patterns.js.map +0 -1
  675. package/dist/detect/ai-code/endpoint-protection.d.ts +0 -38
  676. package/dist/detect/ai-code/endpoint-protection.d.ts.map +0 -1
  677. package/dist/detect/ai-code/endpoint-protection.js +0 -349
  678. package/dist/detect/ai-code/endpoint-protection.js.map +0 -1
  679. package/dist/detect/ai-code/execution-sinks.d.ts +0 -21
  680. package/dist/detect/ai-code/execution-sinks.d.ts.map +0 -1
  681. package/dist/detect/ai-code/execution-sinks.js +0 -1158
  682. package/dist/detect/ai-code/execution-sinks.js.map +0 -1
  683. package/dist/detect/ai-code/fingerprinting.d.ts +0 -10
  684. package/dist/detect/ai-code/fingerprinting.d.ts.map +0 -1
  685. package/dist/detect/ai-code/fingerprinting.js +0 -665
  686. package/dist/detect/ai-code/fingerprinting.js.map +0 -1
  687. package/dist/detect/ai-code/mcp-security.d.ts +0 -20
  688. package/dist/detect/ai-code/mcp-security.d.ts.map +0 -1
  689. package/dist/detect/ai-code/mcp-security.js +0 -880
  690. package/dist/detect/ai-code/mcp-security.js.map +0 -1
  691. package/dist/detect/ai-code/model-supply-chain.d.ts +0 -23
  692. package/dist/detect/ai-code/model-supply-chain.d.ts.map +0 -1
  693. package/dist/detect/ai-code/model-supply-chain.js +0 -447
  694. package/dist/detect/ai-code/model-supply-chain.js.map +0 -1
  695. package/dist/detect/ai-code/package-hallucination.d.ts +0 -22
  696. package/dist/detect/ai-code/package-hallucination.d.ts.map +0 -1
  697. package/dist/detect/ai-code/package-hallucination.js +0 -841
  698. package/dist/detect/ai-code/package-hallucination.js.map +0 -1
  699. package/dist/detect/ai-code/prompt-hygiene.d.ts +0 -22
  700. package/dist/detect/ai-code/prompt-hygiene.d.ts.map +0 -1
  701. package/dist/detect/ai-code/prompt-hygiene.js +0 -1177
  702. package/dist/detect/ai-code/prompt-hygiene.js.map +0 -1
  703. package/dist/detect/ai-code/rag-safety.d.ts +0 -24
  704. package/dist/detect/ai-code/rag-safety.d.ts.map +0 -1
  705. package/dist/detect/ai-code/rag-safety.js +0 -913
  706. package/dist/detect/ai-code/rag-safety.js.map +0 -1
  707. package/dist/detect/ai-code/schema-validation.d.ts +0 -28
  708. package/dist/detect/ai-code/schema-validation.d.ts.map +0 -1
  709. package/dist/detect/ai-code/schema-validation.js +0 -378
  710. package/dist/detect/ai-code/schema-validation.js.map +0 -1
  711. package/dist/detect/secrets/patterns.d.ts +0 -11
  712. package/dist/detect/secrets/patterns.d.ts.map +0 -1
  713. package/dist/detect/secrets/patterns.js +0 -518
  714. package/dist/detect/secrets/patterns.js.map +0 -1
  715. package/dist/detect/secrets/weak-crypto.d.ts +0 -10
  716. package/dist/detect/secrets/weak-crypto.d.ts.map +0 -1
  717. package/dist/detect/secrets/weak-crypto.js +0 -432
  718. package/dist/detect/secrets/weak-crypto.js.map +0 -1
  719. package/dist/detect/structural/auth-patterns.d.ts +0 -22
  720. package/dist/detect/structural/auth-patterns.d.ts.map +0 -1
  721. package/dist/detect/structural/auth-patterns.js +0 -533
  722. package/dist/detect/structural/auth-patterns.js.map +0 -1
  723. package/dist/detect/structural/dangerous-functions/child-process.d.ts +0 -16
  724. package/dist/detect/structural/dangerous-functions/child-process.d.ts.map +0 -1
  725. package/dist/detect/structural/dangerous-functions/child-process.js +0 -74
  726. package/dist/detect/structural/dangerous-functions/child-process.js.map +0 -1
  727. package/dist/detect/structural/dangerous-functions/dom-xss.d.ts +0 -34
  728. package/dist/detect/structural/dangerous-functions/dom-xss.d.ts.map +0 -1
  729. package/dist/detect/structural/dangerous-functions/dom-xss.js +0 -230
  730. package/dist/detect/structural/dangerous-functions/dom-xss.js.map +0 -1
  731. package/dist/detect/structural/dangerous-functions/index.d.ts +0 -16
  732. package/dist/detect/structural/dangerous-functions/index.d.ts.map +0 -1
  733. package/dist/detect/structural/dangerous-functions/index.js +0 -1193
  734. package/dist/detect/structural/dangerous-functions/index.js.map +0 -1
  735. package/dist/detect/structural/dangerous-functions/json-parse.d.ts +0 -31
  736. package/dist/detect/structural/dangerous-functions/json-parse.d.ts.map +0 -1
  737. package/dist/detect/structural/dangerous-functions/json-parse.js +0 -326
  738. package/dist/detect/structural/dangerous-functions/json-parse.js.map +0 -1
  739. package/dist/detect/structural/dangerous-functions/math-random.d.ts +0 -111
  740. package/dist/detect/structural/dangerous-functions/math-random.d.ts.map +0 -1
  741. package/dist/detect/structural/dangerous-functions/math-random.js +0 -684
  742. package/dist/detect/structural/dangerous-functions/math-random.js.map +0 -1
  743. package/dist/detect/structural/dangerous-functions/patterns.d.ts +0 -21
  744. package/dist/detect/structural/dangerous-functions/patterns.d.ts.map +0 -1
  745. package/dist/detect/structural/dangerous-functions/patterns.js +0 -163
  746. package/dist/detect/structural/dangerous-functions/patterns.js.map +0 -1
  747. package/dist/detect/structural/dangerous-functions/request-validation.d.ts +0 -13
  748. package/dist/detect/structural/dangerous-functions/request-validation.d.ts.map +0 -1
  749. package/dist/detect/structural/dangerous-functions/request-validation.js +0 -126
  750. package/dist/detect/structural/dangerous-functions/request-validation.js.map +0 -1
  751. package/dist/detect/structural/dangerous-functions/utils/control-flow.d.ts +0 -24
  752. package/dist/detect/structural/dangerous-functions/utils/control-flow.d.ts.map +0 -1
  753. package/dist/detect/structural/dangerous-functions/utils/control-flow.js +0 -70
  754. package/dist/detect/structural/dangerous-functions/utils/control-flow.js.map +0 -1
  755. package/dist/detect/structural/dangerous-functions/utils/helpers.d.ts +0 -31
  756. package/dist/detect/structural/dangerous-functions/utils/helpers.d.ts.map +0 -1
  757. package/dist/detect/structural/dangerous-functions/utils/helpers.js +0 -147
  758. package/dist/detect/structural/dangerous-functions/utils/helpers.js.map +0 -1
  759. package/dist/detect/structural/dangerous-functions/utils/index.d.ts +0 -9
  760. package/dist/detect/structural/dangerous-functions/utils/index.d.ts.map +0 -1
  761. package/dist/detect/structural/dangerous-functions/utils/index.js +0 -23
  762. package/dist/detect/structural/dangerous-functions/utils/index.js.map +0 -1
  763. package/dist/detect/structural/dangerous-functions/utils/schema-validation.d.ts +0 -22
  764. package/dist/detect/structural/dangerous-functions/utils/schema-validation.d.ts.map +0 -1
  765. package/dist/detect/structural/dangerous-functions/utils/schema-validation.js +0 -102
  766. package/dist/detect/structural/dangerous-functions/utils/schema-validation.js.map +0 -1
  767. package/dist/detect/structural/data-exposure.d.ts +0 -19
  768. package/dist/detect/structural/data-exposure.d.ts.map +0 -1
  769. package/dist/detect/structural/data-exposure.js +0 -262
  770. package/dist/detect/structural/data-exposure.js.map +0 -1
  771. package/dist/detect/structural/framework-checks.d.ts +0 -10
  772. package/dist/detect/structural/framework-checks.d.ts.map +0 -1
  773. package/dist/detect/structural/framework-checks.js +0 -389
  774. package/dist/detect/structural/framework-checks.js.map +0 -1
  775. package/dist/detect/structural/log-injection.d.ts +0 -18
  776. package/dist/detect/structural/log-injection.d.ts.map +0 -1
  777. package/dist/detect/structural/log-injection.js +0 -217
  778. package/dist/detect/structural/log-injection.js.map +0 -1
  779. package/dist/detect/structural/logic-gates.d.ts +0 -10
  780. package/dist/detect/structural/logic-gates.d.ts.map +0 -1
  781. package/dist/detect/structural/logic-gates.js +0 -227
  782. package/dist/detect/structural/logic-gates.js.map +0 -1
  783. package/dist/detect/structural/risky-imports.d.ts +0 -10
  784. package/dist/detect/structural/risky-imports.d.ts.map +0 -1
  785. package/dist/detect/structural/risky-imports.js +0 -168
  786. package/dist/detect/structural/risky-imports.js.map +0 -1
  787. package/dist/detect/structural/security-headers.d.ts +0 -18
  788. package/dist/detect/structural/security-headers.d.ts.map +0 -1
  789. package/dist/detect/structural/security-headers.js +0 -196
  790. package/dist/detect/structural/security-headers.js.map +0 -1
  791. package/dist/detect/structural/ssrf-detection.d.ts +0 -18
  792. package/dist/detect/structural/ssrf-detection.d.ts.map +0 -1
  793. package/dist/detect/structural/ssrf-detection.js +0 -263
  794. package/dist/detect/structural/ssrf-detection.js.map +0 -1
  795. package/dist/detect/structural/variables.d.ts +0 -11
  796. package/dist/detect/structural/variables.d.ts.map +0 -1
  797. package/dist/detect/structural/variables.js +0 -159
  798. package/dist/detect/structural/variables.js.map +0 -1
  799. package/dist/detect/structural/xxe-detection.d.ts +0 -18
  800. package/dist/detect/structural/xxe-detection.d.ts.map +0 -1
  801. package/dist/detect/structural/xxe-detection.js +0 -245
  802. package/dist/detect/structural/xxe-detection.js.map +0 -1
  803. package/dist/filtering/context-adjustments.d.ts +0 -23
  804. package/dist/filtering/context-adjustments.d.ts.map +0 -1
  805. package/dist/filtering/context-adjustments.js +0 -100
  806. package/dist/filtering/context-adjustments.js.map +0 -1
  807. package/dist/filtering/index.d.ts +0 -3
  808. package/dist/filtering/index.d.ts.map +0 -1
  809. package/dist/filtering/index.js +0 -8
  810. package/dist/filtering/index.js.map +0 -1
  811. package/dist/filtering/pipeline.d.ts +0 -48
  812. package/dist/filtering/pipeline.d.ts.map +0 -1
  813. package/dist/filtering/pipeline.js +0 -76
  814. package/dist/filtering/pipeline.js.map +0 -1
  815. package/dist/formatters/ai-context.d.ts +0 -23
  816. package/dist/formatters/ai-context.d.ts.map +0 -1
  817. package/dist/formatters/ai-context.js +0 -238
  818. package/dist/formatters/ai-context.js.map +0 -1
  819. package/dist/formatters/cli-terminal.d.ts +0 -65
  820. package/dist/formatters/cli-terminal.d.ts.map +0 -1
  821. package/dist/formatters/cli-terminal.js +0 -735
  822. package/dist/formatters/cli-terminal.js.map +0 -1
  823. package/dist/formatters/github-comment.d.ts +0 -41
  824. package/dist/formatters/github-comment.d.ts.map +0 -1
  825. package/dist/formatters/github-comment.js +0 -370
  826. package/dist/formatters/github-comment.js.map +0 -1
  827. package/dist/formatters/grouping.d.ts +0 -52
  828. package/dist/formatters/grouping.d.ts.map +0 -1
  829. package/dist/formatters/grouping.js +0 -152
  830. package/dist/formatters/grouping.js.map +0 -1
  831. package/dist/formatters/ide/claude-code.d.ts +0 -17
  832. package/dist/formatters/ide/claude-code.d.ts.map +0 -1
  833. package/dist/formatters/ide/claude-code.js +0 -94
  834. package/dist/formatters/ide/claude-code.js.map +0 -1
  835. package/dist/formatters/ide/cursor.d.ts +0 -13
  836. package/dist/formatters/ide/cursor.d.ts.map +0 -1
  837. package/dist/formatters/ide/cursor.js +0 -125
  838. package/dist/formatters/ide/cursor.js.map +0 -1
  839. package/dist/formatters/ide/index.d.ts +0 -62
  840. package/dist/formatters/ide/index.d.ts.map +0 -1
  841. package/dist/formatters/ide/index.js +0 -184
  842. package/dist/formatters/ide/index.js.map +0 -1
  843. package/dist/formatters/ide/windsurf.d.ts +0 -13
  844. package/dist/formatters/ide/windsurf.d.ts.map +0 -1
  845. package/dist/formatters/ide/windsurf.js +0 -117
  846. package/dist/formatters/ide/windsurf.js.map +0 -1
  847. package/dist/formatters/index.d.ts +0 -11
  848. package/dist/formatters/index.d.ts.map +0 -1
  849. package/dist/formatters/index.js +0 -54
  850. package/dist/formatters/index.js.map +0 -1
  851. package/dist/formatters/vscode-diagnostic.d.ts +0 -103
  852. package/dist/formatters/vscode-diagnostic.d.ts.map +0 -1
  853. package/dist/formatters/vscode-diagnostic.js +0 -151
  854. package/dist/formatters/vscode-diagnostic.js.map +0 -1
  855. package/dist/layer1/comments.d.ts +0 -11
  856. package/dist/layer1/comments.d.ts.map +0 -1
  857. package/dist/layer1/comments.js +0 -203
  858. package/dist/layer1/comments.js.map +0 -1
  859. package/dist/layer1/config-audit.d.ts +0 -11
  860. package/dist/layer1/config-audit.d.ts.map +0 -1
  861. package/dist/layer1/config-audit.js +0 -311
  862. package/dist/layer1/config-audit.js.map +0 -1
  863. package/dist/layer1/config-mcp-audit.d.ts +0 -23
  864. package/dist/layer1/config-mcp-audit.d.ts.map +0 -1
  865. package/dist/layer1/config-mcp-audit.js +0 -239
  866. package/dist/layer1/config-mcp-audit.js.map +0 -1
  867. package/dist/layer1/entropy.d.ts +0 -11
  868. package/dist/layer1/entropy.d.ts.map +0 -1
  869. package/dist/layer1/entropy.js +0 -741
  870. package/dist/layer1/entropy.js.map +0 -1
  871. package/dist/layer1/file-flags.d.ts +0 -10
  872. package/dist/layer1/file-flags.d.ts.map +0 -1
  873. package/dist/layer1/file-flags.js +0 -119
  874. package/dist/layer1/file-flags.js.map +0 -1
  875. package/dist/layer1/index.d.ts +0 -38
  876. package/dist/layer1/index.d.ts.map +0 -1
  877. package/dist/layer1/index.js +0 -170
  878. package/dist/layer1/index.js.map +0 -1
  879. package/dist/layer1/patterns.d.ts +0 -11
  880. package/dist/layer1/patterns.d.ts.map +0 -1
  881. package/dist/layer1/patterns.js +0 -512
  882. package/dist/layer1/patterns.js.map +0 -1
  883. package/dist/layer1/urls.d.ts +0 -11
  884. package/dist/layer1/urls.d.ts.map +0 -1
  885. package/dist/layer1/urls.js +0 -444
  886. package/dist/layer1/urls.js.map +0 -1
  887. package/dist/layer1/weak-crypto.d.ts +0 -10
  888. package/dist/layer1/weak-crypto.d.ts.map +0 -1
  889. package/dist/layer1/weak-crypto.js +0 -428
  890. package/dist/layer1/weak-crypto.js.map +0 -1
  891. package/dist/layer2/ai-agent-tools.d.ts +0 -22
  892. package/dist/layer2/ai-agent-tools.d.ts.map +0 -1
  893. package/dist/layer2/ai-agent-tools.js +0 -1490
  894. package/dist/layer2/ai-agent-tools.js.map +0 -1
  895. package/dist/layer2/ai-endpoint-protection.d.ts +0 -38
  896. package/dist/layer2/ai-endpoint-protection.d.ts.map +0 -1
  897. package/dist/layer2/ai-endpoint-protection.js +0 -346
  898. package/dist/layer2/ai-endpoint-protection.js.map +0 -1
  899. package/dist/layer2/ai-execution-sinks.d.ts +0 -21
  900. package/dist/layer2/ai-execution-sinks.d.ts.map +0 -1
  901. package/dist/layer2/ai-execution-sinks.js +0 -1155
  902. package/dist/layer2/ai-execution-sinks.js.map +0 -1
  903. package/dist/layer2/ai-fingerprinting.d.ts +0 -10
  904. package/dist/layer2/ai-fingerprinting.d.ts.map +0 -1
  905. package/dist/layer2/ai-fingerprinting.js +0 -650
  906. package/dist/layer2/ai-fingerprinting.js.map +0 -1
  907. package/dist/layer2/ai-mcp-security.d.ts +0 -20
  908. package/dist/layer2/ai-mcp-security.d.ts.map +0 -1
  909. package/dist/layer2/ai-mcp-security.js +0 -877
  910. package/dist/layer2/ai-mcp-security.js.map +0 -1
  911. package/dist/layer2/ai-package-hallucination.d.ts +0 -22
  912. package/dist/layer2/ai-package-hallucination.d.ts.map +0 -1
  913. package/dist/layer2/ai-package-hallucination.js +0 -828
  914. package/dist/layer2/ai-package-hallucination.js.map +0 -1
  915. package/dist/layer2/ai-prompt-hygiene.d.ts +0 -22
  916. package/dist/layer2/ai-prompt-hygiene.d.ts.map +0 -1
  917. package/dist/layer2/ai-prompt-hygiene.js +0 -1156
  918. package/dist/layer2/ai-prompt-hygiene.js.map +0 -1
  919. package/dist/layer2/ai-rag-safety.d.ts +0 -24
  920. package/dist/layer2/ai-rag-safety.d.ts.map +0 -1
  921. package/dist/layer2/ai-rag-safety.js +0 -910
  922. package/dist/layer2/ai-rag-safety.js.map +0 -1
  923. package/dist/layer2/ai-schema-validation.d.ts +0 -28
  924. package/dist/layer2/ai-schema-validation.d.ts.map +0 -1
  925. package/dist/layer2/ai-schema-validation.js +0 -375
  926. package/dist/layer2/ai-schema-validation.js.map +0 -1
  927. package/dist/layer2/auth-antipatterns.d.ts +0 -22
  928. package/dist/layer2/auth-antipatterns.d.ts.map +0 -1
  929. package/dist/layer2/auth-antipatterns.js +0 -522
  930. package/dist/layer2/auth-antipatterns.js.map +0 -1
  931. package/dist/layer2/byok-patterns.d.ts +0 -15
  932. package/dist/layer2/byok-patterns.d.ts.map +0 -1
  933. package/dist/layer2/byok-patterns.js +0 -302
  934. package/dist/layer2/byok-patterns.js.map +0 -1
  935. package/dist/layer2/dangerous-functions/child-process.d.ts +0 -16
  936. package/dist/layer2/dangerous-functions/child-process.d.ts.map +0 -1
  937. package/dist/layer2/dangerous-functions/child-process.js +0 -74
  938. package/dist/layer2/dangerous-functions/child-process.js.map +0 -1
  939. package/dist/layer2/dangerous-functions/dom-xss.d.ts +0 -34
  940. package/dist/layer2/dangerous-functions/dom-xss.d.ts.map +0 -1
  941. package/dist/layer2/dangerous-functions/dom-xss.js +0 -230
  942. package/dist/layer2/dangerous-functions/dom-xss.js.map +0 -1
  943. package/dist/layer2/dangerous-functions/index.d.ts +0 -16
  944. package/dist/layer2/dangerous-functions/index.d.ts.map +0 -1
  945. package/dist/layer2/dangerous-functions/index.js +0 -1152
  946. package/dist/layer2/dangerous-functions/index.js.map +0 -1
  947. package/dist/layer2/dangerous-functions/json-parse.d.ts +0 -31
  948. package/dist/layer2/dangerous-functions/json-parse.d.ts.map +0 -1
  949. package/dist/layer2/dangerous-functions/json-parse.js +0 -319
  950. package/dist/layer2/dangerous-functions/json-parse.js.map +0 -1
  951. package/dist/layer2/dangerous-functions/math-random.d.ts +0 -111
  952. package/dist/layer2/dangerous-functions/math-random.d.ts.map +0 -1
  953. package/dist/layer2/dangerous-functions/math-random.js +0 -684
  954. package/dist/layer2/dangerous-functions/math-random.js.map +0 -1
  955. package/dist/layer2/dangerous-functions/patterns.d.ts +0 -21
  956. package/dist/layer2/dangerous-functions/patterns.d.ts.map +0 -1
  957. package/dist/layer2/dangerous-functions/patterns.js +0 -163
  958. package/dist/layer2/dangerous-functions/patterns.js.map +0 -1
  959. package/dist/layer2/dangerous-functions/request-validation.d.ts +0 -13
  960. package/dist/layer2/dangerous-functions/request-validation.d.ts.map +0 -1
  961. package/dist/layer2/dangerous-functions/request-validation.js +0 -119
  962. package/dist/layer2/dangerous-functions/request-validation.js.map +0 -1
  963. package/dist/layer2/dangerous-functions/utils/control-flow.d.ts +0 -24
  964. package/dist/layer2/dangerous-functions/utils/control-flow.d.ts.map +0 -1
  965. package/dist/layer2/dangerous-functions/utils/control-flow.js +0 -70
  966. package/dist/layer2/dangerous-functions/utils/control-flow.js.map +0 -1
  967. package/dist/layer2/dangerous-functions/utils/helpers.d.ts +0 -31
  968. package/dist/layer2/dangerous-functions/utils/helpers.d.ts.map +0 -1
  969. package/dist/layer2/dangerous-functions/utils/helpers.js +0 -147
  970. package/dist/layer2/dangerous-functions/utils/helpers.js.map +0 -1
  971. package/dist/layer2/dangerous-functions/utils/index.d.ts +0 -9
  972. package/dist/layer2/dangerous-functions/utils/index.d.ts.map +0 -1
  973. package/dist/layer2/dangerous-functions/utils/index.js +0 -23
  974. package/dist/layer2/dangerous-functions/utils/index.js.map +0 -1
  975. package/dist/layer2/dangerous-functions/utils/schema-validation.d.ts +0 -22
  976. package/dist/layer2/dangerous-functions/utils/schema-validation.d.ts.map +0 -1
  977. package/dist/layer2/dangerous-functions/utils/schema-validation.js +0 -102
  978. package/dist/layer2/dangerous-functions/utils/schema-validation.js.map +0 -1
  979. package/dist/layer2/data-exposure.d.ts +0 -19
  980. package/dist/layer2/data-exposure.d.ts.map +0 -1
  981. package/dist/layer2/data-exposure.js +0 -255
  982. package/dist/layer2/data-exposure.js.map +0 -1
  983. package/dist/layer2/framework-checks.d.ts +0 -10
  984. package/dist/layer2/framework-checks.d.ts.map +0 -1
  985. package/dist/layer2/framework-checks.js +0 -384
  986. package/dist/layer2/framework-checks.js.map +0 -1
  987. package/dist/layer2/index.d.ts +0 -74
  988. package/dist/layer2/index.d.ts.map +0 -1
  989. package/dist/layer2/index.js +0 -544
  990. package/dist/layer2/index.js.map +0 -1
  991. package/dist/layer2/log-injection.d.ts +0 -18
  992. package/dist/layer2/log-injection.d.ts.map +0 -1
  993. package/dist/layer2/log-injection.js +0 -214
  994. package/dist/layer2/log-injection.js.map +0 -1
  995. package/dist/layer2/logic-gates.d.ts +0 -10
  996. package/dist/layer2/logic-gates.d.ts.map +0 -1
  997. package/dist/layer2/logic-gates.js +0 -220
  998. package/dist/layer2/logic-gates.js.map +0 -1
  999. package/dist/layer2/model-supply-chain.d.ts +0 -23
  1000. package/dist/layer2/model-supply-chain.d.ts.map +0 -1
  1001. package/dist/layer2/model-supply-chain.js +0 -444
  1002. package/dist/layer2/model-supply-chain.js.map +0 -1
  1003. package/dist/layer2/risky-imports.d.ts +0 -10
  1004. package/dist/layer2/risky-imports.d.ts.map +0 -1
  1005. package/dist/layer2/risky-imports.js +0 -165
  1006. package/dist/layer2/risky-imports.js.map +0 -1
  1007. package/dist/layer2/security-headers.d.ts +0 -18
  1008. package/dist/layer2/security-headers.d.ts.map +0 -1
  1009. package/dist/layer2/security-headers.js +0 -187
  1010. package/dist/layer2/security-headers.js.map +0 -1
  1011. package/dist/layer2/ssrf-detection.d.ts +0 -18
  1012. package/dist/layer2/ssrf-detection.d.ts.map +0 -1
  1013. package/dist/layer2/ssrf-detection.js +0 -252
  1014. package/dist/layer2/ssrf-detection.js.map +0 -1
  1015. package/dist/layer2/variables.d.ts +0 -11
  1016. package/dist/layer2/variables.d.ts.map +0 -1
  1017. package/dist/layer2/variables.js +0 -156
  1018. package/dist/layer2/variables.js.map +0 -1
  1019. package/dist/layer2/xxe-detection.d.ts +0 -18
  1020. package/dist/layer2/xxe-detection.d.ts.map +0 -1
  1021. package/dist/layer2/xxe-detection.js +0 -242
  1022. package/dist/layer2/xxe-detection.js.map +0 -1
  1023. package/dist/layer3/anthropic/auto-dismiss.d.ts +0 -24
  1024. package/dist/layer3/anthropic/auto-dismiss.d.ts.map +0 -1
  1025. package/dist/layer3/anthropic/auto-dismiss.js +0 -199
  1026. package/dist/layer3/anthropic/auto-dismiss.js.map +0 -1
  1027. package/dist/layer3/anthropic/clients.d.ts +0 -44
  1028. package/dist/layer3/anthropic/clients.d.ts.map +0 -1
  1029. package/dist/layer3/anthropic/clients.js +0 -81
  1030. package/dist/layer3/anthropic/clients.js.map +0 -1
  1031. package/dist/layer3/anthropic/index.d.ts +0 -41
  1032. package/dist/layer3/anthropic/index.d.ts.map +0 -1
  1033. package/dist/layer3/anthropic/index.js +0 -141
  1034. package/dist/layer3/anthropic/index.js.map +0 -1
  1035. package/dist/layer3/anthropic/prompts/index.d.ts +0 -8
  1036. package/dist/layer3/anthropic/prompts/index.d.ts.map +0 -1
  1037. package/dist/layer3/anthropic/prompts/index.js +0 -16
  1038. package/dist/layer3/anthropic/prompts/index.js.map +0 -1
  1039. package/dist/layer3/anthropic/prompts/modules/ai-patterns.d.ts +0 -19
  1040. package/dist/layer3/anthropic/prompts/modules/ai-patterns.d.ts.map +0 -1
  1041. package/dist/layer3/anthropic/prompts/modules/ai-patterns.js +0 -156
  1042. package/dist/layer3/anthropic/prompts/modules/ai-patterns.js.map +0 -1
  1043. package/dist/layer3/anthropic/prompts/modules/auth-access.d.ts +0 -9
  1044. package/dist/layer3/anthropic/prompts/modules/auth-access.d.ts.map +0 -1
  1045. package/dist/layer3/anthropic/prompts/modules/auth-access.js +0 -25
  1046. package/dist/layer3/anthropic/prompts/modules/auth-access.js.map +0 -1
  1047. package/dist/layer3/anthropic/prompts/modules/common.d.ts +0 -11
  1048. package/dist/layer3/anthropic/prompts/modules/common.d.ts.map +0 -1
  1049. package/dist/layer3/anthropic/prompts/modules/common.js +0 -152
  1050. package/dist/layer3/anthropic/prompts/modules/common.js.map +0 -1
  1051. package/dist/layer3/anthropic/prompts/modules/index.d.ts +0 -54
  1052. package/dist/layer3/anthropic/prompts/modules/index.d.ts.map +0 -1
  1053. package/dist/layer3/anthropic/prompts/modules/index.js +0 -185
  1054. package/dist/layer3/anthropic/prompts/modules/index.js.map +0 -1
  1055. package/dist/layer3/anthropic/prompts/modules/owasp-classic.d.ts +0 -8
  1056. package/dist/layer3/anthropic/prompts/modules/owasp-classic.d.ts.map +0 -1
  1057. package/dist/layer3/anthropic/prompts/modules/owasp-classic.js +0 -84
  1058. package/dist/layer3/anthropic/prompts/modules/owasp-classic.js.map +0 -1
  1059. package/dist/layer3/anthropic/prompts/modules/secrets-crypto.d.ts +0 -8
  1060. package/dist/layer3/anthropic/prompts/modules/secrets-crypto.d.ts.map +0 -1
  1061. package/dist/layer3/anthropic/prompts/modules/secrets-crypto.js +0 -68
  1062. package/dist/layer3/anthropic/prompts/modules/secrets-crypto.js.map +0 -1
  1063. package/dist/layer3/anthropic/prompts/modules/xss-prompt.d.ts +0 -8
  1064. package/dist/layer3/anthropic/prompts/modules/xss-prompt.d.ts.map +0 -1
  1065. package/dist/layer3/anthropic/prompts/modules/xss-prompt.js +0 -22
  1066. package/dist/layer3/anthropic/prompts/modules/xss-prompt.js.map +0 -1
  1067. package/dist/layer3/anthropic/prompts/semantic-analysis.d.ts +0 -15
  1068. package/dist/layer3/anthropic/prompts/semantic-analysis.d.ts.map +0 -1
  1069. package/dist/layer3/anthropic/prompts/semantic-analysis.js +0 -169
  1070. package/dist/layer3/anthropic/prompts/semantic-analysis.js.map +0 -1
  1071. package/dist/layer3/anthropic/prompts/validation.d.ts +0 -18
  1072. package/dist/layer3/anthropic/prompts/validation.d.ts.map +0 -1
  1073. package/dist/layer3/anthropic/prompts/validation.js +0 -25
  1074. package/dist/layer3/anthropic/prompts/validation.js.map +0 -1
  1075. package/dist/layer3/anthropic/providers/anthropic.d.ts +0 -21
  1076. package/dist/layer3/anthropic/providers/anthropic.d.ts.map +0 -1
  1077. package/dist/layer3/anthropic/providers/anthropic.js +0 -269
  1078. package/dist/layer3/anthropic/providers/anthropic.js.map +0 -1
  1079. package/dist/layer3/anthropic/providers/index.d.ts +0 -8
  1080. package/dist/layer3/anthropic/providers/index.d.ts.map +0 -1
  1081. package/dist/layer3/anthropic/providers/index.js +0 -15
  1082. package/dist/layer3/anthropic/providers/index.js.map +0 -1
  1083. package/dist/layer3/anthropic/providers/openai.d.ts +0 -18
  1084. package/dist/layer3/anthropic/providers/openai.d.ts.map +0 -1
  1085. package/dist/layer3/anthropic/providers/openai.js +0 -343
  1086. package/dist/layer3/anthropic/providers/openai.js.map +0 -1
  1087. package/dist/layer3/anthropic/request-builder.d.ts +0 -27
  1088. package/dist/layer3/anthropic/request-builder.d.ts.map +0 -1
  1089. package/dist/layer3/anthropic/request-builder.js +0 -150
  1090. package/dist/layer3/anthropic/request-builder.js.map +0 -1
  1091. package/dist/layer3/anthropic/types.d.ts +0 -88
  1092. package/dist/layer3/anthropic/types.d.ts.map +0 -1
  1093. package/dist/layer3/anthropic/types.js +0 -38
  1094. package/dist/layer3/anthropic/types.js.map +0 -1
  1095. package/dist/layer3/anthropic/utils/context-extractor.d.ts +0 -55
  1096. package/dist/layer3/anthropic/utils/context-extractor.d.ts.map +0 -1
  1097. package/dist/layer3/anthropic/utils/context-extractor.js +0 -161
  1098. package/dist/layer3/anthropic/utils/context-extractor.js.map +0 -1
  1099. package/dist/layer3/anthropic/utils/index.d.ts +0 -11
  1100. package/dist/layer3/anthropic/utils/index.d.ts.map +0 -1
  1101. package/dist/layer3/anthropic/utils/index.js +0 -27
  1102. package/dist/layer3/anthropic/utils/index.js.map +0 -1
  1103. package/dist/layer3/anthropic/utils/path-helpers.d.ts +0 -21
  1104. package/dist/layer3/anthropic/utils/path-helpers.d.ts.map +0 -1
  1105. package/dist/layer3/anthropic/utils/path-helpers.js +0 -69
  1106. package/dist/layer3/anthropic/utils/path-helpers.js.map +0 -1
  1107. package/dist/layer3/anthropic/utils/response-parser.d.ts +0 -40
  1108. package/dist/layer3/anthropic/utils/response-parser.d.ts.map +0 -1
  1109. package/dist/layer3/anthropic/utils/response-parser.js +0 -285
  1110. package/dist/layer3/anthropic/utils/response-parser.js.map +0 -1
  1111. package/dist/layer3/anthropic/utils/retry.d.ts +0 -15
  1112. package/dist/layer3/anthropic/utils/retry.d.ts.map +0 -1
  1113. package/dist/layer3/anthropic/utils/retry.js +0 -62
  1114. package/dist/layer3/anthropic/utils/retry.js.map +0 -1
  1115. package/dist/layer3/index.d.ts +0 -27
  1116. package/dist/layer3/index.d.ts.map +0 -1
  1117. package/dist/layer3/index.js +0 -150
  1118. package/dist/layer3/index.js.map +0 -1
  1119. package/dist/layer3/osv-check.d.ts +0 -75
  1120. package/dist/layer3/osv-check.d.ts.map +0 -1
  1121. package/dist/layer3/osv-check.js +0 -308
  1122. package/dist/layer3/osv-check.js.map +0 -1
  1123. package/dist/layer3/package-check.d.ts +0 -63
  1124. package/dist/layer3/package-check.d.ts.map +0 -1
  1125. package/dist/layer3/package-check.js +0 -508
  1126. package/dist/layer3/package-check.js.map +0 -1
  1127. package/dist/model/cross-file-taint.d.ts +0 -40
  1128. package/dist/model/cross-file-taint.d.ts.map +0 -1
  1129. package/dist/model/cross-file-taint.js +0 -290
  1130. package/dist/model/cross-file-taint.js.map +0 -1
  1131. package/dist/model/function-classifier.d.ts +0 -32
  1132. package/dist/model/function-classifier.d.ts.map +0 -1
  1133. package/dist/model/function-classifier.js +0 -143
  1134. package/dist/model/function-classifier.js.map +0 -1
  1135. package/dist/model/sanitiser-detection.d.ts +0 -27
  1136. package/dist/model/sanitiser-detection.d.ts.map +0 -1
  1137. package/dist/model/sanitiser-detection.js +0 -224
  1138. package/dist/model/sanitiser-detection.js.map +0 -1
  1139. package/dist/model/sink-matcher.d.ts +0 -17
  1140. package/dist/model/sink-matcher.d.ts.map +0 -1
  1141. package/dist/model/sink-matcher.js +0 -141
  1142. package/dist/model/sink-matcher.js.map +0 -1
  1143. package/dist/model/sink-patterns.d.ts +0 -19
  1144. package/dist/model/sink-patterns.d.ts.map +0 -1
  1145. package/dist/model/sink-patterns.js +0 -88
  1146. package/dist/model/sink-patterns.js.map +0 -1
  1147. package/dist/model/source-discovery.d.ts +0 -15
  1148. package/dist/model/source-discovery.d.ts.map +0 -1
  1149. package/dist/model/source-discovery.js +0 -170
  1150. package/dist/model/source-discovery.js.map +0 -1
  1151. package/dist/model/taint-tracker.d.ts +0 -21
  1152. package/dist/model/taint-tracker.d.ts.map +0 -1
  1153. package/dist/model/taint-tracker.js +0 -281
  1154. package/dist/model/taint-tracker.js.map +0 -1
  1155. package/dist/modes/incremental.d.ts +0 -66
  1156. package/dist/modes/incremental.d.ts.map +0 -1
  1157. package/dist/modes/incremental.js +0 -200
  1158. package/dist/modes/incremental.js.map +0 -1
  1159. package/dist/rules/framework-fixes.d.ts +0 -48
  1160. package/dist/rules/framework-fixes.d.ts.map +0 -1
  1161. package/dist/rules/framework-fixes.js +0 -439
  1162. package/dist/rules/framework-fixes.js.map +0 -1
  1163. package/dist/rules/index.d.ts +0 -8
  1164. package/dist/rules/index.d.ts.map +0 -1
  1165. package/dist/rules/index.js +0 -18
  1166. package/dist/rules/index.js.map +0 -1
  1167. package/dist/rules/metadata.d.ts +0 -43
  1168. package/dist/rules/metadata.d.ts.map +0 -1
  1169. package/dist/rules/metadata.js +0 -800
  1170. package/dist/rules/metadata.js.map +0 -1
  1171. package/dist/score/auto-dismiss.d.ts +0 -28
  1172. package/dist/score/auto-dismiss.d.ts.map +0 -1
  1173. package/dist/score/auto-dismiss.js +0 -200
  1174. package/dist/score/auto-dismiss.js.map +0 -1
  1175. package/dist/suppression/config-loader.d.ts +0 -74
  1176. package/dist/suppression/config-loader.d.ts.map +0 -1
  1177. package/dist/suppression/config-loader.js +0 -424
  1178. package/dist/suppression/config-loader.js.map +0 -1
  1179. package/dist/suppression/hash.d.ts +0 -48
  1180. package/dist/suppression/hash.d.ts.map +0 -1
  1181. package/dist/suppression/hash.js +0 -88
  1182. package/dist/suppression/hash.js.map +0 -1
  1183. package/dist/suppression/index.d.ts +0 -11
  1184. package/dist/suppression/index.d.ts.map +0 -1
  1185. package/dist/suppression/index.js +0 -39
  1186. package/dist/suppression/index.js.map +0 -1
  1187. package/dist/suppression/inline-parser.d.ts +0 -39
  1188. package/dist/suppression/inline-parser.d.ts.map +0 -1
  1189. package/dist/suppression/inline-parser.js +0 -218
  1190. package/dist/suppression/inline-parser.js.map +0 -1
  1191. package/dist/suppression/manager.d.ts +0 -94
  1192. package/dist/suppression/manager.d.ts.map +0 -1
  1193. package/dist/suppression/manager.js +0 -292
  1194. package/dist/suppression/manager.js.map +0 -1
  1195. package/dist/suppression/types.d.ts +0 -151
  1196. package/dist/suppression/types.d.ts.map +0 -1
  1197. package/dist/suppression/types.js +0 -28
  1198. package/dist/suppression/types.js.map +0 -1
  1199. package/dist/types.d.ts +0 -331
  1200. package/dist/types.d.ts.map +0 -1
  1201. package/dist/types.js +0 -124
  1202. package/dist/types.js.map +0 -1
  1203. package/dist/utils/auth-helper-detector.d.ts +0 -56
  1204. package/dist/utils/auth-helper-detector.d.ts.map +0 -1
  1205. package/dist/utils/auth-helper-detector.js +0 -360
  1206. package/dist/utils/auth-helper-detector.js.map +0 -1
  1207. package/dist/utils/code-analysis.d.ts +0 -39
  1208. package/dist/utils/code-analysis.d.ts.map +0 -1
  1209. package/dist/utils/code-analysis.js +0 -159
  1210. package/dist/utils/code-analysis.js.map +0 -1
  1211. package/dist/utils/comment-analyzer.d.ts +0 -38
  1212. package/dist/utils/comment-analyzer.d.ts.map +0 -1
  1213. package/dist/utils/comment-analyzer.js +0 -218
  1214. package/dist/utils/comment-analyzer.js.map +0 -1
  1215. package/dist/utils/context-helpers.d.ts +0 -219
  1216. package/dist/utils/context-helpers.d.ts.map +0 -1
  1217. package/dist/utils/context-helpers.js +0 -886
  1218. package/dist/utils/context-helpers.js.map +0 -1
  1219. package/dist/utils/diff-detector.d.ts +0 -53
  1220. package/dist/utils/diff-detector.d.ts.map +0 -1
  1221. package/dist/utils/diff-detector.js +0 -104
  1222. package/dist/utils/diff-detector.js.map +0 -1
  1223. package/dist/utils/diff-parser.d.ts +0 -80
  1224. package/dist/utils/diff-parser.d.ts.map +0 -1
  1225. package/dist/utils/diff-parser.js +0 -202
  1226. package/dist/utils/diff-parser.js.map +0 -1
  1227. package/dist/utils/environment-context.d.ts +0 -76
  1228. package/dist/utils/environment-context.d.ts.map +0 -1
  1229. package/dist/utils/environment-context.js +0 -271
  1230. package/dist/utils/environment-context.js.map +0 -1
  1231. package/dist/utils/imported-auth-detector.d.ts +0 -37
  1232. package/dist/utils/imported-auth-detector.d.ts.map +0 -1
  1233. package/dist/utils/imported-auth-detector.js +0 -251
  1234. package/dist/utils/imported-auth-detector.js.map +0 -1
  1235. package/dist/utils/intent-detector.d.ts +0 -66
  1236. package/dist/utils/intent-detector.d.ts.map +0 -1
  1237. package/dist/utils/intent-detector.js +0 -282
  1238. package/dist/utils/intent-detector.js.map +0 -1
  1239. package/dist/utils/middleware-detector.d.ts +0 -55
  1240. package/dist/utils/middleware-detector.d.ts.map +0 -1
  1241. package/dist/utils/middleware-detector.js +0 -260
  1242. package/dist/utils/middleware-detector.js.map +0 -1
  1243. package/dist/utils/oauth-flow-detector.d.ts +0 -41
  1244. package/dist/utils/oauth-flow-detector.d.ts.map +0 -1
  1245. package/dist/utils/oauth-flow-detector.js +0 -202
  1246. package/dist/utils/oauth-flow-detector.js.map +0 -1
  1247. package/dist/utils/parsed-file.d.ts +0 -51
  1248. package/dist/utils/parsed-file.d.ts.map +0 -1
  1249. package/dist/utils/parsed-file.js +0 -95
  1250. package/dist/utils/parsed-file.js.map +0 -1
  1251. package/dist/utils/path-exclusions.d.ts +0 -55
  1252. package/dist/utils/path-exclusions.d.ts.map +0 -1
  1253. package/dist/utils/path-exclusions.js +0 -224
  1254. package/dist/utils/path-exclusions.js.map +0 -1
  1255. package/dist/utils/project-context-builder.d.ts +0 -119
  1256. package/dist/utils/project-context-builder.d.ts.map +0 -1
  1257. package/dist/utils/project-context-builder.js +0 -534
  1258. package/dist/utils/project-context-builder.js.map +0 -1
  1259. package/dist/utils/registry-clients.d.ts +0 -93
  1260. package/dist/utils/registry-clients.d.ts.map +0 -1
  1261. package/dist/utils/registry-clients.js +0 -273
  1262. package/dist/utils/registry-clients.js.map +0 -1
  1263. package/dist/utils/route-hierarchy.d.ts +0 -50
  1264. package/dist/utils/route-hierarchy.d.ts.map +0 -1
  1265. package/dist/utils/route-hierarchy.js +0 -226
  1266. package/dist/utils/route-hierarchy.js.map +0 -1
  1267. package/dist/utils/schema-semantics.d.ts +0 -45
  1268. package/dist/utils/schema-semantics.d.ts.map +0 -1
  1269. package/dist/utils/schema-semantics.js +0 -193
  1270. package/dist/utils/schema-semantics.js.map +0 -1
  1271. package/dist/utils/trpc-analyzer.d.ts +0 -78
  1272. package/dist/utils/trpc-analyzer.d.ts.map +0 -1
  1273. package/dist/utils/trpc-analyzer.js +0 -297
  1274. package/dist/utils/trpc-analyzer.js.map +0 -1
  1275. package/src/__tests__/context-engine/cross-file-taint.test.ts +0 -284
  1276. package/src/__tests__/context-engine/function-classifier.test.ts +0 -146
  1277. package/src/__tests__/context-engine/integration.test.ts +0 -320
  1278. package/src/__tests__/context-engine/sanitiser-detection.test.ts +0 -187
  1279. package/src/__tests__/context-engine/sink-matcher.test.ts +0 -251
  1280. package/src/__tests__/context-engine/source-discovery.test.ts +0 -186
  1281. package/src/__tests__/context-engine/taint-tracker.test.ts +0 -182
  1282. package/src/__tests__/snapshots/__snapshots__/anthropic-validation-refactor.test.ts.snap +0 -750
  1283. package/src/__tests__/snapshots/__snapshots__/dangerous-functions-refactor.test.ts.snap +0 -555
  1284. package/src/__tests__/snapshots/anthropic-validation-refactor.test.ts +0 -321
  1285. package/src/__tests__/snapshots/dangerous-functions-refactor.test.ts +0 -439
  1286. package/src/detect/ai-code/agent-tools.ts +0 -1662
  1287. package/src/detect/ai-code/byok-patterns.ts +0 -354
  1288. package/src/detect/ai-code/endpoint-protection.ts +0 -406
  1289. package/src/detect/ai-code/execution-sinks.ts +0 -1310
  1290. package/src/detect/ai-code/fingerprinting.ts +0 -774
  1291. package/src/detect/ai-code/mcp-security.ts +0 -937
  1292. package/src/detect/ai-code/model-supply-chain.ts +0 -535
  1293. package/src/detect/ai-code/package-hallucination.ts +0 -955
  1294. package/src/detect/ai-code/prompt-hygiene.ts +0 -1314
  1295. package/src/detect/ai-code/rag-safety.ts +0 -977
  1296. package/src/detect/ai-code/schema-validation.ts +0 -427
  1297. package/src/detect/secrets/patterns.ts +0 -561
  1298. package/src/detect/secrets/weak-crypto.ts +0 -485
  1299. package/src/detect/structural/__tests__/math-random-enhanced.test.ts +0 -405
  1300. package/src/detect/structural/auth-patterns.ts +0 -621
  1301. package/src/detect/structural/dangerous-functions/child-process.ts +0 -98
  1302. package/src/detect/structural/dangerous-functions/dom-xss.ts +0 -292
  1303. package/src/detect/structural/dangerous-functions/index.ts +0 -1556
  1304. package/src/detect/structural/dangerous-functions/json-parse.ts +0 -393
  1305. package/src/detect/structural/dangerous-functions/math-random.ts +0 -789
  1306. package/src/detect/structural/dangerous-functions/patterns.ts +0 -176
  1307. package/src/detect/structural/dangerous-functions/request-validation.ts +0 -153
  1308. package/src/detect/structural/dangerous-functions/utils/control-flow.ts +0 -35
  1309. package/src/detect/structural/dangerous-functions/utils/helpers.ts +0 -170
  1310. package/src/detect/structural/dangerous-functions/utils/index.ts +0 -25
  1311. package/src/detect/structural/dangerous-functions/utils/schema-validation.ts +0 -106
  1312. package/src/detect/structural/data-exposure.ts +0 -302
  1313. package/src/detect/structural/framework-checks.ts +0 -439
  1314. package/src/detect/structural/log-injection.ts +0 -254
  1315. package/src/detect/structural/logic-gates.ts +0 -256
  1316. package/src/detect/structural/risky-imports.ts +0 -197
  1317. package/src/detect/structural/security-headers.ts +0 -231
  1318. package/src/detect/structural/ssrf-detection.ts +0 -300
  1319. package/src/detect/structural/variables.ts +0 -177
  1320. package/src/detect/structural/xxe-detection.ts +0 -295
  1321. package/src/model/cross-file-taint.ts +0 -374
  1322. package/src/model/function-classifier.ts +0 -184
  1323. package/src/model/sanitiser-detection.ts +0 -268
  1324. package/src/model/sink-matcher.ts +0 -178
  1325. package/src/model/sink-patterns.ts +0 -109
  1326. package/src/model/source-discovery.ts +0 -209
  1327. package/src/model/taint-tracker.ts +0 -333
  1328. package/src/score/auto-dismiss.ts +0 -224
@@ -0,0 +1,1750 @@
1
+ /**
2
+ * Taint Propagation Engine
3
+ *
4
+ * Forward worklist dataflow analysis. Seeds taint at sources, propagates
5
+ * through CFG to fixpoint, then checks if tainted data reaches sinks
6
+ * without proper sanitization.
7
+ *
8
+ * Algorithm:
9
+ * 1. Map sources/sinks/sanitizers to CFG nodes via AST containment
10
+ * 2. Seed source nodes with taint state
11
+ * 3. Worklist: propagate taint forward through CFG, applying transfer
12
+ * functions at each node (assignment, call, destructuring, etc.)
13
+ * 4. At fixpoint: check each sink node for matching taint kinds
14
+ * 5. Reconstruct source-to-sink paths via backward slice
15
+ */
16
+
17
+ import type Parser from 'tree-sitter'
18
+ import type { CFG, CFGNode } from './cfg-types'
19
+ import { getSuccessors, getPredecessors, buildFileCFGs } from './cfg-builder'
20
+ import type { TaintKind, TaintSource, TaintSink, TaintSanitizer } from './types'
21
+ import type { TaintState, TaintStep, TaintFinding, CallResolutionContext, CalleeResult } from './propagation-types'
22
+ import { getTaint, setTaint, deleteTaint, getFieldTaint, setFieldTaint, WHOLE_OBJECT } from './propagation-types'
23
+ import type { FieldKey } from './propagation-types'
24
+ import { walkAST } from '../parse/ast'
25
+ import { classifySources } from './source-classifier'
26
+ import { classifySinks } from './sink-classifier'
27
+ import { buildSanitizerRegistry } from './sanitizer-registry'
28
+ import { resolveCallTarget } from '../detect/ast-rules/helpers/call-analysis'
29
+ import { resolvePythonCallTarget } from '../detect/ast-rules/helpers/python-helpers'
30
+ import { collectImportBindings } from './helpers'
31
+ import { injectPromiseChainTaint, injectCallbackTaint } from './async-flow'
32
+ import { collectConstants, isConstantExpression } from './constant-propagation'
33
+ import type { ConstantMap } from './constant-propagation'
34
+ import { getOrBuildSummary, composeSummary } from './taint-summary'
35
+
36
+ // ============================================================================
37
+ // AST → CFGNode Matching
38
+ // ============================================================================
39
+
40
+ /**
41
+ * Check if `child` is a descendant of (or equal to) `ancestor` in the AST.
42
+ */
43
+ export function isDescendantOf(
44
+ child: Parser.SyntaxNode,
45
+ ancestor: Parser.SyntaxNode,
46
+ ): boolean {
47
+ let current: Parser.SyntaxNode | null = child
48
+ while (current) {
49
+ if (current.id === ancestor.id) return true
50
+ current = current.parent
51
+ }
52
+ return false
53
+ }
54
+
55
+ /**
56
+ * Find the CFG node that contains a given AST node.
57
+ * Returns the first CFG node whose astNode is an ancestor of (or equal to) the target.
58
+ */
59
+ export function findContainingCFGNode(
60
+ cfg: CFG,
61
+ astNode: Parser.SyntaxNode,
62
+ ): CFGNode | null {
63
+ for (const [, cfgNode] of cfg.nodes) {
64
+ if (!cfgNode.astNode) continue
65
+ if (isDescendantOf(astNode, cfgNode.astNode)) return cfgNode
66
+ }
67
+ return null
68
+ }
69
+
70
+ /**
71
+ * Phase 8 (Part 4): O(D) parent-chain walk using pre-built CFG node map.
72
+ * Walks up the AST parent chain until a mapped node is found.
73
+ * D = AST depth (5-15), vs O(N) where N = CFG nodes (50-200).
74
+ */
75
+ export function findContainingCFGNodeFast(
76
+ cfgNodeMap: Map<number, CFGNode>,
77
+ astNode: Parser.SyntaxNode,
78
+ ): CFGNode | null {
79
+ let current: Parser.SyntaxNode | null = astNode
80
+ while (current) {
81
+ const cfgNode = cfgNodeMap.get(current.id)
82
+ if (cfgNode) return cfgNode
83
+ current = current.parent
84
+ }
85
+ return null
86
+ }
87
+
88
+ /**
89
+ * Build a map from AST node ID → CFGNode for all nodes in a CFG.
90
+ */
91
+ export function buildCFGNodeMap(cfg: CFG): Map<number, CFGNode> {
92
+ const map = new Map<number, CFGNode>()
93
+ for (const [, cfgNode] of cfg.nodes) {
94
+ if (cfgNode.astNode) {
95
+ map.set(cfgNode.astNode.id, cfgNode)
96
+ }
97
+ }
98
+ return map
99
+ }
100
+
101
+ // ============================================================================
102
+ // Taint State Helpers
103
+ // ============================================================================
104
+
105
+ /** Clone a TaintState (deep copy of field maps and sets). */
106
+ function cloneState(state: TaintState): TaintState {
107
+ const clone: TaintState = new Map()
108
+ for (const [varName, fieldMap] of state) {
109
+ const clonedFieldMap = new Map<FieldKey, Set<TaintKind>>()
110
+ for (const [field, kinds] of fieldMap) {
111
+ clonedFieldMap.set(field, new Set(kinds))
112
+ }
113
+ clone.set(varName, clonedFieldMap)
114
+ }
115
+ return clone
116
+ }
117
+
118
+ /** Merge multiple predecessor out-states into one in-state (union). */
119
+ export function mergeStates(states: TaintState[]): TaintState {
120
+ const merged: TaintState = new Map()
121
+ for (const state of states) {
122
+ for (const [varName, fieldMap] of state) {
123
+ let existingFieldMap = merged.get(varName)
124
+ if (!existingFieldMap) {
125
+ existingFieldMap = new Map<FieldKey, Set<TaintKind>>()
126
+ merged.set(varName, existingFieldMap)
127
+ }
128
+ for (const [field, kinds] of fieldMap) {
129
+ const existingKinds = existingFieldMap.get(field)
130
+ if (existingKinds) {
131
+ for (const k of kinds) existingKinds.add(k)
132
+ } else {
133
+ existingFieldMap.set(field, new Set(kinds))
134
+ }
135
+ }
136
+ }
137
+ }
138
+ return merged
139
+ }
140
+
141
+ /** Check if two TaintStates are equal. */
142
+ function statesEqual(a: TaintState, b: TaintState): boolean {
143
+ // Phase 8 (3c): identity fast path — catches cases where applyTransfer returned same ref
144
+ if (a === b) return true
145
+ if (a.size !== b.size) return false
146
+ for (const [varName, aFieldMap] of a) {
147
+ const bFieldMap = b.get(varName)
148
+ if (!bFieldMap) return false
149
+ if (aFieldMap.size !== bFieldMap.size) return false
150
+ for (const [field, aKinds] of aFieldMap) {
151
+ const bKinds = bFieldMap.get(field)
152
+ if (!bKinds) return false
153
+ if (aKinds.size !== bKinds.size) return false
154
+ for (const k of aKinds) {
155
+ if (!bKinds.has(k)) return false
156
+ }
157
+ }
158
+ }
159
+ return true
160
+ }
161
+
162
+ /** Collect taint from a set of used variables in the current state. */
163
+ function collectUseTaint(
164
+ uses: Iterable<string>,
165
+ state: TaintState,
166
+ ): Set<TaintKind> {
167
+ const result = new Set<TaintKind>()
168
+ for (const u of uses) {
169
+ const kinds = getTaint(state, u)
170
+ if (kinds) {
171
+ for (const k of kinds) result.add(k)
172
+ }
173
+ }
174
+ return result
175
+ }
176
+
177
+ // ============================================================================
178
+ // Sanitizer Map
179
+ // ============================================================================
180
+
181
+ export interface SanitizerMapping {
182
+ cfgNodeId: number
183
+ sanitizer: TaintSanitizer
184
+ }
185
+
186
+ /**
187
+ * Build a map from CFG node ID → sanitizers active in that node.
188
+ * Phase 8: accepts optional cfgNodeMap for O(D) lookup instead of O(N).
189
+ */
190
+ export function buildSanitizerMap(
191
+ cfg: CFG,
192
+ sanitizers: TaintSanitizer[],
193
+ cfgNodeMap?: Map<number, CFGNode>,
194
+ ): Map<number, TaintSanitizer[]> {
195
+ const map = new Map<number, TaintSanitizer[]>()
196
+ for (const s of sanitizers) {
197
+ const cfgNode = cfgNodeMap
198
+ ? findContainingCFGNodeFast(cfgNodeMap, s.node)
199
+ : findContainingCFGNode(cfg, s.node)
200
+ if (!cfgNode) continue
201
+ const existing = map.get(cfgNode.id)
202
+ if (existing) {
203
+ existing.push(s)
204
+ } else {
205
+ map.set(cfgNode.id, [s])
206
+ }
207
+ }
208
+ return map
209
+ }
210
+
211
+ // ============================================================================
212
+ // Expression-level Transfer Function
213
+ // ============================================================================
214
+
215
+ /**
216
+ * Resolve taint for the RHS of an assignment by walking its AST.
217
+ *
218
+ * Returns the set of taint kinds that the RHS expression carries,
219
+ * considering sanitizer calls and optionally cross-file call resolution.
220
+ */
221
+ function resolveExpressionTaint(
222
+ exprNode: Parser.SyntaxNode,
223
+ inState: TaintState,
224
+ sanitizers: TaintSanitizer[],
225
+ callContext?: CallResolutionContext,
226
+ callerFile?: string,
227
+ ): Set<TaintKind> {
228
+ const result = new Set<TaintKind>()
229
+
230
+ // Literal values: no taint
231
+ if (isLiteral(exprNode)) return result
232
+
233
+ // Identifier: look up in state
234
+ if (exprNode.type === 'identifier') {
235
+ const kinds = getTaint(inState, exprNode.text)
236
+ if (kinds) for (const k of kinds) result.add(k)
237
+ return result
238
+ }
239
+
240
+ // Helper: shorthand for recursive calls with context forwarding
241
+ const resolve = (node: Parser.SyntaxNode) =>
242
+ resolveExpressionTaint(node, inState, sanitizers, callContext, callerFile)
243
+
244
+ // Await: taint propagates through (Python: 'await', JS: 'await_expression')
245
+ if (exprNode.type === 'await_expression' || exprNode.type === 'await') {
246
+ const inner = exprNode.namedChildren[0]
247
+ if (inner) {
248
+ const innerTaint = resolve(inner)
249
+ for (const k of innerTaint) result.add(k)
250
+ }
251
+ return result
252
+ }
253
+
254
+ // Parenthesized: pass through
255
+ if (exprNode.type === 'parenthesized_expression') {
256
+ const inner = exprNode.namedChildren[0]
257
+ if (inner) {
258
+ const innerTaint = resolve(inner)
259
+ for (const k of innerTaint) result.add(k)
260
+ }
261
+ return result
262
+ }
263
+
264
+ // Call expression: check sanitizers, then cross-file resolution, then conservative
265
+ // Python: 'call', JS: 'call_expression'
266
+ if (exprNode.type === 'call_expression' || exprNode.type === 'call') {
267
+ return resolveCallTaint(exprNode, inState, sanitizers, callContext, callerFile)
268
+ }
269
+
270
+ // New expression: union of arg taint
271
+ if (exprNode.type === 'new_expression') {
272
+ const args = exprNode.childForFieldName('arguments')
273
+ if (args) {
274
+ for (const arg of args.namedChildren) {
275
+ const argTaint = resolve(arg)
276
+ for (const k of argTaint) result.add(k)
277
+ }
278
+ }
279
+ return result
280
+ }
281
+
282
+ // Binary expression / template literal: union of both sides
283
+ // Python: 'binary_operator', JS: 'binary_expression'
284
+ if (exprNode.type === 'binary_expression' || exprNode.type === 'binary_operator') {
285
+ const left = exprNode.childForFieldName('left')
286
+ const right = exprNode.childForFieldName('right')
287
+ if (left) {
288
+ const lt = resolve(left)
289
+ for (const k of lt) result.add(k)
290
+ }
291
+ if (right) {
292
+ const rt = resolve(right)
293
+ for (const k of rt) result.add(k)
294
+ }
295
+ return result
296
+ }
297
+
298
+ // Python boolean/comparison operators: walk children for taint
299
+ if (exprNode.type === 'boolean_operator' || exprNode.type === 'comparison_operator' ||
300
+ exprNode.type === 'not_operator') {
301
+ for (const child of exprNode.namedChildren) {
302
+ const ct = resolve(child)
303
+ for (const k of ct) result.add(k)
304
+ }
305
+ return result
306
+ }
307
+
308
+ // Python f-string: string node with interpolation children
309
+ // Must check BEFORE the fallback walkAST to properly handle f-string taint
310
+ if (exprNode.type === 'string' && exprNode.descendantsOfType('interpolation').length > 0) {
311
+ for (const interp of exprNode.descendantsOfType('interpolation')) {
312
+ for (const child of interp.namedChildren) {
313
+ const childTaint = resolve(child)
314
+ for (const k of childTaint) result.add(k)
315
+ }
316
+ }
317
+ return result
318
+ }
319
+
320
+ // Python concatenated_string: "foo" + "bar" or "a" "b" style
321
+ if (exprNode.type === 'concatenated_string') {
322
+ for (const child of exprNode.namedChildren) {
323
+ const ct = resolve(child)
324
+ for (const k of ct) result.add(k)
325
+ }
326
+ return result
327
+ }
328
+
329
+ // Template string: union of all substitutions
330
+ if (exprNode.type === 'template_string') {
331
+ const subs = exprNode.descendantsOfType('template_substitution')
332
+ for (const sub of subs) {
333
+ for (const child of sub.namedChildren) {
334
+ const childTaint = resolve(child)
335
+ for (const k of childTaint) result.add(k)
336
+ }
337
+ }
338
+ return result
339
+ }
340
+
341
+ // Member expression: field-aware taint resolution
342
+ // Python: 'attribute' + 'subscript', JS: 'member_expression' + 'subscript_expression'
343
+ if (exprNode.type === 'member_expression' || exprNode.type === 'subscript_expression' ||
344
+ exprNode.type === 'attribute' || exprNode.type === 'subscript') {
345
+ const obj = exprNode.childForFieldName('object')
346
+ ?? exprNode.childForFieldName('value') // Python subscript uses 'value' field
347
+ if (obj) {
348
+ // Try field-specific taint: obj.field → getFieldTaint(state, "obj", "field")
349
+ if ((exprNode.type === 'member_expression' || exprNode.type === 'attribute') && obj.type === 'identifier') {
350
+ const prop = exprNode.type === 'attribute'
351
+ ? exprNode.childForFieldName('attribute')
352
+ : exprNode.childForFieldName('property')
353
+ if (prop && (prop.type === 'property_identifier' || prop.type === 'identifier')) {
354
+ const fieldTaint = getFieldTaint(inState, obj.text, prop.text)
355
+ if (fieldTaint) for (const k of fieldTaint) result.add(k)
356
+ return result
357
+ }
358
+ }
359
+ // Computed/dynamic access or deep chain: fall back to whole-object taint
360
+ const objTaint = resolve(obj)
361
+ for (const k of objTaint) result.add(k)
362
+ }
363
+ // Computed index may also carry taint
364
+ if (exprNode.type === 'subscript_expression' || exprNode.type === 'subscript') {
365
+ const index = exprNode.childForFieldName('index')
366
+ ?? exprNode.childForFieldName('subscript') // Python subscript field name
367
+ if (index) {
368
+ const idxTaint = resolve(index)
369
+ for (const k of idxTaint) result.add(k)
370
+ }
371
+ }
372
+ return result
373
+ }
374
+
375
+ // Spread element
376
+ if (exprNode.type === 'spread_element') {
377
+ const inner = exprNode.namedChildren[0]
378
+ if (inner) {
379
+ const innerTaint = resolve(inner)
380
+ for (const k of innerTaint) result.add(k)
381
+ }
382
+ return result
383
+ }
384
+
385
+ // Object literal: union of all value taint (whole-object view for backward compat)
386
+ if (exprNode.type === 'object') {
387
+ for (const child of exprNode.namedChildren) {
388
+ if (child.type === 'pair') {
389
+ const value = child.childForFieldName('value')
390
+ if (value) {
391
+ const vt = resolve(value)
392
+ for (const k of vt) result.add(k)
393
+ }
394
+ } else if (child.type === 'shorthand_property_identifier') {
395
+ const kinds = getTaint(inState, child.text)
396
+ if (kinds) for (const k of kinds) result.add(k)
397
+ } else if (child.type === 'spread_element') {
398
+ const inner = child.namedChildren[0]
399
+ if (inner) {
400
+ const innerTaint = resolve(inner)
401
+ for (const k of innerTaint) result.add(k)
402
+ }
403
+ }
404
+ }
405
+ return result
406
+ }
407
+
408
+ // Array literal / Python list/tuple: union of all element taint
409
+ if (exprNode.type === 'array' || exprNode.type === 'list' || exprNode.type === 'tuple') {
410
+ for (const child of exprNode.namedChildren) {
411
+ const ct = resolve(child)
412
+ for (const k of ct) result.add(k)
413
+ }
414
+ return result
415
+ }
416
+
417
+ // Python dictionary: union of all value taint
418
+ if (exprNode.type === 'dictionary') {
419
+ for (const child of exprNode.namedChildren) {
420
+ if (child.type === 'pair') {
421
+ const value = child.childForFieldName('value')
422
+ if (value) {
423
+ const vt = resolve(value)
424
+ for (const k of vt) result.add(k)
425
+ }
426
+ } else {
427
+ const ct = resolve(child)
428
+ for (const k of ct) result.add(k)
429
+ }
430
+ }
431
+ return result
432
+ }
433
+
434
+ // Ternary: union of both branches (conservative)
435
+ // Python: 'conditional_expression', JS: 'ternary_expression'
436
+ if (exprNode.type === 'ternary_expression' || exprNode.type === 'conditional_expression') {
437
+ for (const child of exprNode.namedChildren) {
438
+ const ct = resolve(child)
439
+ for (const k of ct) result.add(k)
440
+ }
441
+ return result
442
+ }
443
+
444
+ // Unary expression: propagate from operand
445
+ // Python: 'unary_operator', JS: 'unary_expression'
446
+ if (exprNode.type === 'unary_expression' || exprNode.type === 'unary_operator') {
447
+ const arg = exprNode.namedChildren[0]
448
+ if (arg) {
449
+ const at = resolve(arg)
450
+ for (const k of at) result.add(k)
451
+ }
452
+ return result
453
+ }
454
+
455
+ // Python keyword_argument: extract taint from value
456
+ if (exprNode.type === 'keyword_argument') {
457
+ const value = exprNode.childForFieldName('value')
458
+ if (value) {
459
+ const vt = resolve(value)
460
+ for (const k of vt) result.add(k)
461
+ }
462
+ return result
463
+ }
464
+
465
+ // Type assertion / as expression: propagate through
466
+ if (exprNode.type === 'as_expression' || exprNode.type === 'type_assertion' ||
467
+ exprNode.type === 'non_null_expression' || exprNode.type === 'satisfies_expression') {
468
+ const inner = exprNode.namedChildren[0]
469
+ if (inner) {
470
+ const innerTaint = resolve(inner)
471
+ for (const k of innerTaint) result.add(k)
472
+ }
473
+ return result
474
+ }
475
+
476
+ // Fallback: conservatively collect taint from all identifiers in the expression
477
+ walkAST(exprNode, (node) => {
478
+ if (node.type === 'identifier') {
479
+ const kinds = getTaint(inState, node.text)
480
+ if (kinds) for (const k of kinds) result.add(k)
481
+ }
482
+ // Don't descend into nested function expressions
483
+ if (node.type === 'arrow_function' || node.type === 'function_expression' ||
484
+ node.type === 'function_definition' || node.type === 'lambda') return true
485
+ return false
486
+ })
487
+
488
+ return result
489
+ }
490
+
491
+ /**
492
+ * Resolve taint for a call expression, checking sanitizers and cross-file callees.
493
+ */
494
+ function resolveCallTaint(
495
+ callNode: Parser.SyntaxNode,
496
+ inState: TaintState,
497
+ sanitizers: TaintSanitizer[],
498
+ callContext?: CallResolutionContext,
499
+ callerFile?: string,
500
+ ): Set<TaintKind> {
501
+ const result = new Set<TaintKind>()
502
+ const resolve = (node: Parser.SyntaxNode) =>
503
+ resolveExpressionTaint(node, inState, sanitizers, callContext, callerFile)
504
+
505
+ // First, collect taint from all arguments (and per-argument taint for cross-file)
506
+ const argsNode = callNode.childForFieldName('arguments')
507
+ const argTaint = new Set<TaintKind>()
508
+ const perArgTaint: Set<TaintKind>[] = []
509
+ if (argsNode) {
510
+ for (const arg of argsNode.namedChildren) {
511
+ const at = resolve(arg)
512
+ perArgTaint.push(at)
513
+ for (const k of at) argTaint.add(k)
514
+ }
515
+ }
516
+
517
+ // Also get taint from the callee (for method chains: tainted.toString())
518
+ // Python: 'attribute', JS: 'member_expression'
519
+ const fnNode = callNode.childForFieldName('function')
520
+ if (fnNode?.type === 'member_expression' || fnNode?.type === 'attribute') {
521
+ const obj = fnNode.childForFieldName('object')
522
+ if (obj) {
523
+ const objTaint = resolve(obj)
524
+ for (const k of objTaint) argTaint.add(k)
525
+ }
526
+ }
527
+
528
+ // Check if this call is a sanitizer
529
+ const matchingSanitizer = findMatchingSanitizer(callNode, sanitizers)
530
+ if (matchingSanitizer) {
531
+ // Sanitizer: result = argTaint minus clearsKinds
532
+ for (const k of argTaint) {
533
+ if (!matchingSanitizer.clearsKinds.has(k)) {
534
+ result.add(k)
535
+ }
536
+ }
537
+ return result
538
+ }
539
+
540
+ // Cross-file / inter-procedural resolution
541
+ if (callContext && callerFile && argTaint.size > 0) {
542
+ const calleeResult = resolveCalleeReturnTaint(
543
+ callNode, perArgTaint, callContext, callerFile,
544
+ )
545
+ if (calleeResult !== null) {
546
+ return calleeResult.returnTaint
547
+ }
548
+ }
549
+
550
+ // Not a sanitizer, not cross-file resolved: conservatively propagate all arg taint
551
+ return argTaint
552
+ }
553
+
554
+ // ============================================================================
555
+ // Cross-File Call Resolution
556
+ // ============================================================================
557
+
558
+ /**
559
+ * Resolve the return taint from following a call into another function/file.
560
+ *
561
+ * 1. Resolve call target name
562
+ * 2. Look up in CrossFileIndex (resolveImport or functionDefs)
563
+ * 3. If found and not in callStack (recursion guard):
564
+ * a. Parse callee file's AST, build CFG
565
+ * b. Create synthetic sources from argument taint → parameter names
566
+ * c. Run propagation on callee's CFG
567
+ * d. Collect return-value taint from return statements
568
+ * 4. Return the taint kinds flowing out + path steps
569
+ */
570
+ export function resolveCalleeReturnTaint(
571
+ callNode: Parser.SyntaxNode,
572
+ perArgTaint: Set<TaintKind>[],
573
+ ctx: CallResolutionContext,
574
+ callerFile: string,
575
+ ): CalleeResult | null {
576
+ // Resolve the call target (try JS first, then Python fallback)
577
+ let resolved: { type: string; name: string; object?: string } | null = resolveCallTarget(callNode)
578
+ if (!resolved) {
579
+ const pyResolved = resolvePythonCallTarget(callNode)
580
+ if (pyResolved) {
581
+ resolved = { type: pyResolved.type, name: pyResolved.name, object: pyResolved.object }
582
+ }
583
+ }
584
+ if (!resolved) return null
585
+
586
+ const { crossFileIndex, allASTs, callStack, maxDepth } = ctx
587
+
588
+ // Try to find the function definition
589
+ let funcDef = crossFileIndex.resolveImport.get(`${callerFile}:${resolved.name}`)
590
+
591
+ // Also try namespace.method pattern
592
+ if (!funcDef && resolved.type === 'member' && resolved.object) {
593
+ funcDef = crossFileIndex.resolveImport.get(
594
+ `${callerFile}:${resolved.object}.${resolved.name}`,
595
+ )
596
+ }
597
+
598
+ // Also try local function
599
+ if (!funcDef) {
600
+ funcDef = crossFileIndex.functionDefs.get(`${callerFile}:${resolved.name}`)
601
+ }
602
+
603
+ if (!funcDef) return null
604
+
605
+ // Recursion guard
606
+ const callKey = `${funcDef.filePath}:${funcDef.functionName}`
607
+ if (callStack.has(callKey)) return null
608
+ if (callStack.size >= maxDepth) return null
609
+
610
+ // Check cache
611
+ const taintSig = perArgTaint.map(s => [...s].sort().join(',')).join('|')
612
+ const cacheKey = `${callKey}:${taintSig}`
613
+ if (ctx.resultCache.has(cacheKey)) {
614
+ return ctx.resultCache.get(cacheKey)!
615
+ }
616
+
617
+ // Phase 8: Try summary-based composition first (much faster than full analysis)
618
+ if (ctx.summaryCache && ctx.analysisCache) {
619
+ const summary = getOrBuildSummary(funcDef, ctx)
620
+ if (summary) {
621
+ const result = composeSummary(summary, perArgTaint, callerFile, callNode)
622
+ ctx.resultCache.set(cacheKey, result.returnTaint.size > 0 || result.calleeFindings.length > 0 ? result : null)
623
+ return result.returnTaint.size > 0 || result.calleeFindings.length > 0 ? result : null
624
+ }
625
+ }
626
+
627
+ // Get callee AST
628
+ const calleeAST = allASTs.get(funcDef.filePath)
629
+ if (!calleeAST) {
630
+ ctx.resultCache.set(cacheKey, null)
631
+ return null
632
+ }
633
+
634
+ // Phase 8: Use analysis cache if available, otherwise recompute
635
+ const fileCache = ctx.analysisCache?.get(funcDef.filePath)
636
+ const calleeCFGs = fileCache?.cfgs ?? buildFileCFGs(calleeAST)
637
+
638
+ // Find the specific function's CFG
639
+ let calleeCFG: CFG | undefined
640
+ for (const [name, cfg] of calleeCFGs) {
641
+ if (name === funcDef.functionName) {
642
+ calleeCFG = cfg
643
+ break
644
+ }
645
+ }
646
+
647
+ if (!calleeCFG) {
648
+ ctx.resultCache.set(cacheKey, null)
649
+ return null
650
+ }
651
+
652
+ // Create synthetic sources from argument taint → parameter names
653
+ const syntheticSources: TaintSource[] = []
654
+ for (let i = 0; i < funcDef.params.length && i < perArgTaint.length; i++) {
655
+ const paramTaint = perArgTaint[i]
656
+ if (paramTaint.size === 0) continue
657
+
658
+ // Find the parameter's AST node in the callee function
659
+ const paramNode = findParamNode(funcDef.astNode, funcDef.params[i])
660
+ if (!paramNode) continue
661
+
662
+ syntheticSources.push({
663
+ node: paramNode,
664
+ line: paramNode.startPosition.row + 1,
665
+ variable: funcDef.params[i],
666
+ expression: `${funcDef.functionName}(${funcDef.params[i]})`,
667
+ sourceType: 'external_api', // synthetic source
668
+ taintKinds: new Set(paramTaint),
669
+ confidence: 'high',
670
+ })
671
+ }
672
+
673
+ if (syntheticSources.length === 0) {
674
+ ctx.resultCache.set(cacheKey, null)
675
+ return null
676
+ }
677
+
678
+ // Phase 8: Get sinks and sanitizers from cache or recompute
679
+ const calleeSinks = fileCache?.sinks ?? classifySinks(calleeAST)
680
+ const calleeSanitizers = fileCache?.sanitizers ?? buildSanitizerRegistry(calleeAST)
681
+
682
+ // Map synthetic parameter sources to the CFG entry node.
683
+ // Parameters aren't inside any statement node, so mapSourcesToCFG would fail.
684
+ // Instead, seed them at the entry node — parameters are defined at function entry.
685
+ let entryNodeId = -1
686
+ for (const [id, node] of calleeCFG.nodes) {
687
+ if (node.kind === 'entry') {
688
+ entryNodeId = id
689
+ break
690
+ }
691
+ }
692
+ if (entryNodeId === -1) {
693
+ ctx.resultCache.set(cacheKey, null)
694
+ return null
695
+ }
696
+
697
+ const sourceMappings: SourceMapping[] = syntheticSources.map(source => ({
698
+ source,
699
+ cfgNodeId: entryNodeId,
700
+ }))
701
+ // Phase 8 (Part 4): use cached CFG node map for O(D) lookup
702
+ const calleeCFGNodeMap = fileCache?.cfgNodeMaps.get(funcDef.functionName)
703
+ const sinkMappings = mapSinksToCFG(calleeCFG, calleeSinks, calleeCFGNodeMap)
704
+ const sanitizerMap = buildSanitizerMap(calleeCFG, calleeSanitizers, calleeCFGNodeMap)
705
+
706
+ // Push to call stack
707
+ callStack.add(callKey)
708
+
709
+ // Create child context for deeper calls
710
+ const childContext: CallResolutionContext = {
711
+ ...ctx,
712
+ callStack: new Set(callStack),
713
+ }
714
+
715
+ // Run fixpoint ONCE — used for both callee findings and return taint
716
+ const calleeConstants = calleeCFG.functionNode ? collectConstants(calleeCFG.functionNode) : new Map()
717
+ const outStates = runFixpointInternal(calleeCFG, sourceMappings, sanitizerMap, funcDef.filePath, childContext, calleeConstants)
718
+ const calleeFindings = deduplicateFindings(
719
+ checkSinksInternal(calleeCFG, outStates, sinkMappings, sourceMappings, funcDef.filePath),
720
+ )
721
+
722
+ // Pop from call stack
723
+ callStack.delete(callKey)
724
+
725
+ // Extract return-value taint from the already-computed out-states
726
+ const returnTaint = extractReturnTaint(calleeCFG, outStates, calleeSanitizers, childContext, funcDef.filePath)
727
+
728
+ // Build path steps
729
+ const steps: TaintStep[] = [
730
+ {
731
+ nodeId: 0,
732
+ line: callNode.startPosition.row + 1,
733
+ variable: funcDef.functionName,
734
+ taintKinds: new Set(returnTaint),
735
+ description: `CALL_ENTRY ${funcDef.functionName}() in ${funcDef.filePath}`,
736
+ stepType: 'call_entry',
737
+ filePath: funcDef.filePath,
738
+ functionName: funcDef.functionName,
739
+ },
740
+ {
741
+ nodeId: 0,
742
+ line: callNode.startPosition.row + 1,
743
+ variable: funcDef.functionName,
744
+ taintKinds: new Set(returnTaint),
745
+ description: `CALL_RETURN ${funcDef.functionName}() → ${[...returnTaint].join(',')}`,
746
+ stepType: 'call_return',
747
+ filePath: callerFile,
748
+ functionName: funcDef.functionName,
749
+ },
750
+ ]
751
+
752
+ const calleeResult: CalleeResult = {
753
+ returnTaint,
754
+ steps,
755
+ calleeFindings,
756
+ }
757
+
758
+ ctx.resultCache.set(cacheKey, calleeResult)
759
+ return calleeResult
760
+ }
761
+
762
+ /**
763
+ * Extract taint kinds from return statements using pre-computed out-states.
764
+ * Walks all return statements in the CFG and resolves expression taint.
765
+ */
766
+ function extractReturnTaint(
767
+ cfg: CFG,
768
+ outStates: Map<number, TaintState>,
769
+ sanitizers: TaintSanitizer[],
770
+ callContext?: CallResolutionContext,
771
+ filePath?: string,
772
+ ): Set<TaintKind> {
773
+ const returnTaint = new Set<TaintKind>()
774
+
775
+ for (const [, cfgNode] of cfg.nodes) {
776
+ if (!cfgNode.astNode) continue
777
+ const ast = cfgNode.astNode
778
+
779
+ if (ast.type !== 'return_statement') continue
780
+
781
+ const returnExpr = ast.namedChildren[0]
782
+ if (!returnExpr) continue
783
+
784
+ // Get the taint state at this node: merge predecessors + own out-state
785
+ const predIds = getPredecessors(cfg, cfgNode.id)
786
+ const predStates: TaintState[] = []
787
+ for (const pId of predIds) {
788
+ const ps = outStates.get(pId)
789
+ if (ps) predStates.push(ps)
790
+ }
791
+ const nodeInState = mergeStates(predStates)
792
+ const nodeState = mergeStates([nodeInState, outStates.get(cfgNode.id) ?? new Map()])
793
+
794
+ const exprTaint = resolveExpressionTaint(returnExpr, nodeState, sanitizers, callContext, filePath)
795
+ for (const k of exprTaint) returnTaint.add(k)
796
+ }
797
+
798
+ return returnTaint
799
+ }
800
+
801
+ /** Find a parameter's AST node in a function definition. */
802
+ function findParamNode(
803
+ fnNode: Parser.SyntaxNode,
804
+ paramName: string,
805
+ ): Parser.SyntaxNode | null {
806
+ const params = fnNode.childForFieldName('parameters')
807
+ if (!params) return null
808
+
809
+ for (const child of params.namedChildren) {
810
+ if (child.type === 'identifier' && child.text === paramName) return child
811
+ // JS/TS param types
812
+ if (child.type === 'required_parameter' || child.type === 'optional_parameter') {
813
+ const pattern = child.childForFieldName('pattern')
814
+ if (pattern?.type === 'identifier' && pattern.text === paramName) return pattern
815
+ }
816
+ if (child.type === 'assignment_pattern') {
817
+ const left = child.childForFieldName('left')
818
+ if (left?.type === 'identifier' && left.text === paramName) return left
819
+ }
820
+ // Python param types
821
+ if (child.type === 'typed_parameter' || child.type === 'default_parameter' ||
822
+ child.type === 'typed_default_parameter') {
823
+ const nameNode = child.namedChildren.find(c => c.type === 'identifier')
824
+ if (nameNode && nameNode.text === paramName) return nameNode
825
+ }
826
+ if (child.type === 'list_splat_pattern' || child.type === 'dictionary_splat_pattern') {
827
+ const ident = child.namedChildren.find(c => c.type === 'identifier')
828
+ if (ident && ident.text === paramName) return ident
829
+ }
830
+ }
831
+
832
+ // Fallback: search for identifier in params subtree
833
+ let found: Parser.SyntaxNode | null = null
834
+ walkAST(params, (node) => {
835
+ if (node.type === 'identifier' && node.text === paramName && !found) {
836
+ found = node
837
+ return true
838
+ }
839
+ return false
840
+ })
841
+ return found
842
+ }
843
+
844
+ /**
845
+ * Find a sanitizer whose AST node matches this call expression.
846
+ */
847
+ function findMatchingSanitizer(
848
+ callNode: Parser.SyntaxNode,
849
+ sanitizers: TaintSanitizer[],
850
+ ): TaintSanitizer | null {
851
+ for (const s of sanitizers) {
852
+ if (s.node.id === callNode.id) return s
853
+ // Also check if the sanitizer's node is a parent/ancestor of this call
854
+ if (isDescendantOf(callNode, s.node)) return s
855
+ }
856
+ return null
857
+ }
858
+
859
+ /** Check if a node represents a literal value (no taint). */
860
+ function isLiteral(node: Parser.SyntaxNode): boolean {
861
+ switch (node.type) {
862
+ case 'string':
863
+ // Python f-strings have type 'string' but contain interpolation children — NOT a literal
864
+ if (node.descendantsOfType('interpolation').length > 0) return false
865
+ return true
866
+ case 'number':
867
+ case 'true':
868
+ case 'false':
869
+ case 'null':
870
+ case 'undefined':
871
+ case 'regex':
872
+ // Python literals
873
+ case 'integer':
874
+ case 'float':
875
+ case 'none':
876
+ return true
877
+ default:
878
+ return false
879
+ }
880
+ }
881
+
882
+ // ============================================================================
883
+ // Statement-level Transfer Function
884
+ // ============================================================================
885
+
886
+ /**
887
+ * Apply the transfer function for a single CFG node.
888
+ * Given the incoming taint state, compute the outgoing taint state.
889
+ */
890
+ export function applyTransfer(
891
+ cfgNode: CFGNode,
892
+ inState: TaintState,
893
+ sanitizerMap: Map<number, TaintSanitizer[]>,
894
+ callContext?: CallResolutionContext,
895
+ callerFile?: string,
896
+ constantMap?: ConstantMap,
897
+ ): TaintState {
898
+ // Phase 8 (3b): skip clone for no-op nodes — entry, exit, and nodes without AST
899
+ if (!cfgNode.astNode) return inState
900
+ if (cfgNode.kind === 'entry' || cfgNode.kind === 'exit') return inState
901
+
902
+ // Phase 8 (3b): condition nodes with no defs and no sanitizers are read-only
903
+ if (cfgNode.kind === 'condition' && cfgNode.defs.size === 0) {
904
+ const hasSanitizers = sanitizerMap.has(cfgNode.id)
905
+ if (!hasSanitizers) return inState
906
+ }
907
+
908
+ const outState = cloneState(inState)
909
+ const sanitizers = sanitizerMap.get(cfgNode.id) ?? []
910
+ const ast = cfgNode.astNode
911
+
912
+ applyNodeTransfer(ast, outState, sanitizers, callContext, callerFile, constantMap)
913
+
914
+ return outState
915
+ }
916
+
917
+ /**
918
+ * Recursively apply transfer for an AST node within a CFG statement.
919
+ */
920
+ function applyNodeTransfer(
921
+ node: Parser.SyntaxNode,
922
+ state: TaintState,
923
+ sanitizers: TaintSanitizer[],
924
+ callContext?: CallResolutionContext,
925
+ callerFile?: string,
926
+ constantMap?: ConstantMap,
927
+ ): void {
928
+ // Helper for expression taint resolution with context forwarding
929
+ const resolve = (expr: Parser.SyntaxNode) =>
930
+ resolveExpressionTaint(expr, state, sanitizers, callContext, callerFile)
931
+
932
+ // Variable declaration: const x = <expr>
933
+ if (node.type === 'lexical_declaration' || node.type === 'variable_declaration') {
934
+ for (const child of node.namedChildren) {
935
+ applyNodeTransfer(child, state, sanitizers, callContext, callerFile, constantMap)
936
+ }
937
+ return
938
+ }
939
+
940
+ if (node.type === 'variable_declarator') {
941
+ const nameNode = node.childForFieldName('name')
942
+ const valueNode = node.childForFieldName('value')
943
+ if (!nameNode || !valueNode) return
944
+
945
+ if (nameNode.type === 'identifier') {
946
+ // Constant propagation: if RHS is entirely constant-derived, clear taint
947
+ if (constantMap && isConstantExpression(valueNode, constantMap)) {
948
+ deleteTaint(state, nameNode.text)
949
+ return
950
+ }
951
+ // Simple: const x = expr
952
+ const rhsTaint = resolve(valueNode)
953
+ if (rhsTaint.size > 0) {
954
+ setTaint(state, nameNode.text, rhsTaint)
955
+ } else {
956
+ deleteTaint(state, nameNode.text)
957
+ }
958
+ } else if (nameNode.type === 'object_pattern' || nameNode.type === 'array_pattern') {
959
+ // Destructuring: const { a, b } = expr
960
+ const rhsTaint = resolve(valueNode)
961
+ const rhsVarName = valueNode.type === 'identifier' ? valueNode.text
962
+ : (valueNode.type === 'member_expression' ? getMemberRoot(valueNode) : null)
963
+ applyDestructuringTaint(nameNode, rhsTaint, state, rhsVarName ?? undefined)
964
+ }
965
+ return
966
+ }
967
+
968
+ // Assignment: x = expr
969
+ // Python: 'assignment', JS: 'assignment_expression'
970
+ if (node.type === 'assignment_expression' || node.type === 'assignment') {
971
+ const left = node.childForFieldName('left')
972
+ const right = node.childForFieldName('right')
973
+ if (!left || !right) return
974
+
975
+ if (left.type === 'identifier') {
976
+ // Constant propagation: if RHS is entirely constant-derived, clear taint
977
+ if (constantMap && isConstantExpression(right, constantMap)) {
978
+ deleteTaint(state, left.text)
979
+ return
980
+ }
981
+ const rhsTaint = resolve(right)
982
+ if (rhsTaint.size > 0) {
983
+ setTaint(state, left.text, rhsTaint)
984
+ } else {
985
+ deleteTaint(state, left.text)
986
+ }
987
+ } else if (left.type === 'object_pattern' || left.type === 'array_pattern' ||
988
+ left.type === 'tuple_pattern' || left.type === 'list_pattern' ||
989
+ left.type === 'pattern_list' || left.type === 'tuple' || left.type === 'list') {
990
+ // Destructuring / Python unpacking: a, b = expr
991
+ const rhsTaint = resolve(right)
992
+ const rhsVarName = right.type === 'identifier' ? right.text
993
+ : (right.type === 'member_expression' || right.type === 'attribute' ? getMemberRoot(right) : null)
994
+ applyDestructuringTaint(left, rhsTaint, state, rhsVarName ?? undefined)
995
+ } else if (left.type === 'member_expression' || left.type === 'attribute') {
996
+ // obj.prop = val — field-level taint
997
+ // Python: 'attribute' with fields 'object'/'attribute', JS: 'member_expression' with 'object'/'property'
998
+ const obj = left.childForFieldName('object')
999
+ const prop = left.type === 'attribute'
1000
+ ? left.childForFieldName('attribute')
1001
+ : left.childForFieldName('property')
1002
+ if (obj?.type === 'identifier' && prop && (prop.type === 'property_identifier' || prop.type === 'identifier')) {
1003
+ // One-level field assignment: obj.field = val
1004
+ const rhsTaint = resolve(right)
1005
+ if (rhsTaint.size > 0) {
1006
+ setFieldTaint(state, obj.text, prop.text, rhsTaint)
1007
+ }
1008
+ } else {
1009
+ // Deep chain or computed: fall back to root object taint
1010
+ const root = getMemberRoot(left)
1011
+ if (root) {
1012
+ const rhsTaint = resolve(right)
1013
+ // Phase 8: clone before mutating — getTaint may return internal Set reference
1014
+ const existing = new Set(getTaint(state, root) ?? [])
1015
+ for (const k of rhsTaint) existing.add(k)
1016
+ if (existing.size > 0) setTaint(state, root, existing)
1017
+ }
1018
+ }
1019
+ }
1020
+ return
1021
+ }
1022
+
1023
+ // Augmented assignment: x += expr
1024
+ // Python: 'augmented_assignment', JS: 'augmented_assignment_expression'
1025
+ if (node.type === 'augmented_assignment_expression' || node.type === 'augmented_assignment') {
1026
+ const left = node.childForFieldName('left')
1027
+ const right = node.childForFieldName('right')
1028
+ if (!left || !right) return
1029
+
1030
+ if (left.type === 'identifier') {
1031
+ const rhsTaint = resolve(right)
1032
+ // Phase 8: clone before mutating — getTaint may return internal Set reference
1033
+ const existing = new Set(getTaint(state, left.text) ?? [])
1034
+ for (const k of rhsTaint) existing.add(k)
1035
+ if (existing.size > 0) setTaint(state, left.text, existing)
1036
+ }
1037
+ return
1038
+ }
1039
+
1040
+ // Expression statement: unwrap the inner expression
1041
+ if (node.type === 'expression_statement') {
1042
+ for (const child of node.namedChildren) {
1043
+ applyNodeTransfer(child, state, sanitizers, callContext, callerFile, constantMap)
1044
+ }
1045
+ return
1046
+ }
1047
+
1048
+ // For-in header: captures iteration variable taint from the right side
1049
+ if (node.type === 'for_in_statement') {
1050
+ const left = node.childForFieldName('left')
1051
+ const right = node.childForFieldName('right')
1052
+ if (left && right) {
1053
+ const rhsTaint = resolve(right)
1054
+ if (left.type === 'identifier') {
1055
+ if (rhsTaint.size > 0) setTaint(state, left.text, rhsTaint)
1056
+ } else {
1057
+ // Destructuring in for-of/for-in
1058
+ applyDestructuringTaint(left, rhsTaint, state)
1059
+ }
1060
+ }
1061
+ return
1062
+ }
1063
+
1064
+ // Python for loop with left/right fields: for x in iterable
1065
+ if (node.type === 'for_statement') {
1066
+ const left = node.childForFieldName('left')
1067
+ const right = node.childForFieldName('right')
1068
+ if (left && right) {
1069
+ const rhsTaint = resolve(right)
1070
+ if (left.type === 'identifier') {
1071
+ if (rhsTaint.size > 0) setTaint(state, left.text, rhsTaint)
1072
+ } else {
1073
+ applyDestructuringTaint(left, rhsTaint, state)
1074
+ }
1075
+ }
1076
+ return
1077
+ }
1078
+
1079
+ // Python with statement: with expr as var
1080
+ if (node.type === 'with_statement') {
1081
+ // The with_clause may contain 'as_pattern' nodes: expr as name
1082
+ for (const child of node.namedChildren) {
1083
+ if (child.type === 'with_clause') {
1084
+ for (const item of child.namedChildren) {
1085
+ if (item.type === 'with_item' || item.type === 'as_pattern') {
1086
+ const expr = item.namedChildren[0]
1087
+ const alias = item.namedChildren[1]
1088
+ if (expr && alias?.type === 'identifier') {
1089
+ const exprTaint = resolve(expr)
1090
+ if (exprTaint.size > 0) setTaint(state, alias.text, exprTaint)
1091
+ }
1092
+ }
1093
+ }
1094
+ }
1095
+ }
1096
+ return
1097
+ }
1098
+
1099
+ // Standalone call expression: trigger expression resolution so cross-file
1100
+ // analysis discovers callee findings (sinks reached inside the called function).
1101
+ // Without this, standalone calls like `query(input)` would be silently ignored.
1102
+ // Python: 'call', JS: 'call_expression'
1103
+ if (node.type === 'call_expression' || node.type === 'call') {
1104
+ // Inject taint into callback parameters for promise chains and callback APIs.
1105
+ // This must happen BEFORE resolve() so the taint state is available when
1106
+ // analyzing the callback body's expressions.
1107
+ injectPromiseChainTaint(node, state)
1108
+ injectCallbackTaint(node, state)
1109
+ resolve(node)
1110
+ return
1111
+ }
1112
+
1113
+ // Return / throw: no defs, but the expression is "used"
1114
+ // (no state changes needed — uses are tracked by def-use)
1115
+ }
1116
+
1117
+ /**
1118
+ * Apply taint from a destructuring pattern.
1119
+ * When rhsVarName is provided and object_pattern is used, field-specific
1120
+ * taint is extracted per destructured key. Otherwise falls back to whole-object taint.
1121
+ */
1122
+ function applyDestructuringTaint(
1123
+ pattern: Parser.SyntaxNode,
1124
+ rhsTaint: Set<TaintKind>,
1125
+ state: TaintState,
1126
+ rhsVarName?: string,
1127
+ ): void {
1128
+ if (rhsTaint.size === 0) return
1129
+
1130
+ if (pattern.type === 'identifier') {
1131
+ setTaint(state, pattern.text, new Set(rhsTaint))
1132
+ return
1133
+ }
1134
+
1135
+ if (pattern.type === 'object_pattern') {
1136
+ for (const prop of pattern.namedChildren) {
1137
+ if (prop.type === 'shorthand_property_identifier_pattern') {
1138
+ // { email } = obj → email gets field-specific taint from obj.email
1139
+ if (rhsVarName) {
1140
+ const fieldTaint = getFieldTaint(state, rhsVarName, prop.text)
1141
+ if (fieldTaint && fieldTaint.size > 0) {
1142
+ setTaint(state, prop.text, new Set(fieldTaint))
1143
+ } else {
1144
+ // Field has no taint — don't assign whole-object taint
1145
+ deleteTaint(state, prop.text)
1146
+ }
1147
+ } else {
1148
+ setTaint(state, prop.text, new Set(rhsTaint))
1149
+ }
1150
+ } else if (prop.type === 'pair_pattern') {
1151
+ // { email: e } = obj → e gets taint from obj.email
1152
+ const key = prop.childForFieldName('key')
1153
+ const value = prop.childForFieldName('value')
1154
+ if (value && rhsVarName && key) {
1155
+ const fieldName = key.text
1156
+ const fieldTaint = getFieldTaint(state, rhsVarName, fieldName)
1157
+ if (fieldTaint && fieldTaint.size > 0) {
1158
+ applyDestructuringTaint(value, fieldTaint, state)
1159
+ }
1160
+ } else if (value) {
1161
+ applyDestructuringTaint(value, rhsTaint, state)
1162
+ }
1163
+ } else if (prop.type === 'rest_pattern') {
1164
+ // { ...rest } = obj → rest gets whole-object taint (conservative)
1165
+ const inner = prop.namedChildren[0]
1166
+ if (inner) applyDestructuringTaint(inner, rhsTaint, state)
1167
+ }
1168
+ }
1169
+ return
1170
+ }
1171
+
1172
+ if (pattern.type === 'array_pattern') {
1173
+ for (const elem of pattern.namedChildren) {
1174
+ applyDestructuringTaint(elem, rhsTaint, state)
1175
+ }
1176
+ return
1177
+ }
1178
+
1179
+ // Python unpacking: a, b = expr / (a, b) = expr / [a, b] = expr
1180
+ if (pattern.type === 'tuple_pattern' || pattern.type === 'list_pattern' ||
1181
+ pattern.type === 'pattern_list' || pattern.type === 'expression_list' ||
1182
+ pattern.type === 'tuple' || pattern.type === 'list') {
1183
+ for (const elem of pattern.namedChildren) {
1184
+ applyDestructuringTaint(elem, rhsTaint, state)
1185
+ }
1186
+ return
1187
+ }
1188
+
1189
+ // Python list_splat_pattern: *rest
1190
+ if (pattern.type === 'list_splat_pattern') {
1191
+ const inner = pattern.namedChildren[0]
1192
+ if (inner) applyDestructuringTaint(inner, rhsTaint, state)
1193
+ return
1194
+ }
1195
+
1196
+ if (pattern.type === 'assignment_pattern') {
1197
+ const left = pattern.childForFieldName('left')
1198
+ if (left) applyDestructuringTaint(left, rhsTaint, state, rhsVarName)
1199
+ return
1200
+ }
1201
+
1202
+ if (pattern.type === 'rest_pattern') {
1203
+ const inner = pattern.namedChildren[0]
1204
+ if (inner) applyDestructuringTaint(inner, rhsTaint, state)
1205
+ }
1206
+ }
1207
+
1208
+ /** Get the root identifier of a member expression chain: `a.b.c` → 'a'. */
1209
+ function getMemberRoot(node: Parser.SyntaxNode): string | null {
1210
+ let current = node
1211
+ while (current.type === 'member_expression' || current.type === 'subscript_expression' ||
1212
+ current.type === 'attribute' || current.type === 'subscript') {
1213
+ const obj = current.childForFieldName('object')
1214
+ ?? current.childForFieldName('value') // Python subscript uses 'value' field
1215
+ if (!obj) return null
1216
+ current = obj
1217
+ }
1218
+ return current.type === 'identifier' ? current.text : null
1219
+ }
1220
+
1221
+ // ============================================================================
1222
+ // Source / Sink Mapping
1223
+ // ============================================================================
1224
+
1225
+ export interface SourceMapping {
1226
+ source: TaintSource
1227
+ cfgNodeId: number
1228
+ }
1229
+
1230
+ export interface SinkMapping {
1231
+ sink: TaintSink
1232
+ cfgNodeId: number
1233
+ }
1234
+
1235
+ /**
1236
+ * Map sources to their containing CFG nodes.
1237
+ * Phase 8: accepts optional cfgNodeMap for O(D) lookup instead of O(N).
1238
+ */
1239
+ export function mapSourcesToCFG(
1240
+ cfg: CFG,
1241
+ sources: TaintSource[],
1242
+ cfgNodeMap?: Map<number, CFGNode>,
1243
+ ): SourceMapping[] {
1244
+ const mappings: SourceMapping[] = []
1245
+ for (const source of sources) {
1246
+ const cfgNode = cfgNodeMap
1247
+ ? findContainingCFGNodeFast(cfgNodeMap, source.node)
1248
+ : findContainingCFGNode(cfg, source.node)
1249
+ if (cfgNode) {
1250
+ mappings.push({ source, cfgNodeId: cfgNode.id })
1251
+ }
1252
+ }
1253
+ return mappings
1254
+ }
1255
+
1256
+ /**
1257
+ * Map sinks to their containing CFG nodes.
1258
+ * Phase 8: accepts optional cfgNodeMap for O(D) lookup instead of O(N).
1259
+ */
1260
+ export function mapSinksToCFG(
1261
+ cfg: CFG,
1262
+ sinks: TaintSink[],
1263
+ cfgNodeMap?: Map<number, CFGNode>,
1264
+ ): SinkMapping[] {
1265
+ const mappings: SinkMapping[] = []
1266
+ for (const sink of sinks) {
1267
+ const cfgNode = cfgNodeMap
1268
+ ? findContainingCFGNodeFast(cfgNodeMap, sink.node)
1269
+ : findContainingCFGNode(cfg, sink.node)
1270
+ if (cfgNode) {
1271
+ mappings.push({ sink, cfgNodeId: cfgNode.id })
1272
+ }
1273
+ }
1274
+ return mappings
1275
+ }
1276
+
1277
+ // ============================================================================
1278
+ // Worklist Algorithm
1279
+ // ============================================================================
1280
+
1281
+ const MAX_ITERATIONS = 1000
1282
+
1283
+ /**
1284
+ * Run the worklist fixpoint algorithm on a CFG.
1285
+ *
1286
+ * Seeds taint at source nodes, propagates forward through the CFG until
1287
+ * no more state changes occur (fixpoint). Returns the per-node out-states.
1288
+ *
1289
+ * Exported as runFixpointInternal for use by taint-summary.ts (Phase 8).
1290
+ */
1291
+ export function runFixpointInternal(
1292
+ cfg: CFG,
1293
+ sourceMappings: SourceMapping[],
1294
+ sanitizerMap: Map<number, TaintSanitizer[]>,
1295
+ filePath: string,
1296
+ callContext?: CallResolutionContext,
1297
+ constantMap?: ConstantMap,
1298
+ ): Map<number, TaintState> {
1299
+ // Per-node out-states
1300
+ const outStates = new Map<number, TaintState>()
1301
+ for (const [id] of cfg.nodes) {
1302
+ outStates.set(id, new Map())
1303
+ }
1304
+
1305
+ // Seed sources: set source variable taint in the source node's out-state
1306
+ const worklist = new Set<number>()
1307
+
1308
+ // Build a per-node source seed map so seeds survive worklist overwrites.
1309
+ // Without this, when a predecessor's propagation causes node N to be
1310
+ // re-processed, applyTransfer overwrites the seeded out-state with just
1311
+ // the propagated in-state — losing any source taint that was seeded here.
1312
+ const sourceSeeds = new Map<number, Array<{ variable: string; kinds: Set<TaintKind>; isDestructuring: boolean; defs: Set<string> }>>()
1313
+
1314
+ for (const { source, cfgNodeId } of sourceMappings) {
1315
+ const state = outStates.get(cfgNodeId)!
1316
+ const cfgNode = cfg.nodes.get(cfgNodeId)
1317
+ const varName = source.variable
1318
+
1319
+ const isDestructuring = varName.startsWith('{') || varName.startsWith('[')
1320
+ if (isDestructuring && cfgNode && cfgNode.defs.size > 0) {
1321
+ for (const defVar of cfgNode.defs) {
1322
+ // Phase 8: clone before mutating — getTaint may return internal Set reference
1323
+ const existing = new Set(getTaint(state, defVar) ?? [])
1324
+ for (const k of source.taintKinds) existing.add(k)
1325
+ setTaint(state, defVar, existing)
1326
+ }
1327
+ } else {
1328
+ // Phase 8: clone before mutating — getTaint may return internal Set reference
1329
+ const existing = new Set(getTaint(state, varName) ?? [])
1330
+ for (const k of source.taintKinds) existing.add(k)
1331
+ setTaint(state, varName, existing)
1332
+
1333
+ // For compound source variables (e.g. "req.body", "req.query"), also seed
1334
+ // the root identifier. The expression-level resolver walks member chains
1335
+ // from the root, so `req.body.email` resolves `req` → tainted → propagates.
1336
+ if (varName.includes('.')) {
1337
+ const root = varName.split('.')[0]
1338
+ const rootExisting = new Set(getTaint(state, root) ?? [])
1339
+ for (const k of source.taintKinds) rootExisting.add(k)
1340
+ setTaint(state, root, rootExisting)
1341
+ }
1342
+ }
1343
+
1344
+ // Record seed for re-injection during worklist
1345
+ if (!sourceSeeds.has(cfgNodeId)) sourceSeeds.set(cfgNodeId, [])
1346
+ sourceSeeds.get(cfgNodeId)!.push({
1347
+ variable: varName,
1348
+ kinds: new Set(source.taintKinds),
1349
+ isDestructuring,
1350
+ defs: cfgNode?.defs ?? new Set(),
1351
+ })
1352
+
1353
+ // Push successors to worklist (the source node's out-state is now seeded)
1354
+ for (const succ of getSuccessors(cfg, cfgNodeId)) {
1355
+ worklist.add(succ)
1356
+ }
1357
+ }
1358
+
1359
+ // Iterate to fixpoint
1360
+ let iterations = 0
1361
+
1362
+ while (worklist.size > 0 && iterations < MAX_ITERATIONS) {
1363
+ iterations++
1364
+
1365
+ // Pop first element from worklist
1366
+ const nodeId = worklist.values().next().value!
1367
+ worklist.delete(nodeId)
1368
+
1369
+ const cfgNode = cfg.nodes.get(nodeId)
1370
+ if (!cfgNode) continue
1371
+
1372
+ // Compute in-state = merge of all predecessor out-states
1373
+ // Phase 8 (3a): single-predecessor fast path — skip mergeStates allocation for ~70% of nodes
1374
+ const predIds = getPredecessors(cfg, nodeId)
1375
+ let inState: TaintState
1376
+ if (predIds.length === 1) {
1377
+ const ps = outStates.get(predIds[0])
1378
+ inState = ps ?? new Map()
1379
+ } else {
1380
+ const predStates: TaintState[] = []
1381
+ for (const pId of predIds) {
1382
+ const ps = outStates.get(pId)
1383
+ if (ps) predStates.push(ps)
1384
+ }
1385
+ inState = mergeStates(predStates)
1386
+ }
1387
+
1388
+ // Apply transfer function
1389
+ const newOutState = applyTransfer(cfgNode, inState, sanitizerMap, callContext, filePath, constantMap)
1390
+
1391
+ // Re-inject source seeds: if this node has sources, ensure their taint
1392
+ // survives the transfer function (which only sees predecessor in-state).
1393
+ // Phase 8: clone before mutating — getTaint may return internal Set reference
1394
+ const seeds = sourceSeeds.get(nodeId)
1395
+ if (seeds) {
1396
+ for (const seed of seeds) {
1397
+ if (seed.isDestructuring && seed.defs.size > 0) {
1398
+ for (const defVar of seed.defs) {
1399
+ const existing = new Set(getTaint(newOutState, defVar) ?? [])
1400
+ for (const k of seed.kinds) existing.add(k)
1401
+ setTaint(newOutState, defVar, existing)
1402
+ }
1403
+ } else {
1404
+ const existing = new Set(getTaint(newOutState, seed.variable) ?? [])
1405
+ for (const k of seed.kinds) existing.add(k)
1406
+ setTaint(newOutState, seed.variable, existing)
1407
+
1408
+ if (seed.variable.includes('.')) {
1409
+ const root = seed.variable.split('.')[0]
1410
+ const rootExisting = new Set(getTaint(newOutState, root) ?? [])
1411
+ for (const k of seed.kinds) rootExisting.add(k)
1412
+ setTaint(newOutState, root, rootExisting)
1413
+ }
1414
+ }
1415
+ }
1416
+ }
1417
+
1418
+ // Check if state changed
1419
+ const oldOutState = outStates.get(nodeId)!
1420
+ // Phase 8 (3d): identity check — if applyTransfer returned same ref, no change possible
1421
+ if (newOutState !== oldOutState && !statesEqual(newOutState, oldOutState)) {
1422
+ outStates.set(nodeId, newOutState)
1423
+ // Push all successors to worklist
1424
+ for (const succ of getSuccessors(cfg, nodeId)) {
1425
+ worklist.add(succ)
1426
+ }
1427
+ }
1428
+ }
1429
+
1430
+ if (iterations >= MAX_ITERATIONS) {
1431
+ console.warn(`[taint] Worklist hit iteration limit (${MAX_ITERATIONS}) for ${cfg.functionName} — results may be incomplete`)
1432
+ }
1433
+
1434
+ return outStates
1435
+ }
1436
+
1437
+ /**
1438
+ * Check sinks for tainted data given computed out-states.
1439
+ * Returns findings for each source→sink pair with matching taint kinds.
1440
+ *
1441
+ * Exported as checkSinksInternal for use by taint-summary.ts (Phase 8).
1442
+ */
1443
+ export function checkSinksInternal(
1444
+ cfg: CFG,
1445
+ outStates: Map<number, TaintState>,
1446
+ sinkMappings: SinkMapping[],
1447
+ sourceMappings: SourceMapping[],
1448
+ filePath: string,
1449
+ ): TaintFinding[] {
1450
+ const findings: TaintFinding[] = []
1451
+
1452
+ for (const { sink, cfgNodeId } of sinkMappings) {
1453
+ // The taint state at the sink is the in-state (merge of predecessor outs)
1454
+ const predIds = getPredecessors(cfg, cfgNodeId)
1455
+ const predStates: TaintState[] = []
1456
+ for (const pId of predIds) {
1457
+ const ps = outStates.get(pId)
1458
+ if (ps) predStates.push(ps)
1459
+ }
1460
+ // Also include the sink node's own out-state predecessor contributions
1461
+ // But more importantly, check the in-state to the sink node
1462
+ const sinkInState = mergeStates(predStates)
1463
+
1464
+ // Also check the out-state of the sink's own node (for cases where
1465
+ // source and sink are in the same statement or sink uses vars from its own node)
1466
+ const sinkOutState = outStates.get(cfgNodeId) ?? new Map()
1467
+
1468
+ // Merge both for maximum coverage
1469
+ const combined = mergeStates([sinkInState, sinkOutState])
1470
+
1471
+ // Find which variables at this sink are tainted with matching kinds
1472
+ const sinkNode = cfg.nodes.get(cfgNodeId)
1473
+ if (!sinkNode) continue
1474
+
1475
+ // Get all variables used by the sink expression
1476
+ const sinkUses = extractSinkUses(sink, sinkNode)
1477
+
1478
+ // Extract field-level accesses from the sink for precise taint checking
1479
+ const sinkFieldAccesses = extractSinkFieldAccesses(sink)
1480
+
1481
+ for (const varName of sinkUses) {
1482
+ // Check if this variable has a field-level access in the sink
1483
+ const fieldAccess = sinkFieldAccesses.get(varName)
1484
+ const varTaint = fieldAccess
1485
+ ? getFieldTaint(combined, varName, fieldAccess)
1486
+ : getTaint(combined, varName)
1487
+ if (!varTaint || varTaint.size === 0) continue
1488
+
1489
+ // Find matching kinds: intersection of variable's taint and sink's vulnerable kinds
1490
+ const matchingKinds = new Set<TaintKind>()
1491
+ for (const k of varTaint) {
1492
+ if (sink.vulnerableToKinds.has(k)) {
1493
+ matchingKinds.add(k)
1494
+ }
1495
+ }
1496
+
1497
+ if (matchingKinds.size === 0) continue
1498
+
1499
+ // Find which source(s) contributed this taint
1500
+ for (const { source } of sourceMappings) {
1501
+ // Check if source's taint kinds overlap with matching kinds
1502
+ const sourceOverlap = new Set<TaintKind>()
1503
+ for (const k of matchingKinds) {
1504
+ if (source.taintKinds.has(k)) sourceOverlap.add(k)
1505
+ }
1506
+ if (sourceOverlap.size === 0) continue
1507
+
1508
+ // Reconstruct path
1509
+ const path = reconstructPath(
1510
+ cfg, outStates, source, sink, varName,
1511
+ sourceMappings, cfgNodeId,
1512
+ )
1513
+
1514
+ findings.push({
1515
+ source,
1516
+ sink,
1517
+ path,
1518
+ matchingKinds: sourceOverlap,
1519
+ functionName: cfg.functionName,
1520
+ filePath,
1521
+ })
1522
+ }
1523
+ }
1524
+ }
1525
+
1526
+ return findings
1527
+ }
1528
+
1529
+ /**
1530
+ * Propagate taint through a single function's CFG.
1531
+ *
1532
+ * Returns all taint findings (source→sink pairs with matching kinds).
1533
+ * When callContext is provided, calls to imported/local functions are
1534
+ * resolved inter-procedurally.
1535
+ */
1536
+ export function propagateFunction(
1537
+ cfg: CFG,
1538
+ sourceMappings: SourceMapping[],
1539
+ sinkMappings: SinkMapping[],
1540
+ sanitizerMap: Map<number, TaintSanitizer[]>,
1541
+ filePath: string,
1542
+ callContext?: CallResolutionContext,
1543
+ ): TaintFinding[] {
1544
+ // Collect constants for this function scope
1545
+ const constantMap = cfg.functionNode ? collectConstants(cfg.functionNode) : new Map()
1546
+ const outStates = runFixpointInternal(cfg, sourceMappings, sanitizerMap, filePath, callContext, constantMap)
1547
+ const findings = checkSinksInternal(cfg, outStates, sinkMappings, sourceMappings, filePath)
1548
+ return deduplicateFindings(findings)
1549
+ }
1550
+
1551
+ /**
1552
+ * Extract variables used by a sink expression.
1553
+ * Uses the CFG node's `uses` set plus any identifiers in the sink's AST.
1554
+ *
1555
+ * When `sink.relevantArgNodes` is set (e.g., SSRF sinks), only variables
1556
+ * within those specific argument nodes are collected — taint in other
1557
+ * arguments (like request body) won't trigger the finding.
1558
+ */
1559
+ function extractSinkUses(sink: TaintSink, cfgNode: CFGNode): Set<string> {
1560
+ // When the sink specifies relevant arg nodes, ONLY collect vars from those nodes.
1561
+ // This prevents e.g. tainted body data from triggering SSRF (which requires tainted URL).
1562
+ if (sink.relevantArgNodes && sink.relevantArgNodes.length > 0) {
1563
+ const uses = new Set<string>()
1564
+ for (const argNode of sink.relevantArgNodes) {
1565
+ walkAST(argNode, (node) => {
1566
+ if (node.type === 'identifier') {
1567
+ uses.add(node.text)
1568
+ }
1569
+ if (node.type === 'arrow_function' || node.type === 'function_expression') return true
1570
+ return false
1571
+ })
1572
+ }
1573
+ return uses
1574
+ }
1575
+
1576
+ // Default: collect from entire sink expression + CFG node uses
1577
+ const uses = new Set<string>(cfgNode.uses)
1578
+
1579
+ walkAST(sink.node, (node) => {
1580
+ if (node.type === 'identifier') {
1581
+ uses.add(node.text)
1582
+ }
1583
+ if (node.type === 'arrow_function' || node.type === 'function_expression') return true
1584
+ return false
1585
+ })
1586
+
1587
+ return uses
1588
+ }
1589
+
1590
+ /**
1591
+ * Extract one-level field accesses from a sink expression.
1592
+ * Returns a map of root variable → field name for `obj.field` patterns.
1593
+ * Used for field-sensitive sink checking.
1594
+ */
1595
+ function extractSinkFieldAccesses(sink: TaintSink): Map<string, string> {
1596
+ const accesses = new Map<string, string>()
1597
+
1598
+ // Walk the sink's arguments to find member expression patterns
1599
+ walkAST(sink.node, (node) => {
1600
+ if (node.type === 'member_expression') {
1601
+ const obj = node.childForFieldName('object')
1602
+ const prop = node.childForFieldName('property')
1603
+ if (obj?.type === 'identifier' && prop?.type === 'property_identifier') {
1604
+ accesses.set(obj.text, prop.text)
1605
+ }
1606
+ }
1607
+ if (node.type === 'arrow_function' || node.type === 'function_expression') return true
1608
+ return false
1609
+ })
1610
+
1611
+ return accesses
1612
+ }
1613
+
1614
+ // ============================================================================
1615
+ // Path Reconstruction
1616
+ // ============================================================================
1617
+
1618
+ /**
1619
+ * Reconstruct the path from source to sink via backward slice.
1620
+ */
1621
+ function reconstructPath(
1622
+ cfg: CFG,
1623
+ outStates: Map<number, TaintState>,
1624
+ source: TaintSource,
1625
+ sink: TaintSink,
1626
+ sinkVar: string,
1627
+ sourceMappings: SourceMapping[],
1628
+ sinkNodeId: number,
1629
+ ): TaintStep[] {
1630
+ const steps: TaintStep[] = []
1631
+
1632
+ // Step 1: Sink step
1633
+ const sinkNode = cfg.nodes.get(sinkNodeId)
1634
+ if (sinkNode) {
1635
+ steps.unshift({
1636
+ nodeId: sinkNodeId,
1637
+ line: sink.line,
1638
+ variable: sinkVar,
1639
+ taintKinds: new Set(sink.vulnerableToKinds),
1640
+ description: `SINK ${sink.expression.slice(0, 60)}`,
1641
+ stepType: 'sink',
1642
+ })
1643
+ }
1644
+
1645
+ // Step 2: Walk backward from sink to source
1646
+ const visited = new Set<number>()
1647
+ let currentVar = sinkVar
1648
+ let currentNodeId = sinkNodeId
1649
+
1650
+ for (let depth = 0; depth < 50; depth++) {
1651
+ visited.add(currentNodeId)
1652
+
1653
+ // Check if we've reached a source node
1654
+ const sourceMapping = sourceMappings.find(
1655
+ sm => sm.source === source && sm.cfgNodeId === currentNodeId
1656
+ )
1657
+ if (sourceMapping) break
1658
+
1659
+ // Find a predecessor that has taint for the current variable
1660
+ const predIds = getPredecessors(cfg, currentNodeId)
1661
+ let foundPred = false
1662
+
1663
+ for (const predId of predIds) {
1664
+ if (visited.has(predId)) continue
1665
+
1666
+ const predState = outStates.get(predId)
1667
+ if (!predState) continue
1668
+
1669
+ // Check if this predecessor contributes taint for our variable
1670
+ const predTaint = getTaint(predState, currentVar)
1671
+ if (!predTaint || predTaint.size === 0) continue
1672
+
1673
+ const predNode = cfg.nodes.get(predId)
1674
+ if (!predNode) continue
1675
+
1676
+ // Check if this node defines the variable (it's a propagation step)
1677
+ if (predNode.defs.has(currentVar)) {
1678
+ steps.unshift({
1679
+ nodeId: predId,
1680
+ line: predNode.line,
1681
+ variable: currentVar,
1682
+ taintKinds: new Set(predTaint),
1683
+ description: `ASSIGN ${predNode.label}`,
1684
+ stepType: 'propagation',
1685
+ })
1686
+
1687
+ // Check what variable(s) contributed to this def
1688
+ // Look at the node's uses that are tainted
1689
+ for (const use of predNode.uses) {
1690
+ const useTaint = getTaint(predState, use) // check predecessor's state
1691
+ if (!useTaint || useTaint.size === 0) {
1692
+ // Also check in-state (merge of pred's preds)
1693
+ const predPredIds = getPredecessors(cfg, predId)
1694
+ for (const ppId of predPredIds) {
1695
+ const ppState = outStates.get(ppId)
1696
+ const ppTaint = ppState ? getTaint(ppState, use) : undefined
1697
+ if (ppTaint && ppTaint.size > 0) {
1698
+ currentVar = use
1699
+ break
1700
+ }
1701
+ }
1702
+ if (currentVar !== use) continue
1703
+ } else {
1704
+ currentVar = use
1705
+ }
1706
+ break
1707
+ }
1708
+ }
1709
+
1710
+ currentNodeId = predId
1711
+ foundPred = true
1712
+ break
1713
+ }
1714
+
1715
+ if (!foundPred) break
1716
+ }
1717
+
1718
+ // Step 3: Source step
1719
+ steps.unshift({
1720
+ nodeId: sourceMappings.find(sm => sm.source === source)?.cfgNodeId ?? 0,
1721
+ line: source.line,
1722
+ variable: source.variable,
1723
+ taintKinds: new Set(source.taintKinds),
1724
+ description: `SOURCE ${source.expression.slice(0, 60)}`,
1725
+ stepType: 'source',
1726
+ })
1727
+
1728
+ return steps
1729
+ }
1730
+
1731
+ // ============================================================================
1732
+ // Deduplication
1733
+ // ============================================================================
1734
+
1735
+ /**
1736
+ * Deduplicate findings: same source line + same sink line + same kinds = one finding.
1737
+ */
1738
+ function deduplicateFindings(findings: TaintFinding[]): TaintFinding[] {
1739
+ const seen = new Set<string>()
1740
+ const result: TaintFinding[] = []
1741
+
1742
+ for (const f of findings) {
1743
+ const key = `${f.source.line}:${f.sink.line}:${[...f.matchingKinds].sort().join(',')}`
1744
+ if (seen.has(key)) continue
1745
+ seen.add(key)
1746
+ result.push(f)
1747
+ }
1748
+
1749
+ return result
1750
+ }