@js-recon/js-recon 1.4.4 → 2.0.1-alpha.1

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 (424) hide show
  1. package/.claude-sync/sync.sh +1 -1
  2. package/.github/workflows/build-and-prettify.yaml +49 -19
  3. package/.github/workflows/codeql.yml +33 -0
  4. package/.github/workflows/exploit-smoke-test.yaml +160 -0
  5. package/.github/workflows/framework-detection-smoke-test.yaml +135 -0
  6. package/.github/workflows/plumber.yml +20 -0
  7. package/.github/workflows/promote-js-recon.yml +5 -3
  8. package/.github/workflows/publish-js-recon.yml +6 -1
  9. package/.github/workflows/rules-smoke-test.yaml +13 -5
  10. package/.nvmrc +1 -0
  11. package/.plumber.yaml +151 -0
  12. package/CHANGELOG.md +35 -0
  13. package/CONTRIBUTING.md +32 -0
  14. package/Dockerfile +1 -0
  15. package/README.md +3 -2
  16. package/SECURITY.md +1 -1
  17. package/build/analyze/engine/astEngine.js +10 -9
  18. package/build/analyze/engine/astEngine.js.map +1 -1
  19. package/build/analyze/engine/csMastSEngine.js +6 -6
  20. package/build/analyze/engine/csMastSEngine.js.map +1 -1
  21. package/build/analyze/engine/index.js +1 -1
  22. package/build/analyze/engine/index.js.map +1 -1
  23. package/build/analyze/engine/requestEngine.js +6 -6
  24. package/build/analyze/engine/requestEngine.js.map +1 -1
  25. package/build/analyze/helpers/determineCompatibleVersion.js +70 -0
  26. package/build/analyze/helpers/determineCompatibleVersion.js.map +1 -0
  27. package/build/analyze/helpers/engineHelpers/findMemberExpressionAssignment.js +9 -3
  28. package/build/analyze/helpers/engineHelpers/findMemberExpressionAssignment.js.map +1 -1
  29. package/build/analyze/helpers/initRules.js +9 -9
  30. package/build/analyze/helpers/initRules.js.map +1 -1
  31. package/build/analyze/helpers/outputHelper.js +3 -3
  32. package/build/analyze/helpers/outputHelper.js.map +1 -1
  33. package/build/analyze/helpers/schemas.js +1 -0
  34. package/build/analyze/helpers/schemas.js.map +1 -1
  35. package/build/analyze/helpers/validate.js +9 -5
  36. package/build/analyze/helpers/validate.js.map +1 -1
  37. package/build/analyze/index.js +26 -16
  38. package/build/analyze/index.js.map +1 -1
  39. package/build/cliProgram.js +710 -0
  40. package/build/cliProgram.js.map +1 -0
  41. package/build/completion/index.js +247 -382
  42. package/build/completion/index.js.map +1 -1
  43. package/build/completion/introspect.js +17 -0
  44. package/build/completion/introspect.js.map +1 -0
  45. package/build/config/applicationConfig.js +3 -2
  46. package/build/config/applicationConfig.js.map +1 -1
  47. package/build/cs_mast/index.js +18 -17
  48. package/build/cs_mast/index.js.map +1 -1
  49. package/build/endpoints/gen_report/gen_json.js +2 -2
  50. package/build/endpoints/gen_report/gen_json.js.map +1 -1
  51. package/build/endpoints/gen_report/utility/iterate_n_store.js +1 -1
  52. package/build/endpoints/gen_report/utility/iterate_n_store.js.map +1 -1
  53. package/build/endpoints/index.js +12 -12
  54. package/build/endpoints/index.js.map +1 -1
  55. package/build/endpoints/next_js/client_jsFilesHref.js +3 -3
  56. package/build/endpoints/next_js/client_jsFilesHref.js.map +1 -1
  57. package/build/endpoints/next_js/client_jsonParse.js +4 -4
  58. package/build/endpoints/next_js/client_jsonParse.js.map +1 -1
  59. package/build/endpoints/next_js/client_mappedJsonFile.js +6 -6
  60. package/build/endpoints/next_js/client_mappedJsonFile.js.map +1 -1
  61. package/build/endpoints/next_js/client_subsequentRequests.js +5 -5
  62. package/build/endpoints/next_js/client_subsequentRequests.js.map +1 -1
  63. package/build/exploit/angular/cve-2026-68945.js +61 -0
  64. package/build/exploit/angular/cve-2026-68945.js.map +1 -0
  65. package/build/exploit/index.js +60 -0
  66. package/build/exploit/index.js.map +1 -0
  67. package/build/exploit/next/cve-2025-29927.js +65 -0
  68. package/build/exploit/next/cve-2025-29927.js.map +1 -0
  69. package/build/exploit/next/cve-2026-64645.js +51 -0
  70. package/build/exploit/next/cve-2026-64645.js.map +1 -0
  71. package/build/exploit/nuxt/cve-2026-71315.js +47 -0
  72. package/build/exploit/nuxt/cve-2026-71315.js.map +1 -0
  73. package/build/exploit/nuxt/cve-2026-71320.js +114 -0
  74. package/build/exploit/nuxt/cve-2026-71320.js.map +1 -0
  75. package/build/exploit/react/cve-2025-55182.js +116 -0
  76. package/build/exploit/react/cve-2025-55182.js.map +1 -0
  77. package/build/exploit/registry/cveRegistry.js +115 -0
  78. package/build/exploit/registry/cveRegistry.js.map +1 -0
  79. package/build/exploit/types.js +2 -0
  80. package/build/exploit/types.js.map +1 -0
  81. package/build/exploit/utility/compareResponses.js +29 -0
  82. package/build/exploit/utility/compareResponses.js.map +1 -0
  83. package/build/exploit/utility/outputHelper.js +22 -0
  84. package/build/exploit/utility/outputHelper.js.map +1 -0
  85. package/build/exploit/utility/rawRequest.js +54 -0
  86. package/build/exploit/utility/rawRequest.js.map +1 -0
  87. package/build/exploit/utility/sandboxRce.js +49 -0
  88. package/build/exploit/utility/sandboxRce.js.map +1 -0
  89. package/build/exploit/utility/toEngineOutput.js +28 -0
  90. package/build/exploit/utility/toEngineOutput.js.map +1 -0
  91. package/build/exploit/utility/wsClient.js +78 -0
  92. package/build/exploit/utility/wsClient.js.map +1 -0
  93. package/build/exploit/vite/cve-2025-30208.js +44 -0
  94. package/build/exploit/vite/cve-2025-30208.js.map +1 -0
  95. package/build/exploit/vite/cve-2026-39363.js +60 -0
  96. package/build/exploit/vite/cve-2026-39363.js.map +1 -0
  97. package/build/fingerprint/index.js +3 -2
  98. package/build/fingerprint/index.js.map +1 -1
  99. package/build/globalConfig.js +2 -2
  100. package/build/globalConfig.js.map +1 -1
  101. package/build/index.js +5 -596
  102. package/build/index.js.map +1 -1
  103. package/build/lazyLoad/angular/angular_getFromPageSource.js +3 -3
  104. package/build/lazyLoad/angular/angular_getFromPageSource.js.map +1 -1
  105. package/build/lazyLoad/downloadFilesUtil.js +14 -11
  106. package/build/lazyLoad/downloadFilesUtil.js.map +1 -1
  107. package/build/lazyLoad/downloadQueue.js +5 -1
  108. package/build/lazyLoad/downloadQueue.js.map +1 -1
  109. package/build/lazyLoad/downloadResponse.js +1 -0
  110. package/build/lazyLoad/downloadResponse.js.map +1 -1
  111. package/build/lazyLoad/generic/generic_crawlPages.js +186 -0
  112. package/build/lazyLoad/generic/generic_crawlPages.js.map +1 -0
  113. package/build/lazyLoad/generic/generic_downloadFiles.js +81 -0
  114. package/build/lazyLoad/generic/generic_downloadFiles.js.map +1 -0
  115. package/build/lazyLoad/generic/generic_extractLinks.js +79 -0
  116. package/build/lazyLoad/generic/generic_extractLinks.js.map +1 -0
  117. package/build/lazyLoad/generic/generic_getScriptTags.js +152 -0
  118. package/build/lazyLoad/generic/generic_getScriptTags.js.map +1 -0
  119. package/build/lazyLoad/generic/generic_importMapDiscovery.js +87 -0
  120. package/build/lazyLoad/generic/generic_importMapDiscovery.js.map +1 -0
  121. package/build/lazyLoad/generic/generic_resolveScope.js +61 -0
  122. package/build/lazyLoad/generic/generic_resolveScope.js.map +1 -0
  123. package/build/lazyLoad/generic/generic_scanAttributesForJs.js +122 -0
  124. package/build/lazyLoad/generic/generic_scanAttributesForJs.js.map +1 -0
  125. package/build/lazyLoad/generic/generic_stringsDiscovery.js +103 -0
  126. package/build/lazyLoad/generic/generic_stringsDiscovery.js.map +1 -0
  127. package/build/lazyLoad/generic/generic_webpackChunkPaths.js +56 -0
  128. package/build/lazyLoad/generic/generic_webpackChunkPaths.js.map +1 -0
  129. package/build/lazyLoad/globals.js +31 -0
  130. package/build/lazyLoad/globals.js.map +1 -1
  131. package/build/lazyLoad/index.js +129 -66
  132. package/build/lazyLoad/index.js.map +1 -1
  133. package/build/lazyLoad/methodFilter.js +2 -0
  134. package/build/lazyLoad/methodFilter.js.map +1 -1
  135. package/build/lazyLoad/next_js/NextJsCrawler.js +38 -14
  136. package/build/lazyLoad/next_js/NextJsCrawler.js.map +1 -1
  137. package/build/lazyLoad/next_js/next_GetJSScript.js +3 -3
  138. package/build/lazyLoad/next_js/next_GetJSScript.js.map +1 -1
  139. package/build/lazyLoad/next_js/next_GetLazyResourcesBuildManifestJs.js +4 -4
  140. package/build/lazyLoad/next_js/next_GetLazyResourcesBuildManifestJs.js.map +1 -1
  141. package/build/lazyLoad/next_js/next_GetLazyResourcesWebpackJs.js +13 -11
  142. package/build/lazyLoad/next_js/next_GetLazyResourcesWebpackJs.js.map +1 -1
  143. package/build/lazyLoad/next_js/next_SubsequentRequests.js +7 -6
  144. package/build/lazyLoad/next_js/next_SubsequentRequests.js.map +1 -1
  145. package/build/lazyLoad/next_js/next_bruteForceJsFiles.js +1 -1
  146. package/build/lazyLoad/next_js/next_bruteForceJsFiles.js.map +1 -1
  147. package/build/lazyLoad/next_js/next_buildId.js +2 -2
  148. package/build/lazyLoad/next_js/next_buildId.js.map +1 -1
  149. package/build/lazyLoad/next_js/next_getClientSidePaths.js +2 -2
  150. package/build/lazyLoad/next_js/next_getClientSidePaths.js.map +1 -1
  151. package/build/lazyLoad/next_js/next_parseLayoutJs.js +6 -6
  152. package/build/lazyLoad/next_js/next_parseLayoutJs.js.map +1 -1
  153. package/build/lazyLoad/next_js/next_promiseResolve.js +1 -1
  154. package/build/lazyLoad/next_js/next_promiseResolve.js.map +1 -1
  155. package/build/lazyLoad/next_js/next_routerStateForge.js +341 -0
  156. package/build/lazyLoad/next_js/next_routerStateForge.js.map +1 -0
  157. package/build/lazyLoad/next_js/next_scriptTagsSubsequentRequests.js +1 -1
  158. package/build/lazyLoad/next_js/next_scriptTagsSubsequentRequests.js.map +1 -1
  159. package/build/lazyLoad/next_js/next_serverActionIdScan.js +77 -0
  160. package/build/lazyLoad/next_js/next_serverActionIdScan.js.map +1 -0
  161. package/build/lazyLoad/nuxt_js/nuxt_astParse.js +15 -13
  162. package/build/lazyLoad/nuxt_js/nuxt_astParse.js.map +1 -1
  163. package/build/lazyLoad/nuxt_js/nuxt_getBuildsManifest.js +2 -2
  164. package/build/lazyLoad/nuxt_js/nuxt_getBuildsManifest.js.map +1 -1
  165. package/build/lazyLoad/nuxt_js/nuxt_getFromPageSource.js +3 -3
  166. package/build/lazyLoad/nuxt_js/nuxt_getFromPageSource.js.map +1 -1
  167. package/build/lazyLoad/nuxt_js/nuxt_stringAnalysisJSFiles.js +2 -2
  168. package/build/lazyLoad/nuxt_js/nuxt_stringAnalysisJSFiles.js.map +1 -1
  169. package/build/lazyLoad/react/react_webpackChunkPaths.js +10 -202
  170. package/build/lazyLoad/react/react_webpackChunkPaths.js.map +1 -1
  171. package/build/lazyLoad/researchUtils.js +15 -0
  172. package/build/lazyLoad/researchUtils.js.map +1 -0
  173. package/build/lazyLoad/shared/webpackChunkParsers.js +218 -0
  174. package/build/lazyLoad/shared/webpackChunkParsers.js.map +1 -0
  175. package/build/lazyLoad/stagnation/stagnationMonitor.js +63 -0
  176. package/build/lazyLoad/stagnation/stagnationMonitor.js.map +1 -0
  177. package/build/lazyLoad/svelte/svelte_discoverPagesFromJs.js +1 -0
  178. package/build/lazyLoad/svelte/svelte_discoverPagesFromJs.js.map +1 -1
  179. package/build/lazyLoad/svelte/svelte_getFromPageSource.js +5 -5
  180. package/build/lazyLoad/svelte/svelte_getFromPageSource.js.map +1 -1
  181. package/build/lazyLoad/svelte/svelte_getVersionJson.js +2 -2
  182. package/build/lazyLoad/svelte/svelte_getVersionJson.js.map +1 -1
  183. package/build/lazyLoad/svelte/svelte_recursivePageCrawl.js +6 -6
  184. package/build/lazyLoad/svelte/svelte_recursivePageCrawl.js.map +1 -1
  185. package/build/lazyLoad/svelte/svelte_stringAnalysisJSFiles.js +2 -2
  186. package/build/lazyLoad/svelte/svelte_stringAnalysisJSFiles.js.map +1 -1
  187. package/build/lazyLoad/techDetect/checkAngularJS.js +1 -1
  188. package/build/lazyLoad/techDetect/checkAngularJS.js.map +1 -1
  189. package/build/lazyLoad/techDetect/checkNuxtJS.js +3 -3
  190. package/build/lazyLoad/techDetect/checkNuxtJS.js.map +1 -1
  191. package/build/lazyLoad/techDetect/checkSvelte.js +0 -1
  192. package/build/lazyLoad/techDetect/checkSvelte.js.map +1 -1
  193. package/build/lazyLoad/techDetect/checkVueJS.js +6 -6
  194. package/build/lazyLoad/techDetect/checkVueJS.js.map +1 -1
  195. package/build/lazyLoad/techDetect/index.js +13 -1
  196. package/build/lazyLoad/techDetect/index.js.map +1 -1
  197. package/build/lazyLoad/vue/vue_SingleJsFileOnHome.js +2 -2
  198. package/build/lazyLoad/vue/vue_SingleJsFileOnHome.js.map +1 -1
  199. package/build/lazyLoad/vue/vue_discoverJsFiles.js +12 -10
  200. package/build/lazyLoad/vue/vue_discoverJsFiles.js.map +1 -1
  201. package/build/lazyLoad/vue/vue_getClientSidePaths.js +1 -1
  202. package/build/lazyLoad/vue/vue_getClientSidePaths.js.map +1 -1
  203. package/build/lazyLoad/vue/vue_pageSrc.js +1 -1
  204. package/build/lazyLoad/vue/vue_pageSrc.js.map +1 -1
  205. package/build/lazyLoad/vue/vue_reconstructSourceMaps.js +2 -2
  206. package/build/lazyLoad/vue/vue_reconstructSourceMaps.js.map +1 -1
  207. package/build/lazyLoad/vue/vue_recursiveClientSidePathDownload.js +2 -2
  208. package/build/lazyLoad/vue/vue_recursiveClientSidePathDownload.js.map +1 -1
  209. package/build/lazyLoad/vue/vue_severalJsFilesHome.js +3 -3
  210. package/build/lazyLoad/vue/vue_severalJsFilesHome.js.map +1 -1
  211. package/build/load/index.js +8 -7
  212. package/build/load/index.js.map +1 -1
  213. package/build/map/angular_js/getAngularConnections.js +6 -6
  214. package/build/map/angular_js/getAngularConnections.js.map +1 -1
  215. package/build/map/graphql/resolveGraphql.js +6 -6
  216. package/build/map/graphql/resolveGraphql.js.map +1 -1
  217. package/build/map/index.js +17 -17
  218. package/build/map/index.js.map +1 -1
  219. package/build/map/interactive-mode/commandHandler.js +278 -0
  220. package/build/map/interactive-mode/commandHandler.js.map +1 -0
  221. package/build/map/interactive-mode/commandHelpers.js +189 -0
  222. package/build/map/interactive-mode/commandHelpers.js.map +1 -0
  223. package/build/map/interactive-mode/esqueryGen.js.map +1 -0
  224. package/build/map/interactive-mode/helpMenu.js +11 -0
  225. package/build/map/interactive-mode/helpMenu.js.map +1 -0
  226. package/build/map/interactive-mode/inputPatch.js.map +1 -0
  227. package/build/map/interactive-mode/interactive.js +71 -0
  228. package/build/map/interactive-mode/interactive.js.map +1 -0
  229. package/build/map/interactive-mode/keybindings.js.map +1 -0
  230. package/build/map/interactive-mode/printer.js.map +1 -0
  231. package/build/map/interactive-mode/ui.js.map +1 -0
  232. package/build/map/next_js/getAxiosInstances.js +5 -5
  233. package/build/map/next_js/getAxiosInstances.js.map +1 -1
  234. package/build/map/next_js/getExports.js +4 -4
  235. package/build/map/next_js/getExports.js.map +1 -1
  236. package/build/map/next_js/getFetchInstances.js +10 -10
  237. package/build/map/next_js/getFetchInstances.js.map +1 -1
  238. package/build/map/next_js/getTurbopackConnections.js +8 -8
  239. package/build/map/next_js/getTurbopackConnections.js.map +1 -1
  240. package/build/map/next_js/getWebpackConnections.js +27 -16
  241. package/build/map/next_js/getWebpackConnections.js.map +1 -1
  242. package/build/map/next_js/interactive.js +3 -65
  243. package/build/map/next_js/interactive.js.map +1 -1
  244. package/build/map/next_js/interactive_helpers/commandHandler.js +38 -290
  245. package/build/map/next_js/interactive_helpers/commandHandler.js.map +1 -1
  246. package/build/map/next_js/interactive_helpers/commandHelpers.js +0 -184
  247. package/build/map/next_js/interactive_helpers/commandHelpers.js.map +1 -1
  248. package/build/map/next_js/interactive_helpers/helpMenu.js +2 -10
  249. package/build/map/next_js/interactive_helpers/helpMenu.js.map +1 -1
  250. package/build/map/next_js/resolveAxios.js +6 -6
  251. package/build/map/next_js/resolveAxios.js.map +1 -1
  252. package/build/map/next_js/resolveAxiosHelpers/findAxiosClients.js +4 -4
  253. package/build/map/next_js/resolveAxiosHelpers/findAxiosClients.js.map +1 -1
  254. package/build/map/next_js/resolveAxiosHelpers/findAxiosInstance.js +2 -2
  255. package/build/map/next_js/resolveAxiosHelpers/findAxiosInstance.js.map +1 -1
  256. package/build/map/next_js/resolveAxiosHelpers/findCrossChunkParams.js +5 -5
  257. package/build/map/next_js/resolveAxiosHelpers/findCrossChunkParams.js.map +1 -1
  258. package/build/map/next_js/resolveAxiosHelpers/handleAxiosCreate.js +10 -10
  259. package/build/map/next_js/resolveAxiosHelpers/handleAxiosCreate.js.map +1 -1
  260. package/build/map/next_js/resolveAxiosHelpers/handleZDotCreate.js +13 -9
  261. package/build/map/next_js/resolveAxiosHelpers/handleZDotCreate.js.map +1 -1
  262. package/build/map/next_js/resolveAxiosHelpers/processAxiosCall.js +12 -8
  263. package/build/map/next_js/resolveAxiosHelpers/processAxiosCall.js.map +1 -1
  264. package/build/map/next_js/resolveAxiosHelpers/processDirectAxiosCall.js +12 -8
  265. package/build/map/next_js/resolveAxiosHelpers/processDirectAxiosCall.js.map +1 -1
  266. package/build/map/next_js/resolveAxiosHelpers/processExportedEndpoints.js +11 -11
  267. package/build/map/next_js/resolveAxiosHelpers/processExportedEndpoints.js.map +1 -1
  268. package/build/map/next_js/resolveAxiosHelpers/traceAxiosInstanceExports.js +16 -16
  269. package/build/map/next_js/resolveAxiosHelpers/traceAxiosInstanceExports.js.map +1 -1
  270. package/build/map/next_js/resolveFetch.js +23 -23
  271. package/build/map/next_js/resolveFetch.js.map +1 -1
  272. package/build/map/next_js/resolveNewRequest.js +10 -10
  273. package/build/map/next_js/resolveNewRequest.js.map +1 -1
  274. package/build/map/next_js/resolveServerActions.js +4 -4
  275. package/build/map/next_js/resolveServerActions.js.map +1 -1
  276. package/build/map/next_js/utils.js +8 -2
  277. package/build/map/next_js/utils.js.map +1 -1
  278. package/build/map/react_js/getReactConnections.js +21 -14
  279. package/build/map/react_js/getReactConnections.js.map +1 -1
  280. package/build/map/svelte_js/interactive.js +3 -54
  281. package/build/map/svelte_js/interactive.js.map +1 -1
  282. package/build/map/vue_js/getViteConnections.js +23 -16
  283. package/build/map/vue_js/getViteConnections.js.map +1 -1
  284. package/build/map/vue_js/interactive.js +3 -63
  285. package/build/map/vue_js/interactive.js.map +1 -1
  286. package/build/map/vue_js/interactive_helpers/commandHandler.js +34 -283
  287. package/build/map/vue_js/interactive_helpers/commandHandler.js.map +1 -1
  288. package/build/map/vue_js/interactive_helpers/helpMenu.js +2 -10
  289. package/build/map/vue_js/interactive_helpers/helpMenu.js.map +1 -1
  290. package/build/map/vue_js/taint_utils.js +1 -1
  291. package/build/map/vue_js/taint_utils.js.map +1 -1
  292. package/build/map/vue_js/vue_resolveFetch.js +12 -12
  293. package/build/map/vue_js/vue_resolveFetch.js.map +1 -1
  294. package/build/map/vue_js/vue_resolveHttpClient.js +18 -18
  295. package/build/map/vue_js/vue_resolveHttpClient.js.map +1 -1
  296. package/build/map/vue_js/vue_resolveXhr.js +11 -11
  297. package/build/map/vue_js/vue_resolveXhr.js.map +1 -1
  298. package/build/mcp/chatOneShot.js +7 -7
  299. package/build/mcp/chatOneShot.js.map +1 -1
  300. package/build/mcp/claudeCodeCreds.js +5 -5
  301. package/build/mcp/claudeCodeCreds.js.map +1 -1
  302. package/build/mcp/cli.js +36 -35
  303. package/build/mcp/cli.js.map +1 -1
  304. package/build/mcp/config.js +4 -4
  305. package/build/mcp/config.js.map +1 -1
  306. package/build/mcp/index.js +7 -7
  307. package/build/mcp/index.js.map +1 -1
  308. package/build/mcp/mcpServer.js +3 -2
  309. package/build/mcp/mcpServer.js.map +1 -1
  310. package/build/mcp/skills.js +1 -0
  311. package/build/mcp/skills.js.map +1 -1
  312. package/build/mcp/tools.js +5 -4
  313. package/build/mcp/tools.js.map +1 -1
  314. package/build/proxy/detectBlockedResponse.js +2 -0
  315. package/build/proxy/detectBlockedResponse.js.map +1 -1
  316. package/build/proxy/index.js +3 -3
  317. package/build/proxy/index.js.map +1 -1
  318. package/build/refactor/index.js +83 -79
  319. package/build/refactor/index.js.map +1 -1
  320. package/build/refactor/next/index.js +69 -26
  321. package/build/refactor/next/index.js.map +1 -1
  322. package/build/refactor/next/transform.js +11 -4
  323. package/build/refactor/next/transform.js.map +1 -1
  324. package/build/refactor/next/validator.js +7 -7
  325. package/build/refactor/next/validator.js.map +1 -1
  326. package/build/refactor/react/index.js +13 -13
  327. package/build/refactor/react/index.js.map +1 -1
  328. package/build/refactor/react/validator.js +7 -7
  329. package/build/refactor/react/validator.js.map +1 -1
  330. package/build/refactor/react-vite/index.js +3 -3
  331. package/build/refactor/react-vite/index.js.map +1 -1
  332. package/build/refactor/remote/hf-client.js +1 -0
  333. package/build/refactor/remote/hf-client.js.map +1 -1
  334. package/build/refactor/remote/version-detect.js +12 -12
  335. package/build/refactor/remote/version-detect.js.map +1 -1
  336. package/build/refactor/vue/index.js +6 -6
  337. package/build/refactor/vue/index.js.map +1 -1
  338. package/build/refactor/vue/vite.js +6 -6
  339. package/build/refactor/vue/vite.js.map +1 -1
  340. package/build/report/index.js +30 -8
  341. package/build/report/index.js.map +1 -1
  342. package/build/report/swaggerJacker.js +63 -0
  343. package/build/report/swaggerJacker.js.map +1 -0
  344. package/build/report/utility/genHtml.js +7 -7
  345. package/build/report/utility/genHtml.js.map +1 -1
  346. package/build/report/utility/populateDb/populateAnalysisFindings.js +2 -2
  347. package/build/report/utility/populateDb/populateAnalysisFindings.js.map +1 -1
  348. package/build/report/utility/populateDb/populateEndpoints.js +3 -3
  349. package/build/report/utility/populateDb/populateEndpoints.js.map +1 -1
  350. package/build/report/utility/populateDb/populateMappedJson.js +2 -2
  351. package/build/report/utility/populateDb/populateMappedJson.js.map +1 -1
  352. package/build/report/utility/populateDb/populateMappedOpenapi.js +3 -3
  353. package/build/report/utility/populateDb/populateMappedOpenapi.js.map +1 -1
  354. package/build/run/bundler-detect.js +45 -9
  355. package/build/run/bundler-detect.js.map +1 -1
  356. package/build/run/dashboard/dashboardHtml.js +150 -0
  357. package/build/run/dashboard/dashboardHtml.js.map +1 -0
  358. package/build/run/dashboard/fsBrowser.js +43 -0
  359. package/build/run/dashboard/fsBrowser.js.map +1 -0
  360. package/build/run/dashboard/server.js +123 -0
  361. package/build/run/dashboard/server.js.map +1 -0
  362. package/build/run/dashboard/state.js +97 -0
  363. package/build/run/dashboard/state.js.map +1 -0
  364. package/build/run/index.js +177 -110
  365. package/build/run/index.js.map +1 -1
  366. package/build/run/interruptHandler.js +18 -0
  367. package/build/run/interruptHandler.js.map +1 -1
  368. package/build/sourcemaps/index.js +7 -6
  369. package/build/sourcemaps/index.js.map +1 -1
  370. package/build/strings/index.js +27 -24
  371. package/build/strings/index.js.map +1 -1
  372. package/build/strings/openapi.js +4 -4
  373. package/build/strings/openapi.js.map +1 -1
  374. package/build/strings/permutate.js +4 -4
  375. package/build/strings/permutate.js.map +1 -1
  376. package/build/strings/secrets.js +1 -0
  377. package/build/strings/secrets.js.map +1 -1
  378. package/build/strings/trufflehog.js +66 -19
  379. package/build/strings/trufflehog.js.map +1 -1
  380. package/build/strings/trufflehogConfig.js +36 -0
  381. package/build/strings/trufflehogConfig.js.map +1 -0
  382. package/build/strings/trufflehogDownload.js +115 -0
  383. package/build/strings/trufflehogDownload.js.map +1 -0
  384. package/build/utility/ai.js +33 -4
  385. package/build/utility/ai.js.map +1 -1
  386. package/build/utility/banner.js +4 -3
  387. package/build/utility/banner.js.map +1 -1
  388. package/build/utility/configureSandbox.js +2 -2
  389. package/build/utility/configureSandbox.js.map +1 -1
  390. package/build/utility/globals.js +19 -11
  391. package/build/utility/globals.js.map +1 -1
  392. package/build/utility/heap.js +2 -1
  393. package/build/utility/heap.js.map +1 -1
  394. package/build/utility/makeReq.js +1 -1
  395. package/build/utility/makeReq.js.map +1 -1
  396. package/build/utility/openapiGenerator.js +2 -2
  397. package/build/utility/openapiGenerator.js.map +1 -1
  398. package/build/utility/printMsg.js +53 -0
  399. package/build/utility/printMsg.js.map +1 -0
  400. package/build/utility/progressLog.js +4 -3
  401. package/build/utility/progressLog.js.map +1 -1
  402. package/build/utility/resolvePath.js +2 -1
  403. package/build/utility/resolvePath.js.map +1 -1
  404. package/build/utility/ruleVersionMap.js +73 -0
  405. package/build/utility/ruleVersionMap.js.map +1 -0
  406. package/contributing/testing.md +106 -0
  407. package/eslint.config.js +24 -0
  408. package/package.json +22 -5
  409. package/scripts/exploit-smoke-test.js +82 -0
  410. package/scripts/framework-detect-smoke-test.js +64 -0
  411. package/scripts/postinstall-completion.mjs +40 -0
  412. package/scripts/smoke-test.js +12 -0
  413. package/build/lazyLoad/downloadLoadedJsUtil.js +0 -98
  414. package/build/lazyLoad/downloadLoadedJsUtil.js.map +0 -1
  415. package/build/map/next_js/interactive_helpers/esqueryGen.js.map +0 -1
  416. package/build/map/next_js/interactive_helpers/inputPatch.js.map +0 -1
  417. package/build/map/next_js/interactive_helpers/keybindings.js.map +0 -1
  418. package/build/map/next_js/interactive_helpers/printer.js.map +0 -1
  419. package/build/map/next_js/interactive_helpers/ui.js.map +0 -1
  420. /package/build/map/{next_js/interactive_helpers → interactive-mode}/esqueryGen.js +0 -0
  421. /package/build/map/{next_js/interactive_helpers → interactive-mode}/inputPatch.js +0 -0
  422. /package/build/map/{next_js/interactive_helpers → interactive-mode}/keybindings.js +0 -0
  423. /package/build/map/{next_js/interactive_helpers → interactive-mode}/printer.js +0 -0
  424. /package/build/map/{next_js/interactive_helpers → interactive-mode}/ui.js +0 -0
