@js-recon/js-recon 1.4.3 → 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 (461) hide show
  1. package/.claude-sync/sync.sh +1 -1
  2. package/.github/workflows/build-and-prettify.yaml +55 -25
  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 +15 -7
  10. package/.nvmrc +1 -0
  11. package/.plumber.yaml +151 -0
  12. package/CHANGELOG.md +54 -0
  13. package/CONTRIBUTING.md +32 -0
  14. package/Dockerfile +1 -0
  15. package/README.md +55 -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 +42 -24
  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 +245 -339
  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 +494 -0
  46. package/build/config/applicationConfig.js.map +1 -0
  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 +11 -21
  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 +16 -555
  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 +51 -40
  106. package/build/lazyLoad/downloadFilesUtil.js.map +1 -1
  107. package/build/lazyLoad/downloadQueue.js +154 -50
  108. package/build/lazyLoad/downloadQueue.js.map +1 -1
  109. package/build/lazyLoad/downloadResponse.js +113 -0
  110. package/build/lazyLoad/downloadResponse.js.map +1 -0
  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 +35 -0
  130. package/build/lazyLoad/globals.js.map +1 -1
  131. package/build/lazyLoad/index.js +311 -175
  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 +39 -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 +21 -20
  142. package/build/lazyLoad/next_js/next_GetLazyResourcesWebpackJs.js.map +1 -1
  143. package/build/lazyLoad/next_js/next_SubsequentRequests.js +100 -99
  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/outputPath.js +92 -0
  170. package/build/lazyLoad/outputPath.js.map +1 -0
  171. package/build/lazyLoad/react/react_followImports.js +15 -5
  172. package/build/lazyLoad/react/react_followImports.js.map +1 -1
  173. package/build/lazyLoad/react/react_getScriptTags.js +11 -6
  174. package/build/lazyLoad/react/react_getScriptTags.js.map +1 -1
  175. package/build/lazyLoad/react/react_sourcemapUrls.js +3 -2
  176. package/build/lazyLoad/react/react_sourcemapUrls.js.map +1 -1
  177. package/build/lazyLoad/react/react_webpackChunkPaths.js +12 -203
  178. package/build/lazyLoad/react/react_webpackChunkPaths.js.map +1 -1
  179. package/build/lazyLoad/researchUtils.js +15 -0
  180. package/build/lazyLoad/researchUtils.js.map +1 -0
  181. package/build/lazyLoad/shared/webpackChunkParsers.js +218 -0
  182. package/build/lazyLoad/shared/webpackChunkParsers.js.map +1 -0
  183. package/build/lazyLoad/stagnation/stagnationMonitor.js +63 -0
  184. package/build/lazyLoad/stagnation/stagnationMonitor.js.map +1 -0
  185. package/build/lazyLoad/svelte/svelte_discoverPagesFromJs.js +1 -0
  186. package/build/lazyLoad/svelte/svelte_discoverPagesFromJs.js.map +1 -1
  187. package/build/lazyLoad/svelte/svelte_getFromPageSource.js +5 -5
  188. package/build/lazyLoad/svelte/svelte_getFromPageSource.js.map +1 -1
  189. package/build/lazyLoad/svelte/svelte_getVersionJson.js +2 -2
  190. package/build/lazyLoad/svelte/svelte_getVersionJson.js.map +1 -1
  191. package/build/lazyLoad/svelte/svelte_recursivePageCrawl.js +6 -6
  192. package/build/lazyLoad/svelte/svelte_recursivePageCrawl.js.map +1 -1
  193. package/build/lazyLoad/svelte/svelte_stringAnalysisJSFiles.js +2 -2
  194. package/build/lazyLoad/svelte/svelte_stringAnalysisJSFiles.js.map +1 -1
  195. package/build/lazyLoad/techDetect/checkAngularJS.js +1 -1
  196. package/build/lazyLoad/techDetect/checkAngularJS.js.map +1 -1
  197. package/build/lazyLoad/techDetect/checkNuxtJS.js +3 -3
  198. package/build/lazyLoad/techDetect/checkNuxtJS.js.map +1 -1
  199. package/build/lazyLoad/techDetect/checkSvelte.js +0 -1
  200. package/build/lazyLoad/techDetect/checkSvelte.js.map +1 -1
  201. package/build/lazyLoad/techDetect/checkVueJS.js +6 -6
  202. package/build/lazyLoad/techDetect/checkVueJS.js.map +1 -1
  203. package/build/lazyLoad/techDetect/index.js +106 -60
  204. package/build/lazyLoad/techDetect/index.js.map +1 -1
  205. package/build/lazyLoad/vue/vue_RuntimeJs.js +20 -15
  206. package/build/lazyLoad/vue/vue_RuntimeJs.js.map +1 -1
  207. package/build/lazyLoad/vue/vue_SingleJsFileOnHome.js +10 -5
  208. package/build/lazyLoad/vue/vue_SingleJsFileOnHome.js.map +1 -1
  209. package/build/lazyLoad/vue/vue_discoverJsFiles.js +20 -17
  210. package/build/lazyLoad/vue/vue_discoverJsFiles.js.map +1 -1
  211. package/build/lazyLoad/vue/vue_getClientSidePaths.js +70 -46
  212. package/build/lazyLoad/vue/vue_getClientSidePaths.js.map +1 -1
  213. package/build/lazyLoad/vue/vue_jsImports.js +3 -2
  214. package/build/lazyLoad/vue/vue_jsImports.js.map +1 -1
  215. package/build/lazyLoad/vue/vue_pageSrc.js +3 -2
  216. package/build/lazyLoad/vue/vue_pageSrc.js.map +1 -1
  217. package/build/lazyLoad/vue/vue_reconstructSourceMaps.js +6 -5
  218. package/build/lazyLoad/vue/vue_reconstructSourceMaps.js.map +1 -1
  219. package/build/lazyLoad/vue/vue_recursiveClientSidePathDownload.js +10 -21
  220. package/build/lazyLoad/vue/vue_recursiveClientSidePathDownload.js.map +1 -1
  221. package/build/lazyLoad/vue/vue_severalJsFilesHome.js +5 -4
  222. package/build/lazyLoad/vue/vue_severalJsFilesHome.js.map +1 -1
  223. package/build/lazyLoad/vue/vue_stringJsFiles.js +28 -25
  224. package/build/lazyLoad/vue/vue_stringJsFiles.js.map +1 -1
  225. package/build/lazyLoad/vue/vue_viteMapDeps.js +8 -2
  226. package/build/lazyLoad/vue/vue_viteMapDeps.js.map +1 -1
  227. package/build/load/index.js +8 -7
  228. package/build/load/index.js.map +1 -1
  229. package/build/map/angular_js/getAngularConnections.js +6 -6
  230. package/build/map/angular_js/getAngularConnections.js.map +1 -1
  231. package/build/map/graphql/resolveGraphql.js +6 -6
  232. package/build/map/graphql/resolveGraphql.js.map +1 -1
  233. package/build/map/index.js +17 -17
  234. package/build/map/index.js.map +1 -1
  235. package/build/map/interactive-mode/commandHandler.js +278 -0
  236. package/build/map/interactive-mode/commandHandler.js.map +1 -0
  237. package/build/map/interactive-mode/commandHelpers.js +189 -0
  238. package/build/map/interactive-mode/commandHelpers.js.map +1 -0
  239. package/build/map/interactive-mode/esqueryGen.js.map +1 -0
  240. package/build/map/interactive-mode/helpMenu.js +11 -0
  241. package/build/map/interactive-mode/helpMenu.js.map +1 -0
  242. package/build/map/interactive-mode/inputPatch.js.map +1 -0
  243. package/build/map/interactive-mode/interactive.js +71 -0
  244. package/build/map/interactive-mode/interactive.js.map +1 -0
  245. package/build/map/interactive-mode/keybindings.js.map +1 -0
  246. package/build/map/interactive-mode/printer.js.map +1 -0
  247. package/build/map/interactive-mode/ui.js.map +1 -0
  248. package/build/map/next_js/getAxiosInstances.js +5 -5
  249. package/build/map/next_js/getAxiosInstances.js.map +1 -1
  250. package/build/map/next_js/getExports.js +4 -4
  251. package/build/map/next_js/getExports.js.map +1 -1
  252. package/build/map/next_js/getFetchInstances.js +10 -10
  253. package/build/map/next_js/getFetchInstances.js.map +1 -1
  254. package/build/map/next_js/getTurbopackConnections.js +8 -8
  255. package/build/map/next_js/getTurbopackConnections.js.map +1 -1
  256. package/build/map/next_js/getWebpackConnections.js +27 -16
  257. package/build/map/next_js/getWebpackConnections.js.map +1 -1
  258. package/build/map/next_js/interactive.js +3 -65
  259. package/build/map/next_js/interactive.js.map +1 -1
  260. package/build/map/next_js/interactive_helpers/commandHandler.js +38 -290
  261. package/build/map/next_js/interactive_helpers/commandHandler.js.map +1 -1
  262. package/build/map/next_js/interactive_helpers/commandHelpers.js +0 -184
  263. package/build/map/next_js/interactive_helpers/commandHelpers.js.map +1 -1
  264. package/build/map/next_js/interactive_helpers/helpMenu.js +2 -10
  265. package/build/map/next_js/interactive_helpers/helpMenu.js.map +1 -1
  266. package/build/map/next_js/resolveAxios.js +6 -6
  267. package/build/map/next_js/resolveAxios.js.map +1 -1
  268. package/build/map/next_js/resolveAxiosHelpers/findAxiosClients.js +4 -4
  269. package/build/map/next_js/resolveAxiosHelpers/findAxiosClients.js.map +1 -1
  270. package/build/map/next_js/resolveAxiosHelpers/findAxiosInstance.js +2 -2
  271. package/build/map/next_js/resolveAxiosHelpers/findAxiosInstance.js.map +1 -1
  272. package/build/map/next_js/resolveAxiosHelpers/findCrossChunkParams.js +5 -5
  273. package/build/map/next_js/resolveAxiosHelpers/findCrossChunkParams.js.map +1 -1
  274. package/build/map/next_js/resolveAxiosHelpers/handleAxiosCreate.js +10 -10
  275. package/build/map/next_js/resolveAxiosHelpers/handleAxiosCreate.js.map +1 -1
  276. package/build/map/next_js/resolveAxiosHelpers/handleZDotCreate.js +13 -9
  277. package/build/map/next_js/resolveAxiosHelpers/handleZDotCreate.js.map +1 -1
  278. package/build/map/next_js/resolveAxiosHelpers/processAxiosCall.js +12 -8
  279. package/build/map/next_js/resolveAxiosHelpers/processAxiosCall.js.map +1 -1
  280. package/build/map/next_js/resolveAxiosHelpers/processDirectAxiosCall.js +12 -8
  281. package/build/map/next_js/resolveAxiosHelpers/processDirectAxiosCall.js.map +1 -1
  282. package/build/map/next_js/resolveAxiosHelpers/processExportedEndpoints.js +11 -11
  283. package/build/map/next_js/resolveAxiosHelpers/processExportedEndpoints.js.map +1 -1
  284. package/build/map/next_js/resolveAxiosHelpers/traceAxiosInstanceExports.js +16 -16
  285. package/build/map/next_js/resolveAxiosHelpers/traceAxiosInstanceExports.js.map +1 -1
  286. package/build/map/next_js/resolveFetch.js +23 -23
  287. package/build/map/next_js/resolveFetch.js.map +1 -1
  288. package/build/map/next_js/resolveNewRequest.js +10 -10
  289. package/build/map/next_js/resolveNewRequest.js.map +1 -1
  290. package/build/map/next_js/resolveServerActions.js +4 -4
  291. package/build/map/next_js/resolveServerActions.js.map +1 -1
  292. package/build/map/next_js/utils.js +8 -2
  293. package/build/map/next_js/utils.js.map +1 -1
  294. package/build/map/react_js/getReactConnections.js +21 -14
  295. package/build/map/react_js/getReactConnections.js.map +1 -1
  296. package/build/map/svelte_js/interactive.js +3 -54
  297. package/build/map/svelte_js/interactive.js.map +1 -1
  298. package/build/map/vue_js/getViteConnections.js +23 -16
  299. package/build/map/vue_js/getViteConnections.js.map +1 -1
  300. package/build/map/vue_js/interactive.js +3 -63
  301. package/build/map/vue_js/interactive.js.map +1 -1
  302. package/build/map/vue_js/interactive_helpers/commandHandler.js +34 -283
  303. package/build/map/vue_js/interactive_helpers/commandHandler.js.map +1 -1
  304. package/build/map/vue_js/interactive_helpers/helpMenu.js +2 -10
  305. package/build/map/vue_js/interactive_helpers/helpMenu.js.map +1 -1
  306. package/build/map/vue_js/taint_utils.js +1 -1
  307. package/build/map/vue_js/taint_utils.js.map +1 -1
  308. package/build/map/vue_js/vue_resolveFetch.js +12 -12
  309. package/build/map/vue_js/vue_resolveFetch.js.map +1 -1
  310. package/build/map/vue_js/vue_resolveHttpClient.js +18 -18
  311. package/build/map/vue_js/vue_resolveHttpClient.js.map +1 -1
  312. package/build/map/vue_js/vue_resolveXhr.js +11 -11
  313. package/build/map/vue_js/vue_resolveXhr.js.map +1 -1
  314. package/build/mcp/chatOneShot.js +7 -7
  315. package/build/mcp/chatOneShot.js.map +1 -1
  316. package/build/mcp/claudeCodeCreds.js +5 -5
  317. package/build/mcp/claudeCodeCreds.js.map +1 -1
  318. package/build/mcp/cli.js +36 -35
  319. package/build/mcp/cli.js.map +1 -1
  320. package/build/mcp/config.js +4 -4
  321. package/build/mcp/config.js.map +1 -1
  322. package/build/mcp/index.js +7 -7
  323. package/build/mcp/index.js.map +1 -1
  324. package/build/mcp/mcpServer.js +3 -2
  325. package/build/mcp/mcpServer.js.map +1 -1
  326. package/build/mcp/skills.js +1 -0
  327. package/build/mcp/skills.js.map +1 -1
  328. package/build/mcp/tools.js +5 -4
  329. package/build/mcp/tools.js.map +1 -1
  330. package/build/proxy/checkFeasibility.js +8 -4
  331. package/build/proxy/checkFeasibility.js.map +1 -1
  332. package/build/proxy/checkFireWallBlocking.js +23 -13
  333. package/build/proxy/checkFireWallBlocking.js.map +1 -1
  334. package/build/proxy/detectBlockedResponse.js +205 -0
  335. package/build/proxy/detectBlockedResponse.js.map +1 -0
  336. package/build/proxy/genReq.js +434 -127
  337. package/build/proxy/genReq.js.map +1 -1
  338. package/build/proxy/index.js +3 -3
  339. package/build/proxy/index.js.map +1 -1
  340. package/build/proxy/oxylabsFallback.js +110 -0
  341. package/build/proxy/oxylabsFallback.js.map +1 -0
  342. package/build/proxy/proxyFeasibilityRequest.js +11 -9
  343. package/build/proxy/proxyFeasibilityRequest.js.map +1 -1
  344. package/build/refactor/index.js +83 -79
  345. package/build/refactor/index.js.map +1 -1
  346. package/build/refactor/next/index.js +69 -26
  347. package/build/refactor/next/index.js.map +1 -1
  348. package/build/refactor/next/transform.js +11 -4
  349. package/build/refactor/next/transform.js.map +1 -1
  350. package/build/refactor/next/validator.js +7 -7
  351. package/build/refactor/next/validator.js.map +1 -1
  352. package/build/refactor/react/index.js +13 -13
  353. package/build/refactor/react/index.js.map +1 -1
  354. package/build/refactor/react/validator.js +7 -7
  355. package/build/refactor/react/validator.js.map +1 -1
  356. package/build/refactor/react-vite/index.js +3 -3
  357. package/build/refactor/react-vite/index.js.map +1 -1
  358. package/build/refactor/remote/hf-client.js +1 -0
  359. package/build/refactor/remote/hf-client.js.map +1 -1
  360. package/build/refactor/remote/version-detect.js +12 -12
  361. package/build/refactor/remote/version-detect.js.map +1 -1
  362. package/build/refactor/vue/index.js +6 -6
  363. package/build/refactor/vue/index.js.map +1 -1
  364. package/build/refactor/vue/vite.js +6 -6
  365. package/build/refactor/vue/vite.js.map +1 -1
  366. package/build/report/index.js +30 -8
  367. package/build/report/index.js.map +1 -1
  368. package/build/report/swaggerJacker.js +63 -0
  369. package/build/report/swaggerJacker.js.map +1 -0
  370. package/build/report/utility/genHtml.js +7 -7
  371. package/build/report/utility/genHtml.js.map +1 -1
  372. package/build/report/utility/populateDb/populateAnalysisFindings.js +2 -2
  373. package/build/report/utility/populateDb/populateAnalysisFindings.js.map +1 -1
  374. package/build/report/utility/populateDb/populateEndpoints.js +3 -3
  375. package/build/report/utility/populateDb/populateEndpoints.js.map +1 -1
  376. package/build/report/utility/populateDb/populateMappedJson.js +2 -2
  377. package/build/report/utility/populateDb/populateMappedJson.js.map +1 -1
  378. package/build/report/utility/populateDb/populateMappedOpenapi.js +3 -3
  379. package/build/report/utility/populateDb/populateMappedOpenapi.js.map +1 -1
  380. package/build/run/bundler-detect.js +45 -9
  381. package/build/run/bundler-detect.js.map +1 -1
  382. package/build/run/cancellableStep.js +27 -0
  383. package/build/run/cancellableStep.js.map +1 -0
  384. package/build/run/dashboard/dashboardHtml.js +150 -0
  385. package/build/run/dashboard/dashboardHtml.js.map +1 -0
  386. package/build/run/dashboard/fsBrowser.js +43 -0
  387. package/build/run/dashboard/fsBrowser.js.map +1 -0
  388. package/build/run/dashboard/server.js +123 -0
  389. package/build/run/dashboard/server.js.map +1 -0
  390. package/build/run/dashboard/state.js +97 -0
  391. package/build/run/dashboard/state.js.map +1 -0
  392. package/build/run/index.js +239 -204
  393. package/build/run/index.js.map +1 -1
  394. package/build/run/interruptHandler.js +18 -0
  395. package/build/run/interruptHandler.js.map +1 -1
  396. package/build/run/outputDirectory.js +377 -0
  397. package/build/run/outputDirectory.js.map +1 -0
  398. package/build/sourcemaps/index.js +116 -29
  399. package/build/sourcemaps/index.js.map +1 -1
  400. package/build/strings/index.js +38 -28
  401. package/build/strings/index.js.map +1 -1
  402. package/build/strings/openapi.js +4 -4
  403. package/build/strings/openapi.js.map +1 -1
  404. package/build/strings/permutate.js +4 -4
  405. package/build/strings/permutate.js.map +1 -1
  406. package/build/strings/secrets.js +1 -0
  407. package/build/strings/secrets.js.map +1 -1
  408. package/build/strings/trufflehog.js +66 -19
  409. package/build/strings/trufflehog.js.map +1 -1
  410. package/build/strings/trufflehogConfig.js +36 -0
  411. package/build/strings/trufflehogConfig.js.map +1 -0
  412. package/build/strings/trufflehogDownload.js +115 -0
  413. package/build/strings/trufflehogDownload.js.map +1 -0
  414. package/build/utility/ai.js +33 -4
  415. package/build/utility/ai.js.map +1 -1
  416. package/build/utility/banner.js +4 -3
  417. package/build/utility/banner.js.map +1 -1
  418. package/build/utility/configureSandbox.js +2 -2
  419. package/build/utility/configureSandbox.js.map +1 -1
  420. package/build/utility/downloadProgress.js +99 -0
  421. package/build/utility/downloadProgress.js.map +1 -0
  422. package/build/utility/globals.js +19 -11
  423. package/build/utility/globals.js.map +1 -1
  424. package/build/utility/heap.js +2 -1
  425. package/build/utility/heap.js.map +1 -1
  426. package/build/utility/makeReq.js +490 -257
  427. package/build/utility/makeReq.js.map +1 -1
  428. package/build/utility/openapiGenerator.js +2 -2
  429. package/build/utility/openapiGenerator.js.map +1 -1
  430. package/build/utility/printMsg.js +53 -0
  431. package/build/utility/printMsg.js.map +1 -0
  432. package/build/utility/progressLog.js +68 -7
  433. package/build/utility/progressLog.js.map +1 -1
  434. package/build/utility/resolvePath.js +2 -1
  435. package/build/utility/resolvePath.js.map +1 -1
  436. package/build/utility/ruleVersionMap.js +73 -0
  437. package/build/utility/ruleVersionMap.js.map +1 -0
  438. package/build/utility/targetInputs.js +177 -0
  439. package/build/utility/targetInputs.js.map +1 -0
  440. package/build/utility/urlUtils.js +37 -1
  441. package/build/utility/urlUtils.js.map +1 -1
  442. package/config.dist.yaml +251 -0
  443. package/contributing/testing.md +106 -0
  444. package/eslint.config.js +24 -0
  445. package/package.json +22 -5
  446. package/scripts/exploit-smoke-test.js +82 -0
  447. package/scripts/framework-detect-smoke-test.js +64 -0
  448. package/scripts/postinstall-completion.mjs +40 -0
  449. package/scripts/smoke-test.js +12 -0
  450. package/build/lazyLoad/downloadLoadedJsUtil.js +0 -98
  451. package/build/lazyLoad/downloadLoadedJsUtil.js.map +0 -1
  452. package/build/map/next_js/interactive_helpers/esqueryGen.js.map +0 -1
  453. package/build/map/next_js/interactive_helpers/inputPatch.js.map +0 -1
  454. package/build/map/next_js/interactive_helpers/keybindings.js.map +0 -1
  455. package/build/map/next_js/interactive_helpers/printer.js.map +0 -1
  456. package/build/map/next_js/interactive_helpers/ui.js.map +0 -1
  457. /package/build/map/{next_js/interactive_helpers → interactive-mode}/esqueryGen.js +0 -0
  458. /package/build/map/{next_js/interactive_helpers → interactive-mode}/inputPatch.js +0 -0
  459. /package/build/map/{next_js/interactive_helpers → interactive-mode}/keybindings.js +0 -0
  460. /package/build/map/{next_js/interactive_helpers → interactive-mode}/printer.js +0 -0
  461. /package/build/map/{next_js/interactive_helpers → interactive-mode}/ui.js +0 -0
@@ -7,15 +7,51 @@
7
7
  * @param {string} url - The URL to parse.
8
8
  * @returns {Object} An object with the host and directory of the URL.
9
9
  */
10
+ export const toOutputHost = (host) => {
11
+ const normalized = host.normalize("NFKC").replace(/[^a-zA-Z0-9._\-[\]]/g, "_");
12
+ const nonTraversing = normalized.length === 0 || /^\.+$/.test(normalized) ? normalized.replace(/\./g, "_") || "_" : normalized;
13
+ const changed = nonTraversing !== host;
14
+ const reservedLiteral = nonTraversing.startsWith(ENCODED_HOST_PREFIX);
15
+ const needsBounding = nonTraversing.length > MAX_OUTPUT_HOST_LENGTH;
16
+ if (!changed && !reservedLiteral && !needsBounding)
17
+ return nonTraversing;
18
+ const category = changed ? "encoded" : needsBounding ? "bounded" : "literal";
19
+ const digest = createHash("sha256").update(host).digest("hex").slice(0, 12);
20
+ const tagged = `${ENCODED_HOST_PREFIX}${category}_${nonTraversing}`;
21
+ return `${tagged.slice(0, MAX_OUTPUT_HOST_LENGTH - digest.length - 1)}-${digest}`;
22
+ };
23
+ const canonicalNetworkHost = (host) => {
24
+ const candidate = host.trim();
25
+ if (!candidate)
26
+ return null;
27
+ try {
28
+ const parsed = new URL(candidate.includes("://") ? candidate : `http://${candidate}`);
29
+ return parsed.host.toLowerCase();
30
+ }
31
+ catch (_a) {
32
+ return null;
33
+ }
34
+ };
35
+ /** Compares canonical network hosts without using lossy filesystem naming. */
36
+ export const hostMatchesScope = (host, scope) => {
37
+ const canonicalHost = canonicalNetworkHost(host);
38
+ if (!canonicalHost)
39
+ return false;
40
+ return scope.some((candidate) => candidate.trim() === "*" || canonicalNetworkHost(candidate) === canonicalHost);
41
+ };
10
42
  const getURLDirectory = (url) => {
11
43
  const u = new URL(url);
12
44
  const pathname = u.pathname;
13
45
  // Remove filename (last part after final /) if it ends with .js or any file extension
14
46
  const dir = pathname.replace(/\/[^\/?#]+\.[^\/?#]+$/, "");
15
47
  return {
16
- host: u.host.replace(":", "_"), // e.g., "vercel.com" or "localhost_3000"
48
+ host: toOutputHost(u.host), // e.g., "vercel.com" or "localhost_3000"
49
+ rawHost: u.host,
17
50
  directory: dir, // e.g., "/static/js"
18
51
  };
19
52
  };
20
53
  export { getURLDirectory };
54
+ import { createHash } from "node:crypto";
55
+ const ENCODED_HOST_PREFIX = "__jsr_host_";
56
+ const MAX_OUTPUT_HOST_LENGTH = 180;
21
57
  //# sourceMappingURL=urlUtils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"urlUtils.js","sourceRoot":"","sources":["../../src/utility/urlUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,eAAe,GAAG,CAAC,GAAW,EAAE,EAAE;IACpC,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACvB,MAAM,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;IAE5B,sFAAsF;IACtF,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,uBAAuB,EAAE,EAAE,CAAC,CAAC;IAE1D,OAAO;QACH,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,yCAAyC;QACzE,SAAS,EAAE,GAAG,EAAE,qBAAqB;KACxC,CAAC;AACN,CAAC,CAAC;AAEF,OAAO,EAAE,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"urlUtils.js","sourceRoot":"","sources":["../../src/utility/urlUtils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,251 @@
1
+ # js-recon application configuration
2
+ #
3
+ # The CLI creates ~/.config/js-recon/config.yaml on first use. Copy this file
4
+ # elsewhere when you want to use: js-recon --config /path/to/config.yaml <command>
5
+ #
6
+ # Precedence (highest first): environment, command-line flag, this YAML file,
7
+ # built-in default. Every command option also has a canonical environment name:
8
+ # JS_RECON_<COMMAND>_<OPTION>, for example JS_RECON_RUN_THREADS.
9
+ #
10
+ # null means "not configured". Keep credential-bearing files mode 0600.
11
+ version: 1
12
+
13
+ oxylabs:
14
+ # Required in an explicitly selected config when oxylabsWafFallback is true.
15
+ # JS_RECON_OXYLABS_USERNAME/PASSWORD/COUNTRY may override these values.
16
+ username: null
17
+ password: null
18
+ country: null
19
+
20
+ commands:
21
+ lazyload:
22
+ # May also be a YAML list of HTTP(S) URLs:
23
+ # url:
24
+ # - https://one.example.com
25
+ # - https://two.example.com
26
+ url: null
27
+ output: output
28
+ strictScope: false
29
+ scope: "*"
30
+ threads: "1"
31
+ subsequentRequests: false
32
+ urlsFile: extracted_urls.json
33
+ proxyConfig: .proxy_config.json
34
+ ignoreProxyEnv: false
35
+ oxylabsWafFallback: false
36
+ oxylabsFallbackMaxRequests: "10"
37
+ oxylabsFallbackMaxTotal: "100"
38
+ oxylabsFallbackMaxOrigins: "25"
39
+ cacheFile: .resp_cache.json
40
+ disableCache: false
41
+ cacheOnly: false
42
+ yes: false
43
+ timeout: "30000"
44
+ insecure: false
45
+ sandbox: true
46
+ buildId: false
47
+ sourcemapDir: extracted
48
+ research: false
49
+ researchOutput: research.json
50
+ maxIterations: "10"
51
+ maxJsSize: "2"
52
+ lazyloadTimeout: "30"
53
+ detectionTimeout: "30"
54
+ maxPages: "200"
55
+ includeMethods: null
56
+ excludeMethods: null
57
+ listMethods: null
58
+
59
+ endpoints:
60
+ url: null
61
+ directory: null
62
+ output: endpoints
63
+ outputFormat: json
64
+ tech: null
65
+ list: false
66
+ mappedJson: null
67
+
68
+ strings:
69
+ directory: null
70
+ output: strings.json
71
+ extractUrls: false
72
+ extractedUrlPath: extracted_urls
73
+ permutate: false
74
+ openapi: false
75
+ scanSecrets: false
76
+ trufflehog: false
77
+
78
+ proxy:
79
+ init: false
80
+ destroy: null
81
+ destroyAll: false
82
+ region: null
83
+ awsAccessKey: null
84
+ awsSecretKey: null
85
+ config: .proxy_config.json
86
+ list: false
87
+ feasibility: false
88
+ feasibilityUrl: null
89
+ proxyMethod: null
90
+ proxy: null
91
+ oxylabsUsername: null
92
+ oxylabsPassword: null
93
+ oxylabsCountry: null
94
+ oxylabsCity: null
95
+ oxylabsSessionId: null
96
+
97
+ map:
98
+ directory: null
99
+ tech: null
100
+ list: false
101
+ output: mapped
102
+ format: json
103
+ interactive: false
104
+ command: []
105
+ ai: null
106
+ aiThreads: "5"
107
+ aiProvider: openai
108
+ aiEndpoint: null
109
+ openaiApiKey: null
110
+ model: gpt-4o-mini
111
+ openapi: false
112
+ openapiOutput: mapped-openapi.json
113
+ openapiChunkTag: false
114
+ graphql: true
115
+ ngql: null
116
+ maxRecursionDepth: "3"
117
+ maxHeap: null
118
+
119
+ refactor:
120
+ mappedJson: mapped.json
121
+ output: output_refactored
122
+ tech: null
123
+ list: false
124
+ collisions: null
125
+ signatureQuality: "100"
126
+ refreshCache: false
127
+ skipCacheChecks: false
128
+ remote: true
129
+ remoteCollisions: null
130
+ scat: null
131
+ detectVersion: false
132
+ detectVersionConfig: null
133
+ detectVersionDynamicThreshold: "3"
134
+ detectVersionDynamicConfPurge: false
135
+
136
+ analyze:
137
+ rules: null
138
+ mappedJson: mapped.json
139
+ tech: null
140
+ openapi: null
141
+ list: false
142
+ validate: false
143
+ output: analyze.json
144
+ disableRulesVersionCheck: false
145
+
146
+ report:
147
+ sqliteDb: js-recon.db
148
+ mappedJson: null
149
+ analyzeJson: null
150
+ endpointsJson: null
151
+ mappedOpenapiJson: null
152
+ output: report
153
+
154
+ run:
155
+ # May also be a YAML list. Repeated -u flags and comma-separated URLs
156
+ # are supported on the command line; a target-file path is also valid.
157
+ # url:
158
+ # - https://one.example.com
159
+ # - https://two.example.com
160
+ url: null
161
+ rules: null
162
+ disableRulesVersionCheck: false
163
+ command: []
164
+ output: output
165
+ outputOverwrite: false
166
+ strictScope: false
167
+ scope: "*"
168
+ threads: "1"
169
+ proxyConfig: .proxy_config.json
170
+ ignoreProxyEnv: false
171
+ proxyWafFallback: false
172
+ oxylabsWafFallback: false
173
+ oxylabsFallbackMaxRequests: "10"
174
+ oxylabsFallbackMaxTotal: "100"
175
+ oxylabsFallbackMaxOrigins: "25"
176
+ cacheFile: .resp_cache.json
177
+ disableCache: false
178
+ cacheOnly: false
179
+ yes: false
180
+ secrets: false
181
+ trufflehog: false
182
+ ai: null
183
+ aiThreads: "5"
184
+ aiProvider: openai
185
+ aiEndpoint: null
186
+ openaiApiKey: null
187
+ model: gpt-4o-mini
188
+ mapOpenapiChunkTag: false
189
+ graphql: true
190
+ ngql: null
191
+ timeout: "30000"
192
+ insecure: false
193
+ sandbox: true
194
+ sourcemapDir: extracted
195
+ research: false
196
+ researchOutput: research.json
197
+ maxIterations: "10"
198
+ maxJsSize: "2"
199
+ lazyloadTimeout: "30"
200
+ detectionTimeout: "30"
201
+ maxHeap: null
202
+ maxPages: "200"
203
+ includeMethods: null
204
+ excludeMethods: null
205
+ listMethods: null
206
+ csMastTechDetectThreshold: "50"
207
+ disableRefactor: false
208
+
209
+ load:
210
+ caido: null
211
+ url: null
212
+ cacheFile: .resp_cache.json
213
+
214
+ fingerprint:
215
+ # May also be a YAML list of HTTP(S) URLs.
216
+ url: null
217
+ output: null
218
+ format: text
219
+ threads: "5"
220
+ timeout: "30000"
221
+ insecure: false
222
+ sandbox: true
223
+
224
+ mcp:
225
+ cli: false
226
+ server: false
227
+ chat: []
228
+ config: null
229
+ apiKey: null
230
+ model: null
231
+ provider: null
232
+ refreshClaudeCreds: true
233
+ claudeClientId: null
234
+
235
+ cs-mast:
236
+ output: output
237
+ collisionTable: false
238
+ minCollisions: "2"
239
+ collisionOutput: null
240
+ collisionFormat: csv
241
+ scat: lit,decl,loop,cond
242
+ sinc: ""
243
+ allScatPermutations: false
244
+ permOutput: null
245
+ permConcurrency: "0"
246
+
247
+ sourcemaps:
248
+ input: null
249
+ output: extracted
250
+
251
+ completion: {}
@@ -0,0 +1,106 @@
1
+ # Writing tests for js-recon
2
+
3
+ New functionality must ship with tests. Which kind depends on what you're adding — see below.
4
+
5
+ ## Unit tests (Vitest)
6
+
7
+ Test framework is [Vitest](https://vitest.dev/) — ESM-native, TypeScript-native, no build step.
8
+
9
+ ```bash
10
+ npm test # run all unit tests once
11
+ npm run test:watch # watch mode
12
+ npm run test:coverage # run with coverage report
13
+ ```
14
+
15
+ **What to test.** Pure functions: anything that takes plain inputs and returns a value without I/O.
16
+ Puppeteer, network calls (`makeRequest`), and file writes are intentionally left untested at the
17
+ unit level — they're validated end-to-end via the `run` subcommand instead (see below). When a
18
+ function mixes I/O with logic, extract the parse/transform step into an exported pure function and
19
+ test that:
20
+
21
+ ```typescript
22
+ // Exported pure function — testable
23
+ export const parseThings = (content: string, baseUrl: string): string[] => {
24
+ /* ... */
25
+ };
26
+
27
+ // Orchestrator — not unit-tested
28
+ const myModule = async (url: string): Promise<string[]> => {
29
+ const resp = await makeRequest(url);
30
+ const content = await resp.text();
31
+ return parseThings(content, url);
32
+ };
33
+ ```
34
+
35
+ **File layout.** Tests live in `src/__tests__/<component>/<name>.test.ts`, mirroring the source
36
+ path. Use `describe`/`it` blocks grouped by function name; cover the happy path, edge cases (empty
37
+ input, malformed input), and threshold boundaries.
38
+
39
+ **Local imports use the `.js` extension** (this is an ESM project with `"module": "node16"`):
40
+
41
+ ```typescript
42
+ import { fn } from "../../lazyLoad/next_js/myModule.js";
43
+ ```
44
+
45
+ **Constructing Babel AST nodes for tests.** If a function under test requires a real Babel AST node
46
+ (with `scope`, `path`, correct `start`/`end` offsets), parse a snippet and capture the node via a
47
+ `traverse` visitor rather than building it by hand:
48
+
49
+ ```typescript
50
+ import parser from "@babel/parser";
51
+ import _traverse from "@babel/traverse";
52
+ const traverse = (_traverse.default ?? _traverse) as typeof _traverse.default;
53
+
54
+ function parseExpr(code: string) {
55
+ const src = `const _x = ${code};`;
56
+ const ast = parser.parse(src, { sourceType: "unambiguous", plugins: ["jsx", "typescript"] });
57
+ let node: any;
58
+ traverse(ast, {
59
+ VariableDeclarator(p) {
60
+ node = p.node.init;
61
+ p.stop();
62
+ },
63
+ });
64
+ return { node, src };
65
+ }
66
+ ```
67
+
68
+ **Avoid GitHub's secret scanner false-positives.** Strings that look like real secrets (webhook
69
+ URLs, API keys) get blocked by push protection even inside test files. Assemble them at runtime:
70
+
71
+ ```typescript
72
+ // BAD — blocked by secret scanner
73
+ const url = "https://hooks.slack.com/services/TABCDEF/BABCDEF/xxxxxxxxxxxx";
74
+
75
+ // GOOD — assembled at runtime
76
+ const parts = ["https://hooks.slack.com/services/T", "ABCDEF/B", "ABCDEF/xxxx"];
77
+ const url = parts.join("");
78
+ ```
79
+
80
+ ## Fuzz tests (fast-check)
81
+
82
+ js-recon's job is parsing and analyzing JS bundles pulled from third-party targets — that input is
83
+ fully untrusted. Functions on that boundary (parsing raw bundle text, resolving URLs/strings out of
84
+ it) should get a property-based fuzz test in addition to example-based unit tests, using
85
+ [fast-check](https://fast-check.dev/).
86
+
87
+ ```bash
88
+ npm run test:fuzz # runs src/**/*.fuzz.test.ts via vitest.fuzz.config.ts
89
+ ```
90
+
91
+ Fuzz tests live alongside the function's regular unit test, named `<name>.fuzz.test.ts`, and are
92
+ excluded from the default `npm test` run (they're slower — property-based, hundreds of generated
93
+ cases per run). See `src/__tests__/strings/extractStrings.fuzz.test.ts` for the reference shape:
94
+ generate arbitrary/adversarial strings, feed them through the same parse config the real call site
95
+ uses, and assert the function under test never throws uncaught or hangs. If a parse step can
96
+ legitimately throw on malformed input (Babel's `errorRecovery: true` does not guarantee it won't),
97
+ wrap it in try/catch inside the test exactly as the real call site does — a caught, expected error
98
+ is not a fuzz failure; an uncaught throw or a hang is.
99
+
100
+ ## Smoke tests (CI)
101
+
102
+ The `rules-smoke-test` GitHub Actions workflow runs js-recon end-to-end against a seeded lab app and
103
+ asserts every expected rule fires. If you're adding a new AST/request rule to `js-recon-rules`, seed
104
+ the corresponding vulnerability in `js-recon-labs`'s `next_js/vuln-all-rules` app and add the rule ID
105
+ to `EXPECTED_RULES` in `scripts/smoke-test.js`. See the root `CLAUDE.md`'s "Rules smoke test (CI)"
106
+ section for details.
@@ -0,0 +1,24 @@
1
+ import tseslint from "typescript-eslint";
2
+ import security from "eslint-plugin-security";
3
+
4
+ export default tseslint.config(
5
+ {
6
+ ignores: ["build/**", "output/**", "output_refactored/**", "node_modules/**"],
7
+ },
8
+ {
9
+ files: ["src/**/*.ts"],
10
+ extends: [...tseslint.configs.recommended],
11
+ plugins: {
12
+ security,
13
+ },
14
+ rules: {
15
+ ...security.configs.recommended.rules,
16
+ // These fire on legitimate dynamic-code patterns intrinsic to a bundle-analysis tool
17
+ // (parsing/instrumenting untrusted third-party JS is the entire point of js-recon).
18
+ "security/detect-non-literal-fs-filename": "off",
19
+ "security/detect-object-injection": "off",
20
+ "@typescript-eslint/no-explicit-any": "off",
21
+ "@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
22
+ },
23
+ }
24
+ );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@js-recon/js-recon",
3
- "version": "1.4.3",
3
+ "version": "2.0.1-alpha.1",
4
4
  "description": "JS Recon Tool",
5
5
  "main": "build/index.js",
6
6
  "type": "module",
@@ -13,9 +13,12 @@
13
13
  "start": "node --max-old-space-size=8192 build/index.js",
14
14
  "test": "vitest run",
15
15
  "test:watch": "vitest",
16
+ "test:coverage": "vitest run --coverage",
17
+ "test:fuzz": "vitest run --config vitest.fuzz.config.ts",
16
18
  "test:build": "node build/index.js -h",
17
- "postinstall": "patch-package",
18
- "cleanup": "rm -rf build output output_refactored .resp_cache.json endpoints.json extracted_urls{.txt,.json,-openapi.json} strings.json mapped{-openapi.json,.json,-openapi.postman_collection.json} analyze.json test{.yaml,.js} js-recon-js-recon-*.tgz js-recon.db report.{html,md} js_recon_run_output *_test.js extracted/ research.json results* out.* && tsc"
19
+ "lint": "eslint src",
20
+ "postinstall": "patch-package || true; node scripts/postinstall-completion.mjs",
21
+ "cleanup": "rm -rf build output output_refactored .resp_cache.json .resp_cache.json.entries endpoints.json extracted_urls{.txt,.json,-openapi.json} strings.json mapped{-openapi.json,.json,-openapi.postman_collection.json} analyze.json test{.yaml,.js} js-recon-js-recon-*.tgz js-recon.db report.{html,md} js_recon_run_output *_test.js extracted/ research.json results* out.* swagger-jacker-results.json && tsc"
19
22
  },
20
23
  "keywords": [],
21
24
  "author": "Shriyans Sudhi",
@@ -27,7 +30,7 @@
27
30
  "@babel/traverse": "^7.28.5",
28
31
  "@babel/types": "^7.27.6",
29
32
  "@modelcontextprotocol/sdk": "^1.29.0",
30
- "@shriyanss/cli-print-img": "^1.1.0",
33
+ "@shriyanss/cli-print-img": "^1.1.1",
31
34
  "@shriyanss/cs-mast": "0.1.8",
32
35
  "@types/chalk": "^0.4.31",
33
36
  "@types/cli-progress": "^3.11.6",
@@ -41,6 +44,7 @@
41
44
  "datatables.net": "^2.3.6",
42
45
  "datatables.net-dt": "^2.3.6",
43
46
  "esquery": "^1.6.0",
47
+ "express": "^5.2.1",
44
48
  "extract-zip": "^2.0.1",
45
49
  "fs": "^0.0.2",
46
50
  "graphql": "^16.14.1",
@@ -48,6 +52,7 @@
48
52
  "inquirer": "^12.6.3",
49
53
  "marked": "^16.1.2",
50
54
  "md5": "^2.3.0",
55
+ "ohash": "^2.0.11",
51
56
  "ollama": "^0.6.3",
52
57
  "openai": "^5.8.2",
53
58
  "patch-package": "^8.0.1",
@@ -58,7 +63,10 @@
58
63
  "puppeteer-extra-plugin-stealth": "^2.11.2",
59
64
  "readline": "^1.3.0",
60
65
  "ses": "^1.13.0",
61
- "undici": "^7.28.0",
66
+ "shell-quote": "^1.10.0",
67
+ "tar": "^7.5.22",
68
+ "undici": "^7.29.0",
69
+ "ws": "^8.21.2",
62
70
  "yaml": "^2.8.0",
63
71
  "zod": "^3.23.8"
64
72
  },
@@ -78,11 +86,20 @@
78
86
  "@types/babel__traverse": "^7.28.0",
79
87
  "@types/better-sqlite3": "^7.6.13",
80
88
  "@types/blessed": "^0.1.25",
89
+ "@types/express": "^5.0.6",
81
90
  "@types/graphql": "^14.2.3",
82
91
  "@types/node": "^24.12.4",
92
+ "@types/shell-quote": "^1.7.5",
93
+ "@types/ws": "^8.18.1",
94
+ "@vitest/coverage-v8": "^4.1.10",
95
+ "eslint": "^10.8.0",
96
+ "eslint-plugin-security": "^4.0.1",
97
+ "fast-check": "^4.9.0",
98
+ "patch-package": "^8.0.1",
83
99
  "ts-node": "^10.9.2",
84
100
  "tsconfig-paths": "^4.2.0",
85
101
  "typescript": "^5.9.2",
102
+ "typescript-eslint": "^8.66.0",
86
103
  "vitest": "^4.1.10"
87
104
  }