@@ -0,0 +1,710 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { Command, Argument } from "commander";
11
+ import chalk from "chalk";
12
+ import lazyLoad from "./lazyLoad/index.js";
13
+ import { FRAMEWORK_METHODS, VALID_METHODS } from "./lazyLoad/methodFilter.js";
14
+ import endpoints from "./endpoints/index.js";
15
+ import CONFIG from "./globalConfig.js";
16
+ import strings from "./strings/index.js";
17
+ import proxy from "./proxy/index.js";
18
+ import configureProxy from "./utility/configureProxy.js";
19
+ import map from "./map/index.js";
20
+ import * as globalsUtil from "./utility/globals.js";
21
+ import refactor from "./refactor/index.js";
22
+ import run from "./run/index.js";
23
+ import analyze from "./analyze/index.js";
24
+ import report from "./report/index.js";
25
+ import exploit, { printCveList } from "./exploit/index.js";
26
+ import configureSandbox from "./utility/configureSandbox.js";
27
+ import mcp from "./mcp/index.js";
28
+ import load from "./load/index.js";
29
+ import fingerprint from "./fingerprint/index.js";
30
+ import { applyHeapLimit } from "./utility/heap.js";
31
+ import csMast from "./cs_mast/index.js";
32
+ import sourcemaps from "./sourcemaps/index.js";
33
+ import completion from "./completion/index.js";
34
+ import { getLoadedApplicationConfig, prepareProgramConfiguration } from "./config/applicationConfig.js";
35
+ import { configureOxylabsFallback, getOxylabsFallbackConfiguration, OxylabsFallbackConfigurationError, resolveOxylabsFallback, } from "./proxy/oxylabsFallback.js";
36
+ import { collectTargetInput } from "./utility/targetInputs.js";
37
+ /** Valid AI options for analysis modules */
38
+ const validAiOptions = ["description"];
39
+ /**
40
+ * Validates a --max-heap value.
41
+ * @param rawValue Raw value provided via CLI.
42
+ */
43
+ function parseMaxHeapMb(rawValue) {
44
+ const parsed = parseInt(rawValue !== null && rawValue !== void 0 ? rawValue : "0", 10);
45
+ if (!Number.isInteger(parsed) || parsed < 0) {
46
+ console.error(chalk.red(`[!] Invalid --max-heap value: ${rawValue}. Use 0 or a positive integer (MB).`));
47
+ process.exit(1);
48
+ }
49
+ return parsed;
50
+ }
51
+ /**
52
+ * Validates a timeout string and updates the global request timeout.
53
+ * @param timeoutValue Timeout value provided via CLI.
54
+ */
55
+ function validateAndSetTimeout(timeoutValue) {
56
+ const parsedTimeout = parseInt(timeoutValue, 10);
57
+ if (Number.isNaN(parsedTimeout) || parsedTimeout < 1) {
58
+ console.error(chalk.yellow(`[!] Invalid timeout value: "${timeoutValue}". Using default of 30000ms.`));
59
+ globalsUtil.setRequestTimeout(30000);
60
+ }
61
+ else {
62
+ globalsUtil.setRequestTimeout(parsedTimeout);
63
+ }
64
+ }
65
+ /**
66
+ * Builds the fully-configured js-recon Commander program.
67
+ *
68
+ * Returns a fresh `Command` instance every call so this can be safely invoked more than once in
69
+ * the same process (e.g. once for the real CLI entrypoint and again by the completion generator
70
+ * for introspection) without "command already registered" collisions from reusing a singleton.
71
+ */
72
+ export function buildProgram() {
73
+ const program = new Command();
74
+ program
75
+ .version(CONFIG.version)
76
+ .description(CONFIG.toolDesc)
77
+ .option("--config <file>", "Application YAML config (default: ~/.config/js-recon/config.yaml; JS_RECON_CONFIG takes precedence)");
78
+ program.configureHelp({
79
+ styleTitle: (str) => chalk.bold.cyan(str),
80
+ styleCommandText: (str) => chalk.bold(str),
81
+ styleCommandDescription: (str) => chalk.dim(str),
82
+ styleDescriptionText: (str) => chalk.dim(str),
83
+ styleOptionText: (str) => chalk.yellow(str),
84
+ styleArgumentText: (str) => chalk.green(str),
85
+ styleSubcommandText: (str) => chalk.cyan(str),
86
+ styleOptionTerm: (str) => {
87
+ // Color flags yellow, <required> args magenta, [optional] args cyan
88
+ return str
89
+ .split(" ")
90
+ .map((word) => {
91
+ if (word.startsWith("<") && word.endsWith(">"))
92
+ return chalk.magenta(word);
93
+ if (word.startsWith("[") && word.endsWith("]"))
94
+ return chalk.cyan(word);
95
+ return chalk.yellow(word);
96
+ })
97
+ .join(" ");
98
+ },
99
+ styleOptionDescription: (str) => str.replace(/(\(default:[^)]*\))/g, chalk.dim.italic("$1")),
100
+ });
101
+ program
102
+ .command("lazyload")
103
+ .description("Run lazy load module")
104
+ .option("-u, --url <url/list/file>", "Target URL, comma-separated URLs, or target file; may be repeated", collectTargetInput)
105
+ .option("-o, --output <directory>", "Output directory", "output")
106
+ .option("--strict-scope", "Download JS files from only the input URL domain", false)
107
+ .option("-s, --scope <scope>", "Download JS files from specific domains (comma-separated)", "*")
108
+ .option("-t, --threads <threads>", "Number of threads to use", "1")
109
+ .option("--subsequent-requests", "Download JS files from subsequent requests (Next.JS only)", false)
110
+ .option("--urls-file <file>", "Input JSON file containing URLs", "extracted_urls.json")
111
+ .option("--proxy-config <file>", "Proxy config file (generated via the `proxy` module)", ".proxy_config.json")
112
+ .option("--ignore-proxy-env", "Skip JS_RECON_* proxy environment variables during resolution", false)
113
+ .option("--oxylabs-waf-fallback", "Retry strongly identified CDN/WAF blocks through configured Oxylabs; direct requests remain the default", false)
114
+ .option("--oxylabs-fallback-max-requests <count>", "Maximum paid Oxylabs fallback requests per origin", "10")
115
+ .option("--oxylabs-fallback-max-total <count>", "Maximum paid Oxylabs fallback requests per run", "100")
116
+ .option("--oxylabs-fallback-max-origins <count>", "Maximum distinct fallback origins per run", "25")
117
+ .option("--cache-file <file>", "File to store response cache", ".resp_cache.json")
118
+ .option("--disable-cache", "Disable response caching", false)
119
+ .option("--cache-only", "Only use the response cache; never make network requests", false)
120
+ .option("-y, --yes", "Auto-approve executing JS code from the target", false)
121
+ .option("--timeout <timeout>", "Request timeout in ms", "30000")
122
+ .option("-k, --insecure", "Disable SSL certificate verification", false)
123
+ .option("--no-sandbox", "Disable browser sandbox")
124
+ .option("--build-id", "Get the buildId from the Next.js app", false)
125
+ .option("--sourcemap-dir <directory>", "Directory to write source maps", "extracted")
126
+ .option("--research", "Enable research mode", false)
127
+ .option("--research-output <file>", "Output file for research mode", "research.json")
128
+ .option("--max-iterations <iterations>", "Maximum number of recursive crawl iterations", "10")
129
+ .option("--max-js-size <mb>", "Maximum JS file size in MB to parse (Vue only)", "2")
130
+ .option("--lazyload-timeout <minutes>", "Hard timeout for the lazyload module in minutes (0 = no timeout)", "30")
131
+ .option("--detection-timeout <seconds>", "Timeout for front-end framework detection in seconds (0 = no timeout)", "30")
132
+ .option("--max-pages <pages>", "Maximum HTML pages to visit during Next.js crawl (0 = unlimited)", "200")
133
+ .option("--rsc-param-bruteforce-limit <n>", "Max harvested dynamic-route param-name candidates to try per URL in next_routerStateForge's RSC-body keyword fallback (0 = disable the fallback)", "20")
134
+ .option("--verbose", "Show detailed file write error messages", false)
135
+ .option("--max-redirects <n>", "Maximum redirects to follow when resolving the default crawl scope for generic tech", "20")
136
+ .option("--strings", "Enable strings-based recursive JS discovery for generic tech (scans downloaded files for string-literal JS paths)", false)
137
+ .option("--strings-max-iterations <n>", "Maximum recursive strings-discovery passes for generic tech (0 = unlimited, loops until no new files)", "5")
138
+ .option("--stagnation-timein <mins>", "Minutes to wait before generic-tech content stagnation detection begins monitoring (0 = disabled)", "30")
139
+ .option("--stagnation-percentage <percent>", "Percentage of discovered generic-tech JS files sharing identical content required to flag stagnation", "80")
140
+ .option("--stagnation-monitor <mins>", "Interval in minutes between generic-tech stagnation re-checks once armed", "1")
141
+ .option("--include-methods <methods>", "Comma-separated method names to run (whitelist). Use --list-methods to see valid names.")
142
+ .option("--exclude-methods <methods>", "Comma-separated method names to skip (blacklist). Use --list-methods to see valid names.")
143
+ .option("--list-methods [framework]", "Print available method names grouped by framework and exit. Optionally filter by framework (next_js, vue, nuxt_js, svelte, angular, react).")
144
+ .action((cmd) => __awaiter(this, void 0, void 0, function* () {
145
+ // handle --list-methods before any network work
146
+ if (cmd.listMethods !== undefined) {
147
+ const filter = typeof cmd.listMethods === "string" ? cmd.listMethods : null;
148
+ const frameworkKeys = Object.keys(FRAMEWORK_METHODS);
149
+ if (filter && !frameworkKeys.includes(filter)) {
150
+ console.error(chalk.red(`[!] Unknown framework: "${filter}". Valid frameworks: ${frameworkKeys.join(", ")}`));
151
+ process.exit(1);
152
+ }
153
+ const keys = filter ? [filter] : frameworkKeys;
154
+ for (const fw of keys) {
155
+ console.log(chalk.cyan(`\n[${fw}]`));
156
+ for (const method of FRAMEWORK_METHODS[fw]) {
157
+ console.log(chalk.green(` - ${method}`));
158
+ }
159
+ }
160
+ process.exit(0);
161
+ }
162
+ // parse and validate method filter lists
163
+ const includeMethods = cmd.includeMethods
164
+ ? cmd.includeMethods
165
+ .split(",")
166
+ .map((m) => m.trim())
167
+ .filter(Boolean)
168
+ : [];
169
+ const excludeMethods = cmd.excludeMethods
170
+ ? cmd.excludeMethods
171
+ .split(",")
172
+ .map((m) => m.trim())
173
+ .filter(Boolean)
174
+ : [];
175
+ const allMethods = [...includeMethods, ...excludeMethods];
176
+ const invalid = allMethods.filter((m) => !VALID_METHODS.includes(m));
177
+ if (invalid.length > 0) {
178
+ console.error(chalk.red(`[!] Invalid method name(s): ${invalid.join(", ")}`));
179
+ console.error(chalk.yellow(`[i] Valid methods: ${VALID_METHODS.join(", ")}`));
180
+ process.exit(22);
181
+ }
182
+ if (!cmd.url || (Array.isArray(cmd.url) && cmd.url.length === 0)) {
183
+ console.error(chalk.red("[!] Missing required option: -u, --url <url/list/file>"));
184
+ process.exit(1);
185
+ }
186
+ const lazyloadTimeoutMin = Number(cmd.lazyloadTimeout);
187
+ const stagnationTimeinMin = Number(cmd.stagnationTimein);
188
+ if (lazyloadTimeoutMin > 0 && stagnationTimeinMin > lazyloadTimeoutMin) {
189
+ console.error(chalk.red(`[!] --stagnation-timein (${stagnationTimeinMin}m) cannot exceed --lazyload-timeout (${lazyloadTimeoutMin}m)`));
190
+ process.exit(30);
191
+ }
192
+ configureProxy(cmd);
193
+ if (getOxylabsFallbackConfiguration().enabled)
194
+ globalsUtil.setUseProxy(false);
195
+ globalsUtil.setDisableCache(cmd.disableCache);
196
+ globalsUtil.setRespCacheFile(cmd.cacheFile);
197
+ globalsUtil.setCacheOnly(cmd.cacheOnly);
198
+ globalsUtil.setYes(cmd.yes);
199
+ globalsUtil.setVerbose(cmd.verbose);
200
+ validateAndSetTimeout(cmd.timeout);
201
+ configureSandbox(cmd);
202
+ yield lazyLoad(cmd.url, cmd.output, cmd.strictScope, cmd.scope.split(","), Number(cmd.threads), cmd.subsequentRequests, cmd.urlsFile, cmd.insecure, cmd.buildId, cmd.sourcemapDir, cmd.research, cmd.researchOutput, Number(cmd.maxIterations), Number(cmd.maxJsSize), Number(cmd.lazyloadTimeout) * 60 * 1000, Number(cmd.maxPages), includeMethods, excludeMethods, Number(cmd.detectionTimeout) * 1000, undefined, false, Number(cmd.maxRedirects), cmd.strings, Number(cmd.stringsMaxIterations), Number(cmd.stagnationTimein) * 60 * 1000, Number(cmd.stagnationPercentage), Number(cmd.stagnationMonitor) * 60 * 1000, Number(cmd.rscParamBruteforceLimit));
203
+ }));
204
+ program
205
+ .command("endpoints")
206
+ .description("Extract client-side endpoints")
207
+ .option("-u, --url <url>", "Target Base URL (will be used to resolve relative paths)")
208
+ .option("-d, --directory <directory>", "Directory containing JS files")
209
+ .option("-o, --output <filename>", "Output filename (without file extension)", "endpoints")
210
+ .option("--output-format <format>", "Output format for the results comma-separated (available: json)", "json")
211
+ .option("-t, --tech <tech>", "Technology used in the JS files (run with -l/--list to see available options)")
212
+ .option("-l, --list", "List available technologies", false)
213
+ .option("--mapped-json <file>", "Mapped JSON file (for Next.JS)")
214
+ .action((cmd) => __awaiter(this, void 0, void 0, function* () {
215
+ yield endpoints(cmd.url, cmd.directory, cmd.output, cmd.outputFormat.split(","), cmd.tech, cmd.list, cmd.mappedJson);
216
+ }));
217
+ program
218
+ .command("strings")
219
+ .description("Extract strings from JS files")
220
+ .requiredOption("-d, --directory <directory>", "Directory containing JS files")
221
+ .option("-o, --output <file>", "JSON file to save the strings", "strings.json")
222
+ .option("-e, --extract-urls", "Extract URLs from strings", false)
223
+ .option("--extracted-url-path <file>", "Output file for extracted URLs and paths (without extension)", "extracted_urls")
224
+ .option("-p, --permutate", "Permutate URLs and paths found", false)
225
+ .option("--openapi", "Generate OpenAPI specification from the paths found", false)
226
+ .option("-s, --scan-secrets", "Scan for secrets", false)
227
+ .option("--trufflehog", "Run TruffleHog secret scanner on the output directory", false)
228
+ .option("--trufflehog-bin <path>", "Path to the trufflehog binary (skips auto-download)", "trufflehog")
229
+ .option("--trufflehog-accept-terms", "Accept TruffleHog's AGPL-3.0 license terms non-interactively so it can be auto-downloaded (required in non-TTY/CI contexts on first use)", false)
230
+ .action((cmd) => __awaiter(this, void 0, void 0, function* () {
231
+ yield strings(cmd.directory, cmd.output, cmd.extractUrls, cmd.extractedUrlPath, cmd.scanSecrets, cmd.permutate, cmd.openapi, cmd.trufflehog, cmd.trufflehogBin, cmd.trufflehogAcceptTerms);
232
+ }));
233
+ program
234
+ .command("proxy")
235
+ .description("Manage proxy configuration (AWS API Gateway IP rotation, SOCKS/HTTP, Oxylabs)")
236
+ .option("-i, --init", "Initialize the config file (create API) [aws method]", false)
237
+ .option("-d, --destroy <id>", "Destroy API with the given ID [aws method]")
238
+ .option("--destroy-all", "Destroy all the API created by this tool in all regions [aws method]", false)
239
+ .option("-r, --region <region>", "AWS region (default: random region) [aws method]")
240
+ .option("--aws-access-key <key>", "AWS access key (if not provided, AWS_ACCESS_KEY_ID environment variable will be used) [aws method]")
241
+ .option("--aws-secret-key <key>", "AWS secret key (if not provided, AWS_SECRET_ACCESS_KEY environment variable will be used) [aws method]")
242
+ .option("-c, --config <config>", "Name of the config file", ".proxy_config.json")
243
+ .option("-l, --list", "List all the API created by this tool [aws method]", false)
244
+ .option("--feasibility", "Check whether a firewall/WAF blocks the target directly and, if so, whether the proxy method (--proxy-method, or the one already configured via -i/--init) bypasses it", false)
245
+ .option("--feasibility-url <url>", "URL to check feasibility of")
246
+ .option("--proxy-method <method>", "Proxy method to configure with -i/--init: aws, socks, http, or oxylabs (omit for an interactive prompt)")
247
+ .option("--proxy <url>", "SOCKS5/HTTP proxy URL for -i/--init (socks5://[user:pass@]host:port or http://[user:pass@]host:port)")
248
+ .option("--oxylabs-username <username>", "Oxylabs datacenter proxy username for -i/--init")
249
+ .option("--oxylabs-password <password>", "Oxylabs datacenter proxy password for -i/--init")
250
+ .option("--oxylabs-country <country>", "Oxylabs datacenter proxy country code for -i/--init")
251
+ .option("--oxylabs-city <city>", "Oxylabs datacenter proxy city for -i/--init (currently unsupported — no documented username-level city targeting)")
252
+ .option("--oxylabs-session-id <id>", "Oxylabs datacenter proxy sticky session id for -i/--init (currently unsupported via username — sessions are selected by port)")
253
+ .action((cmd) => __awaiter(this, void 0, void 0, function* () {
254
+ try {
255
+ yield proxy({
256
+ init: cmd.init,
257
+ destroy: cmd.destroy,
258
+ destroyAll: cmd.destroyAll,
259
+ list: cmd.list,
260
+ region: cmd.region,
261
+ awsAccessKey: cmd.awsAccessKey,
262
+ awsSecretKey: cmd.awsSecretKey,
263
+ config: cmd.config,
264
+ feasibility: cmd.feasibility,
265
+ feasibilityUrl: cmd.feasibilityUrl,
266
+ proxyMethod: cmd.proxyMethod,
267
+ proxyUrl: cmd.proxy,
268
+ oxylabsUsername: cmd.oxylabsUsername,
269
+ oxylabsPassword: cmd.oxylabsPassword,
270
+ oxylabsCountry: cmd.oxylabsCountry,
271
+ oxylabsCity: cmd.oxylabsCity,
272
+ oxylabsSessionId: cmd.oxylabsSessionId,
273
+ });
274
+ }
275
+ catch (err) {
276
+ console.error(chalk.red(`[!] ${err.message}`));
277
+ process.exit(1);
278
+ }
279
+ }));
280
+ program
281
+ .command("map")
282
+ .description("Map all the functions")
283
+ .option("-d, --directory <directory>", "Directory containing JS files")
284
+ .option("-t, --tech <tech>", "Technology used in the JS files (run with -l/--list to see available options)")
285
+ .option("-l, --list", "List available technologies", false)
286
+ .option("-o, --output <file>", "Output file name (without extension)", "mapped")
287
+ .option("-f, --format <format>", "Output format for the results comma-separated (available: JSON)", "json")
288
+ .option("-i, --interactive", "Interactive mode", false)
289
+ .option("-c, --command <command>", "Run an interactive-mode command non-interactively. Can be passed multiple times, or chain several with `&&` inside a single value (e.g. -c 'list fetch && go to 1234'), to run several commands in sequence.", (val, prev) => [...prev, ...val.split(/\s*&&\s*/).filter((c) => c.length > 0)], [])
290
+ .option("--ai <options>", "Use AI to analyze the code (comma-separated; available: description)")
291
+ .option("--ai-threads <threads>", "Number of threads to use for AI", "5")
292
+ .option("--ai-provider <provider>", "Service provider to use for AI (available: openai, ollama, anthropic)", "openai")
293
+ .option("--ai-endpoint <endpoint>", "Endpoint to use for AI service (for Ollama, etc)")
294
+ .option("--ai-api-key <key>", "API key for the configured AI provider")
295
+ .option("--model <model>", "AI model to use", "gpt-4o-mini")
296
+ .option("--openapi", "Generate OpenAPI spec from the code", false)
297
+ .option("--openapi-output <file>", "Output file for OpenAPI spec", "mapped-openapi.json")
298
+ .option("--openapi-chunk-tag", "Add chunk ID tag to OpenAPI spec for each request found", false)
299
+ .option("--no-graphql", "Disable GraphQL operation extraction during OpenAPI generation")
300
+ .option("--ngql", "Alias for --no-graphql")
301
+ .option("--max-recursion-depth <n>", "Max recursion depth for HTTP-client URL fan-out and cross-file resolution (default 3)", "3")
302
+ .option("--max-heap <mb>", "V8 heap size cap in MB (0 = all available RAM)")
303
+ .action((cmd) => __awaiter(this, void 0, void 0, function* () {
304
+ var _a, _b;
305
+ if (cmd.maxHeap !== undefined)
306
+ applyHeapLimit(parseMaxHeapMb(cmd.maxHeap));
307
+ globalsUtil.setAi(((_a = cmd.ai) === null || _a === void 0 ? void 0 : _a.split(",")) || []);
308
+ globalsUtil.setAiServiceProvider(cmd.aiProvider);
309
+ globalsUtil.setOpenapiChunkTag(cmd.openapiChunkTag);
310
+ globalsUtil.setAiApiKey(cmd.aiApiKey);
311
+ globalsUtil.setAiModel(cmd.model);
312
+ if (cmd.aiEndpoint)
313
+ globalsUtil.setAiEndpoint(cmd.aiEndpoint);
314
+ globalsUtil.setAiThreads(cmd.aiThreads);
315
+ globalsUtil.setOpenapi(cmd.openapi);
316
+ globalsUtil.setOpenapiOutputFile(cmd.openapiOutput);
317
+ // Commander's --no-graphql flips cmd.graphql to false; --ngql is an alias.
318
+ globalsUtil.setGraphqlEnabled(cmd.graphql !== false && !cmd.ngql);
319
+ // validate AI options
320
+ if (globalsUtil.getAi().length !== 0) {
321
+ for (const aiType of globalsUtil.getAi()) {
322
+ if (aiType !== "" && !validAiOptions.includes(aiType)) {
323
+ console.error(chalk.red(`[!] Invalid AI option: ${aiType}`));
324
+ process.exit(1);
325
+ }
326
+ }
327
+ }
328
+ const maxRecursionDepth = parseInt((_b = cmd.maxRecursionDepth) !== null && _b !== void 0 ? _b : "3", 10);
329
+ if (!Number.isFinite(maxRecursionDepth) || maxRecursionDepth < 0) {
330
+ console.error(chalk.red(`[!] Invalid --max-recursion-depth: ${cmd.maxRecursionDepth}`));
331
+ process.exit(1);
332
+ }
333
+ globalsUtil.setMaxRecursionDepth(maxRecursionDepth);
334
+ yield map(cmd.directory, cmd.output, cmd.format.split(","), cmd.tech, cmd.list, cmd.interactive, cmd.command || []);
335
+ }));
336
+ program
337
+ .command("refactor")
338
+ .description("Refactor the code")
339
+ .option("-m, --mapped-json <file>", "Mapped JSON file", "mapped.json")
340
+ .option("-o, --output <directory>", "Output directory", "output_refactored")
341
+ .option("-t, --tech <tech>", "Technology used in the JS files (run with -l/--list to see available options)")
342
+ .option("-l, --list", "List available technologies", false)
343
+ .option("--collisions <file>", "Local path to a CS-MAST collisions.json (or directory). Overrides the default remote HuggingFace signatures.")
344
+ .option("--sq, --signature-quality <number>", "Minimum signature quality threshold (0–100). A signature is used only when (count/sample_size)*100 >= threshold.", "100")
345
+ .option("--refresh-cache", "Force refresh the remote file list cache", false)
346
+ .option("--skip-cache-checks", "Skip cache age and 404-triggered refresh checks", false)
347
+ .option("--no-remote", "Disable remote HuggingFace signature fetch; run without library stripping unless --collisions is provided")
348
+ .option("--remote-collisions <path>", "HuggingFace dataset path to load collision signatures from (e.g. react/vite/large-0.1.8). Overrides the automatic tech-to-branch mapping. Exits with code 25 if the path does not exist.")
349
+ .option("--scat <categories>", "Override the CS-MAST scat categories used for library signature matching. Comma-separated list of: lit,id,op,decl,loop,cond,name,val,op_name (e.g. --scat lit,decl,cond). Overrides the default lit-decl-loop-cond config.")
350
+ .option("--detect-version", "Detect the React version used in the bundle and use it in the refactored output's package.json (react-webpack and react-vite only).", false)
351
+ .option("--detect-version-config <config>", 'Scat configuration for version detection. Use "dynamic" (default) to auto-select reliable configs, or pass comma-separated scat categories for a fixed config (e.g. lit,decl,loop,cond). Exits with code 26 if the static config has empty signatures for any known React version.')
352
+ .option("--detect-version-dynamic-threshold <n>", "Number of scat configs to select in dynamic version detection mode (default: 3). Must be a positive integer.", "3")
353
+ .option("--detect-version-dynamic-conf-purge", "Purge the cached dynamic scat config selection (stored in ~/.js-recon/refactor/config.json) and recompute it on this run.", false)
354
+ .action((cmd) => __awaiter(this, void 0, void 0, function* () {
355
+ var _a, _b;
356
+ const scat = cmd.scat
357
+ ? cmd.scat
358
+ .split(",")
359
+ .map((s) => s.trim())
360
+ .filter(Boolean)
361
+ : undefined;
362
+ const detectVersionDynamicThreshold = Number((_a = cmd.detectVersionDynamicThreshold) !== null && _a !== void 0 ? _a : 3);
363
+ if (!Number.isInteger(detectVersionDynamicThreshold) || detectVersionDynamicThreshold < 1) {
364
+ console.error(`[!] --detect-version-dynamic-threshold must be a positive integer (got "${cmd.detectVersionDynamicThreshold}")`);
365
+ process.exit(1);
366
+ }
367
+ yield refactor(cmd.mappedJson, cmd.output, cmd.tech, cmd.list, cmd.collisions, {
368
+ signatureQuality: Number((_b = cmd.signatureQuality) !== null && _b !== void 0 ? _b : 100),
369
+ refreshCache: !!cmd.refreshCache,
370
+ skipCacheChecks: !!cmd.skipCacheChecks,
371
+ noRemote: cmd.remote === false,
372
+ remoteCollisions: cmd.remoteCollisions,
373
+ scat,
374
+ detectVersion: !!cmd.detectVersion,
375
+ detectVersionConfig: cmd.detectVersionConfig,
376
+ detectVersionDynamicThreshold,
377
+ detectVersionDynamicConfPurge: !!cmd.detectVersionDynamicConfPurge,
378
+ });
379
+ }));
380
+ program
381
+ .command("analyze")
382
+ .description("Analyze the code")
383
+ .option("-r, --rules <file/dir>", "Rules file or directory")
384
+ .option("-m, --mapped-json <file>", "Mapped JSON file", "mapped.json")
385
+ .option("-t, --tech <tech>", "Technology used in the JS files (run with -l/--list to see available options)")
386
+ .option("--openapi <file>", "Path to OpenAPI spec file")
387
+ .option("-l, --list", "List available technologies", false)
388
+ .option("--validate", "Validate the rules", false)
389
+ .option("-o, --output <file>", "Output JSON file name", "analyze.json")
390
+ .option("--disable-rules-version-check", "Skip the GitHub rules version check and use cached rules as-is", false)
391
+ .option("--determine-compatible-version", "Report the js_recon_version/js_recon_max_version each rule actually requires, based on the features it uses", false)
392
+ .option("--apply-compatible-versions", "Same as --determine-compatible-version, but rewrites the rule files in place", false)
393
+ .action((cmd) => __awaiter(this, void 0, void 0, function* () {
394
+ yield analyze(cmd.rules, cmd.mappedJson, cmd.tech, cmd.list, cmd.openapi, cmd.validate, cmd.output, !!cmd.disableRulesVersionCheck, cmd.determineCompatibleVersion, cmd.applyCompatibleVersions);
395
+ }));
396
+ program
397
+ .command("exploit")
398
+ .description("Attempt exploitation of known framework CVEs to discover new attack surface")
399
+ .option("-u, --url <url>", "Target URL")
400
+ .option("--cve <id>", "CVE ID to exploit (e.g. CVE-2025-29927)")
401
+ .option("--list-cve", "List all supported CVEs grouped by framework and exit", false)
402
+ .option("--exec-cmd <cmd>", "Command to execute for RCE-class CVE proof (read-only recommended)", "id")
403
+ .option("-o, --output <file>", "Output JSON file for exploit findings", "exploit.json")
404
+ .option("--engine-output <file>", "Output JSON file in report-compatible EngineOutput format", "exploit-engine.json")
405
+ .option("--proxy-config <file>", "Proxy config file (generated via the `proxy` module)", ".proxy_config.json")
406
+ .option("--ignore-proxy-env", "Skip JS_RECON_* proxy environment variables during resolution", false)
407
+ .option("--timeout <timeout>", "Request timeout in ms", "30000")
408
+ .option("-k, --insecure", "Disable SSL certificate verification", false)
409
+ .action((cmd) => __awaiter(this, void 0, void 0, function* () {
410
+ if (cmd.listCve) {
411
+ printCveList();
412
+ process.exit(0);
413
+ }
414
+ if (!cmd.cve) {
415
+ console.error(chalk.red("[!] Missing required option: --cve <id> (or use --list-cve)"));
416
+ process.exit(1);
417
+ }
418
+ if (!cmd.url) {
419
+ console.error(chalk.red("[!] Missing required option: -u, --url <url>"));
420
+ process.exit(1);
421
+ }
422
+ configureProxy(cmd);
423
+ validateAndSetTimeout(cmd.timeout);
424
+ if (cmd.insecure) {
425
+ globalsUtil.setInsecure(true);
426
+ process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; // lgtm[js/disabling-certificate-validation]: opt-in via -k/--insecure, same as lazyload/run
427
+ console.warn(chalk.yellow("[!] Running in insecure mode. SSL certificate verification disabled"));
428
+ }
429
+ yield exploit(cmd.url, cmd.cve, {
430
+ execCmd: cmd.execCmd,
431
+ output: cmd.output,
432
+ engineOutput: cmd.engineOutput,
433
+ timeout: Number(cmd.timeout),
434
+ insecure: !!cmd.insecure,
435
+ });
436
+ }));
437
+ program
438
+ .command("report")
439
+ .description("Generate a report")
440
+ .option("-s, --sqlite-db <file>", "SQLite database file", "js-recon.db")
441
+ .option("-m, --mapped-json <file>", "Mapped JSON file")
442
+ .option("-a, --analyze-json <file>", "Analyze JSON file")
443
+ .option("-e, --endpoints-json <file>", "Endpoints JSON file")
444
+ .option("--map-openapi, --mapped-openapi-json <file>", "Mapped OpenAPI JSON file")
445
+ .option("--exploit-json <file>", "Exploit findings JSON file, in EngineOutput format (see `exploit --engine-output`)")
446
+ .option("-o, --output <file>", "Output file name (without the extension)", "report")
447
+ .option("--sj", "Run sj (swagger-jacker) against the mapped OpenAPI spec", false)
448
+ .option("--sj-bin <path>", "Path to the sj binary", "sj")
449
+ .option("--sj-args <args>", "Extra arguments passed through to `sj automate`", "")
450
+ .action((cmd) => __awaiter(this, void 0, void 0, function* () {
451
+ yield report(cmd.sqliteDb, cmd.mappedJson, cmd.analyzeJson, cmd.endpointsJson, cmd.mappedOpenapiJson, cmd.output, cmd.sj, cmd.sjBin, cmd.sjArgs, cmd.exploitJson);
452
+ }));
453
+ program
454
+ .command("run")
455
+ .description("Run all modules")
456
+ .option("-u, --url <url/list/file>", "Target URL, comma-separated URLs, or target file; may be repeated", collectTargetInput)
457
+ .option("-r, --rules <file/dir>", "Rules file or directory (passed to analyze module)")
458
+ .option("--disable-rules-version-check", "Skip the GitHub rules version check and use cached rules as-is (passed to analyze module)", false)
459
+ .option("-c, --command <command>", "Run an interactive-mode command on the mapped chunks non-interactively (forwarded to the map step). Can be passed multiple times, or chain several with `&&` inside a single value (e.g. -c 'list fetch && go to 1234').", (val, prev) => [...prev, ...val.split(/\s*&&\s*/).filter((c) => c.length > 0)], [])
460
+ .option("-o, --output <directory>", "Output directory", "output")
461
+ .option("--output-overwrite", "Replace an occupied js-recon-owned output instead of selecting output-2, output-3, etc. Can also be set via JS_RECON_OUTPUT_OVERWRITE=true.", false)
462
+ .option("--strict-scope", "Download JS files from only the input URL domain", false)
463
+ .option("-s, --scope <scope>", "Download JS files from specific domains (comma-separated)", "*")
464
+ .option("-t, --threads <threads>", "Number of threads to use", "1")
465
+ .option("--proxy-config <file>", "Proxy config file (generated via the `proxy` module)", ".proxy_config.json")
466
+ .option("--ignore-proxy-env", "Skip JS_RECON_* proxy environment variables during resolution", false)
467
+ .option("--proxy-waf-fallback", "Before each target, check whether the configured proxy is needed and can bypass a WAF/firewall (reuses the `proxy --feasibility` logic); skip the target if the proxy can't bypass it", false)
468
+ .option("--oxylabs-waf-fallback", "Retry strongly identified CDN/WAF blocks through configured Oxylabs; direct requests remain the default", false)
469
+ .option("--oxylabs-fallback-max-requests <count>", "Maximum paid Oxylabs fallback requests per origin", "10")
470
+ .option("--oxylabs-fallback-max-total <count>", "Maximum paid Oxylabs fallback requests per run", "100")
471
+ .option("--oxylabs-fallback-max-origins <count>", "Maximum distinct fallback origins per run", "25")
472
+ .option("--cache-file <file>", "File to store response cache", ".resp_cache.json")
473
+ .option("--disable-cache", "Disable response caching", false)
474
+ .option("--cache-only", "Only use the response cache; never make network requests", false)
475
+ .option("-y, --yes", "Auto-approve executing JS code from the target", false)
476
+ .option("--secrets", "Scan for secrets", false)
477
+ .option("--trufflehog", "Run TruffleHog secret scanner on the output directory", false)
478
+ .option("--trufflehog-bin <path>", "Path to the trufflehog binary (skips auto-download)", "trufflehog")
479
+ .option("--trufflehog-accept-terms", "Accept TruffleHog's AGPL-3.0 license terms non-interactively so it can be auto-downloaded (required in non-TTY/CI contexts on first use)", false)
480
+ .option("--sj", "Run sj (swagger-jacker) against the mapped OpenAPI spec", false)
481
+ .option("--sj-bin <path>", "Path to the sj binary", "sj")
482
+ .option("--sj-args <args>", "Extra arguments passed through to `sj automate`", "")
483
+ .option("--ai <options>", "Use AI to analyze the code (comma-separated; available: description)")
484
+ .option("--ai-threads <threads>", "Number of threads to use for AI", "5")
485
+ .option("--ai-provider <provider>", "Service provider to use for AI (available: openai, ollama, anthropic)", "openai")
486
+ .option("--ai-endpoint <endpoint>", "Endpoint to use for AI service (for Ollama, etc)")
487
+ .option("--ai-api-key <key>", "API key for the configured AI provider")
488
+ .option("--model <model>", "AI model to use", "gpt-4o-mini")
489
+ .option("--map-openapi-chunk-tag", "Add chunk ID tag to OpenAPI spec for each request found (map module)", false)
490
+ .option("--no-graphql", "Disable GraphQL operation extraction during OpenAPI generation")
491
+ .option("--ngql", "Alias for --no-graphql")
492
+ .option("--timeout <timeout>", "Request timeout in ms", "30000")
493
+ .option("-k, --insecure", "Disable SSL certificate verification", false)
494
+ .option("--no-sandbox", "Disable browser sandbox")
495
+ .option("--sourcemap-dir <directory>", "Directory to write source maps", "extracted")
496
+ .option("--research", "Enable research mode", false)
497
+ .option("--research-output <file>", "Output file for research mode", "research.json")
498
+ .option("--max-iterations <iterations>", "Maximum number of recursive crawl iterations", "10")
499
+ .option("--max-js-size <mb>", "Maximum JS file size in MB to parse (Vue only)", "2")
500
+ .option("--lazyload-timeout <minutes>", "Hard timeout for each lazyload step in minutes (0 = no timeout)", "30")
501
+ .option("--detection-timeout <seconds>", "Timeout for front-end framework detection in seconds (0 = no timeout)", "30")
502
+ .option("--max-heap <mb>", "V8 heap size cap in MB (0 = all available RAM)")
503
+ .option("--max-pages <pages>", "Maximum HTML pages to visit during Next.js crawl (0 = unlimited)", "200")
504
+ .option("--rsc-param-bruteforce-limit <n>", "Max harvested dynamic-route param-name candidates to try per URL in next_routerStateForge's RSC-body keyword fallback (0 = disable the fallback)", "20")
505
+ .option("--verbose", "Show detailed file write error messages", false)
506
+ .option("--max-redirects <n>", "Maximum redirects to follow when resolving the default crawl scope for generic tech", "20")
507
+ .option("--strings", "Enable strings-based recursive JS discovery for generic tech (scans downloaded files for string-literal JS paths)", false)
508
+ .option("--strings-max-iterations <n>", "Maximum recursive strings-discovery passes for generic tech (0 = unlimited, loops until no new files)", "5")
509
+ .option("--stagnation-timein <mins>", "Minutes to wait before generic-tech content stagnation detection begins monitoring (0 = disabled)", "30")
510
+ .option("--stagnation-percentage <percent>", "Percentage of discovered generic-tech JS files sharing identical content required to flag stagnation", "80")
511
+ .option("--stagnation-monitor <mins>", "Interval in minutes between generic-tech stagnation re-checks once armed", "1")
512
+ .option("--include-methods <methods>", "Comma-separated lazyload method names to run (whitelist). Use --list-methods to see valid names.")
513
+ .option("--exclude-methods <methods>", "Comma-separated lazyload method names to skip (blacklist). Use --list-methods to see valid names.")
514
+ .option("--list-methods [framework]", "Print available lazyload method names grouped by framework and exit. Optionally filter by framework (next_js, vue, nuxt_js, svelte, angular, react).")
515
+ .option("--cs-mast-tech-detect-threshold <n>", "Minimum CS-MAST-S signature matches required to detect bundler for the refactor step (0 = skip refactor)", "50")
516
+ .option("--disable-refactor", "Skip the automatic refactor step after report", false)
517
+ .option("--web-stats-dashboard", "Start a live web dashboard (with a REST API) to follow this run's progress instead of relying on console output", false)
518
+ .option("--web-stats-port <port>", "Preferred port for --web-stats-dashboard (increments if already in use)", "6767")
519
+ .action((cmd) => __awaiter(this, void 0, void 0, function* () {
520
+ var _a;
521
+ // handle --list-methods before any network work
522
+ if (cmd.listMethods !== undefined) {
523
+ const filter = typeof cmd.listMethods === "string" ? cmd.listMethods : null;
524
+ const frameworkKeys = Object.keys(FRAMEWORK_METHODS);
525
+ if (filter && !frameworkKeys.includes(filter)) {
526
+ console.error(chalk.red(`[!] Unknown framework: "${filter}". Valid frameworks: ${frameworkKeys.join(", ")}`));
527
+ process.exit(1);
528
+ }
529
+ const keys = filter ? [filter] : frameworkKeys;
530
+ for (const fw of keys) {
531
+ console.log(chalk.cyan(`\n[${fw}]`));
532
+ for (const method of FRAMEWORK_METHODS[fw]) {
533
+ console.log(chalk.green(` - ${method}`));
534
+ }
535
+ }
536
+ process.exit(0);
537
+ }
538
+ // parse and validate method filter lists
539
+ const includeMethods = cmd.includeMethods
540
+ ? cmd.includeMethods
541
+ .split(",")
542
+ .map((m) => m.trim())
543
+ .filter(Boolean)
544
+ : [];
545
+ const excludeMethods = cmd.excludeMethods
546
+ ? cmd.excludeMethods
547
+ .split(",")
548
+ .map((m) => m.trim())
549
+ .filter(Boolean)
550
+ : [];
551
+ const allMethods = [...includeMethods, ...excludeMethods];
552
+ const invalid = allMethods.filter((m) => !VALID_METHODS.includes(m));
553
+ if (invalid.length > 0) {
554
+ console.error(chalk.red(`[!] Invalid method name(s): ${invalid.join(", ")}`));
555
+ console.error(chalk.yellow(`[i] Valid methods: ${VALID_METHODS.join(", ")}`));
556
+ process.exit(22);
557
+ }
558
+ cmd._includeMethods = includeMethods;
559
+ cmd._excludeMethods = excludeMethods;
560
+ if (!cmd.url || (Array.isArray(cmd.url) && cmd.url.length === 0)) {
561
+ console.error(chalk.red("[!] Missing required option: -u, --url <url/list/file>"));
562
+ process.exit(1);
563
+ }
564
+ const runLazyloadTimeoutMin = Number(cmd.lazyloadTimeout);
565
+ const runStagnationTimeinMin = Number(cmd.stagnationTimein);
566
+ if (runLazyloadTimeoutMin > 0 && runStagnationTimeinMin > runLazyloadTimeoutMin) {
567
+ console.error(chalk.red(`[!] --stagnation-timein (${runStagnationTimeinMin}m) cannot exceed --lazyload-timeout (${runLazyloadTimeoutMin}m)`));
568
+ process.exit(30);
569
+ }
570
+ if (cmd.maxHeap !== undefined)
571
+ applyHeapLimit(parseMaxHeapMb(cmd.maxHeap));
572
+ validateAndSetTimeout(cmd.timeout);
573
+ globalsUtil.setAi(((_a = cmd.ai) === null || _a === void 0 ? void 0 : _a.split(",")) || []);
574
+ globalsUtil.setAiApiKey(cmd.aiApiKey);
575
+ globalsUtil.setAiModel(cmd.model);
576
+ globalsUtil.setAiServiceProvider(cmd.aiProvider);
577
+ globalsUtil.setAiThreads(cmd.aiThreads);
578
+ if (cmd.aiEndpoint)
579
+ globalsUtil.setAiEndpoint(cmd.aiEndpoint);
580
+ globalsUtil.setOpenapiChunkTag(cmd.mapOpenapiChunkTag);
581
+ globalsUtil.setGraphqlEnabled(cmd.graphql !== false && !cmd.ngql);
582
+ globalsUtil.setDisableCache(cmd.disableCache);
583
+ globalsUtil.setRespCacheFile(cmd.cacheFile);
584
+ globalsUtil.setCacheOnly(cmd.cacheOnly);
585
+ globalsUtil.setVerbose(cmd.verbose);
586
+ configureSandbox(cmd);
587
+ // validate AI options
588
+ if (globalsUtil.getAi().length !== 0) {
589
+ for (const aiType of globalsUtil.getAi()) {
590
+ if (aiType !== "" && !validAiOptions.includes(aiType)) {
591
+ console.error(chalk.red(`[!] Invalid AI option: ${aiType}`));
592
+ process.exit(2);
593
+ }
594
+ }
595
+ }
596
+ yield run(cmd);
597
+ }));
598
+ program
599
+ .command("load")
600
+ .description("Populate response cache from a Caido/Burp request history export")
601
+ .requiredOption("-c, --caido <file>", "Caido JSON export file")
602
+ .requiredOption("-u, --url <url>", "Target URL — only entries matching this host/port/scheme are loaded")
603
+ .option("--cache-file <file>", "Response cache file to write", ".resp_cache.json")
604
+ .action((cmd) => __awaiter(this, void 0, void 0, function* () {
605
+ globalsUtil.setRespCacheFile(cmd.cacheFile);
606
+ yield load(cmd.caido, cmd.url);
607
+ }));
608
+ program
609
+ .command("fingerprint")
610
+ .description("Detect front-end frameworks across one or more URLs")
611
+ .option("-u, --url <url/list/file>", "Target URL, comma-separated URLs, or target file; may be repeated", collectTargetInput)
612
+ .option("-o, --output <file>", "Output file to write results")
613
+ .option("-f, --format <formats>", "Output format(s): text, csv, json, jsonl (comma-separated)", "text")
614
+ .option("-t, --threads <threads>", "Number of concurrent detection workers", "5")
615
+ .option("--timeout <timeout>", "Request timeout in ms", "30000")
616
+ .option("-k, --insecure", "Disable SSL certificate verification", false)
617
+ .option("--no-sandbox", "Disable browser sandbox")
618
+ .action((cmd) => __awaiter(this, void 0, void 0, function* () {
619
+ if (!cmd.url || (Array.isArray(cmd.url) && cmd.url.length === 0)) {
620
+ console.error(chalk.red("[!] Missing required option: -u, --url <url/list/file>"));
621
+ process.exit(1);
622
+ }
623
+ validateAndSetTimeout(cmd.timeout);
624
+ globalsUtil.setDisableCache(true);
625
+ globalsUtil.setYes(true);
626
+ configureSandbox(cmd);
627
+ yield fingerprint(cmd.url, cmd.output, cmd.format, Number(cmd.threads));
628
+ }));
629
+ program
630
+ .command("mcp")
631
+ .description("AI-powered CLI / one-shot chat / Model Context Protocol server for js-recon")
632
+ .option("--cli", "Start interactive CLI mode", false)
633
+ .option("--server", "Start a Model Context Protocol server over stdio", false)
634
+ .option("-c, --chat <prompt>", "Send a one-shot prompt to the AI agent non-interactively (can be passed multiple times)", (val, prev) => [...prev, val], [])
635
+ .option("--config <file>", "Path to MCP config file", undefined)
636
+ .option("--api-key <key>", "API key for the LLM provider")
637
+ .option("--model <model>", "AI model to use (e.g. gpt-4o-mini, claude-sonnet-4-20250514)")
638
+ .option("--provider <provider>", "LLM provider to use (openai, anthropic)")
639
+ .option("--no-refresh-claude-creds", "Do not auto-refresh Claude Code OAuth tokens; fail if expired")
640
+ .option("--claude-client-id <id>", "OAuth client ID used when refreshing Claude Code credentials")
641
+ .action((cmd) => __awaiter(this, void 0, void 0, function* () {
642
+ yield mcp({
643
+ cli: cmd.cli,
644
+ server: cmd.server,
645
+ chat: cmd.chat,
646
+ configFile: cmd.config,
647
+ apiKey: cmd.apiKey,
648
+ model: cmd.model,
649
+ provider: cmd.provider,
650
+ refreshClaudeCreds: cmd.refreshClaudeCreds,
651
+ claudeClientId: cmd.claudeClientId,
652
+ });
653
+ }));
654
+ program
655
+ .command("cs-mast")
656
+ .description("Compute CS-MAST hashes for downloaded JS files and find structural collisions")
657
+ .option("-o, --output <directory>", "Output directory to scan for JS files", "output")
658
+ .option("--ct, --collision-table", "Find and display hash collisions", false)
659
+ .option("--min-collisions <n>", "Minimum times a hash must appear to be reported", "2")
660
+ .option("--co, --collision-output <file>", "Write collision results to a file")
661
+ .option("--cf, --collision-format <format>", "Output format for collision file: json or csv", "csv")
662
+ .option("--scat <categories>", "Comma-separated scat categories (e.g. lit,decl,loop,cond)", "lit,decl,loop,cond")
663
+ .option("--sinc <nodes>", "Comma-separated exact node types to include via sinc (e.g. IfStatement)", "")
664
+ .option("--all-scat-permutations", "Run all 511 non-empty scat permutations and save per-permutation collision files", false)
665
+ .option("--perm-output <dir>", "Output directory for per-permutation collision files (required with --all-scat-permutations)")
666
+ .option("--perm-concurrency <n>", "Number of parallel permutation workers (default: half of CPU count)", "0")
667
+ .action((cmd) => __awaiter(this, void 0, void 0, function* () {
668
+ yield csMast(cmd.output, cmd.collisionTable, parseInt(cmd.minCollisions, 10), cmd.collisionOutput, cmd.collisionFormat, cmd.scat, cmd.sinc || "", cmd.allScatPermutations, cmd.permOutput, parseInt(cmd.permConcurrency, 10));
669
+ }));
670
+ program
671
+ .command("sourcemaps")
672
+ .description("Extract source files from .map sourcemap file(s)")
673
+ .requiredOption("-i, --input <path>", "Single .map file or directory containing .map files")
674
+ .option("-o, --output <directory>", "Output directory for extracted source files", "extracted")
675
+ .action((cmd) => __awaiter(this, void 0, void 0, function* () {
676
+ yield sourcemaps(cmd.input, cmd.output);
677
+ }));
678
+ program
679
+ .command("completion")
680
+ .description("Install shell completion for bash, zsh, or fish")
681
+ .addArgument(new Argument("<shell>", "Shell type: bash, zsh, or fish").choices(["bash", "zsh", "fish"]))
682
+ .option("--rc-file", "Print the small rc-file loader snippet instead of installing (used internally by the generated rc entry)")
683
+ .addHelpText("after", `
684
+ Examples:
685
+ js-recon completion bash # installs the script and wires ~/.bashrc automatically
686
+ js-recon completion zsh # installs the script and wires ~/.zshrc automatically
687
+ js-recon completion fish # installs to ~/.config/fish/completions/js-recon.fish (auto-loaded)`)
688
+ .action((shell, cmd) => __awaiter(this, void 0, void 0, function* () {
689
+ completion(shell, !!cmd.rcFile);
690
+ }));
691
+ prepareProgramConfiguration(program);
692
+ program.hook("preAction", (_rootCommand, actionCommand) => {
693
+ var _a, _b, _c;
694
+ const commandOptions = actionCommand.opts();
695
+ if (commandOptions.oxylabsWafFallback && commandOptions.proxyWafFallback) {
696
+ throw new OxylabsFallbackConfigurationError("--oxylabs-waf-fallback cannot be combined with --proxy-waf-fallback");
697
+ }
698
+ configureOxylabsFallback(resolveOxylabsFallback({
699
+ enabled: commandOptions.oxylabsWafFallback === true,
700
+ maxRequestsPerOrigin: (_a = commandOptions.oxylabsFallbackMaxRequests) !== null && _a !== void 0 ? _a : "10",
701
+ maxTotalRequests: (_b = commandOptions.oxylabsFallbackMaxTotal) !== null && _b !== void 0 ? _b : "100",
702
+ maxOrigins: (_c = commandOptions.oxylabsFallbackMaxOrigins) !== null && _c !== void 0 ? _c : "25",
703
+ loadedConfig: getLoadedApplicationConfig(),
704
+ env: process.env,
705
+ ignoreEnvironment: commandOptions.ignoreProxyEnv === true,
706
+ }));
707
+ });
708
+ return program;
709
+ }
710
+ //# sourceMappingURL=cliProgram.js.map