88
105
  }
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Smoke test: verifies that the `exploit` module reported `vulnerable: true` for every CVE
4
+ * fixture in js-recon-labs.
5
+ *
6
+ * Usage:
7
+ * node scripts/exploit-smoke-test.js [results-dir]
8
+ *
9
+ * Expects one `<CVE-ID>.json` (rich exploit.json output shape) per CVE in results-dir, as
10
+ * produced by the `exploit-smoke-test.yaml` workflow's `-o` flag.
11
+ */
12
+
13
+ import { readFileSync, existsSync } from "fs";
14
+ import { resolve } from "path";
15
+
16
+ const resultsDir = process.argv[2] || "/tmp/exploit-results";
17
+
18
+ const EXPECTED_CVES = [
19
+ "CVE-2025-29927",
20
+ "CVE-2026-64645",
21
+ "CVE-2025-30208",
22
+ "CVE-2026-39363",
23
+ "CVE-2026-71320",
24
+ "CVE-2026-71315",
25
+ "CVE-2026-68945",
26
+ "CVE-2025-55182",
27
+ ];
28
+
29
+ // RCE-class CVEs must additionally prove their `id` proof output looks like real `id` command
30
+ // output, not just any non-empty string — otherwise a broken payload that returns garbage would
31
+ // still satisfy a loose `vulnerable: true` check.
32
+ const RCE_OUTPUT_PATTERN = /uid=\d+.*gid=\d+/;
33
+ const RCE_CVES = new Set(["CVE-2026-71320", "CVE-2025-55182"]);
34
+
35
+ let failures = [];
36
+
37
+ for (const cveId of EXPECTED_CVES) {
38
+ const filePath = resolve(resultsDir, `${cveId}.json`);
39
+ if (!existsSync(filePath)) {
40
+ failures.push(`${cveId}: no result file at ${filePath}`);
41
+ continue;
42
+ }
43
+
44
+ let findings;
45
+ try {
46
+ findings = JSON.parse(readFileSync(filePath, "utf-8"));
47
+ } catch (err) {
48
+ failures.push(`${cveId}: could not parse ${filePath}: ${err.message}`);
49
+ continue;
50
+ }
51
+
52
+ const finding = findings[0];
53
+ if (!finding || finding.vulnerable !== true) {
54
+ failures.push(`${cveId}: not reported vulnerable (evidence: ${finding?.evidence ?? "none"})`);
55
+ continue;
56
+ }
57
+
58
+ if (RCE_CVES.has(cveId)) {
59
+ const execOutput = finding.execOutput ?? "";
60
+ if (!RCE_OUTPUT_PATTERN.test(execOutput)) {
61
+ failures.push(
62
+ `${cveId}: vulnerable=true but execOutput doesn't look like real 'id' output: "${execOutput}"`
63
+ );
64
+ }
65
+ }
66
+
67
+ console.log(`[✓] ${cveId}: vulnerable (${finding.evidence.slice(0, 120)})`);
68
+ }
69
+
70
+ console.log();
71
+ console.log(`[i] ${EXPECTED_CVES.length - failures.length} / ${EXPECTED_CVES.length} CVEs confirmed vulnerable.`);
72
+
73
+ if (failures.length > 0) {
74
+ console.error();
75
+ console.error("[!] Exploit smoke test FAILED:");
76
+ for (const f of failures) {
77
+ console.error(` - ${f}`);
78
+ }
79
+ process.exit(1);
80
+ }
81
+
82
+ console.log("[✓] Exploit smoke test PASSED.");
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Smoke test: verifies that js-recon's `fingerprint` command detects the
4
+ * correct front-end framework for every lab app in the framework-detection
5
+ * matrix (js-recon-labs/detection/*).
6
+ *
7
+ * Usage:
8
+ * node scripts/framework-detect-smoke-test.js [path-to-fingerprint-result.json]
9
+ *
10
+ * Default path: /tmp/fingerprint-result.json
11
+ */
12
+
13
+ import { readFileSync } from "fs";
14
+ import { resolve } from "path";
15
+
16
+ const resultPath = process.argv[2] || "/tmp/fingerprint-result.json";
17
+ const absolutePath = resolve(resultPath);
18
+
19
+ let results;
20
+ try {
21
+ results = JSON.parse(readFileSync(absolutePath, "utf-8"));
22
+ } catch (err) {
23
+ console.error(`[!] Could not read ${absolutePath}: ${err.message}`);
24
+ console.error(" Make sure `js-recon fingerprint -f json` completed successfully before running this script.");
25
+ process.exit(1);
26
+ }
27
+
28
+ // URL -> expected framework name, matching js-recon-labs/detection/* app ports.
29
+ const EXPECTED = {
30
+ "http://localhost:3010": "next",
31
+ "http://localhost:3011": "vue",
32
+ "http://localhost:3012": "nuxt",
33
+ "http://localhost:3013": "svelte",
34
+ "http://localhost:3014": "angular",
35
+ "http://localhost:3015": "react",
36
+ "http://localhost:3016": "react",
37
+ };
38
+
39
+ const detected = new Map(results.map((r) => [r.url, r.framework]));
40
+ const rows = [];
41
+ let failed = false;
42
+
43
+ for (const [url, expected] of Object.entries(EXPECTED)) {
44
+ const actual = detected.get(url) ?? "unknown";
45
+ const ok = actual === expected;
46
+ if (!ok) failed = true;
47
+ rows.push({ url, expected, actual, ok });
48
+ }
49
+
50
+ console.log(`[i] Checked ${rows.length} lab apps.`);
51
+ console.log();
52
+ console.log("URL".padEnd(28), "Expected".padEnd(10), "Detected".padEnd(10), "Result");
53
+ for (const { url, expected, actual, ok } of rows) {
54
+ console.log(url.padEnd(28), expected.padEnd(10), actual.padEnd(10), ok ? "OK" : "MISMATCH");
55
+ }
56
+ console.log();
57
+
58
+ if (failed) {
59
+ const mismatches = rows.filter((r) => !r.ok).length;
60
+ console.error(`[!] ${mismatches} / ${rows.length} apps failed framework detection. Smoke test FAILED.`);
61
+ process.exit(1);
62
+ }
63
+
64
+ console.log(`[✓] All ${rows.length} apps detected correctly. Smoke test PASSED.`);