0sec-cli 0.18.0 → 0.22.0

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 (329) hide show
  1. package/{0sec.js → 0.js} +90 -82
  2. package/LICENSE +1 -1
  3. package/README.md +62 -46
  4. package/chunks/adapt-loop-7I57LXXR.js +18 -0
  5. package/chunks/{adgraph-JLGA6RYI.js → adgraph-AUDQTBYA.js} +5 -5
  6. package/chunks/agent/skills/frameworks/entra-id.yaml +2 -2
  7. package/chunks/agent/skills/techniques/assumption-mining.yaml +2 -2
  8. package/chunks/agent/skills/techniques/cve-poc-adaptation.yaml +2 -2
  9. package/chunks/agent/skills/techniques/entra-attack-paths.yaml +1 -1
  10. package/chunks/agent/skills/techniques/kernel-weaponization.yaml +1 -1
  11. package/chunks/agent/skills/techniques/llm-prompt-injection.yaml +2 -2
  12. package/chunks/agent/skills/techniques/npm-ecosystem.yaml +1 -1
  13. package/chunks/agent/skills/techniques/poc-verification.yaml +1 -1
  14. package/chunks/agent/skills/techniques/seedless-depth-review.yaml +20 -38
  15. package/chunks/{artifact-scraper-HQ7HLP6V.js → artifact-scraper-PYZ3RU3O.js} +6 -6
  16. package/chunks/{assumption-mining-5SNIVVDN.js → assumption-mining-MFLF43IR.js} +24 -26
  17. package/chunks/{chunk-7DQEV5QI.js → chunk-23DG5YKS.js} +4 -4
  18. package/chunks/{chunk-UR4ELX2Y.js → chunk-2GV4HQKE.js} +340 -703
  19. package/chunks/{chunk-P6WKNFWX.js → chunk-2OQOQ2FZ.js} +8 -8
  20. package/chunks/{chunk-5G3ZXFBW.js → chunk-2WNCI664.js} +3 -3
  21. package/chunks/{chunk-DW5UWPFY.js → chunk-4VGLO2YS.js} +6 -5
  22. package/chunks/{chunk-KLTNTE2Z.js → chunk-5IBCBQEH.js} +13 -14
  23. package/chunks/{chunk-N7BOUYEV.js → chunk-5MWAG3FT.js} +14 -14
  24. package/chunks/{chunk-OEFNRYI2.js → chunk-6GHSR47F.js} +3 -6
  25. package/chunks/chunk-6YNKRUMC.js +4474 -0
  26. package/chunks/{chunk-6L26OBWI.js → chunk-76KSBWOQ.js} +255 -35
  27. package/chunks/chunk-7DEHG7YT.js +2143 -0
  28. package/chunks/{chunk-AD7WXDH6.js → chunk-7UFUALR2.js} +288 -22
  29. package/chunks/{chunk-53G27VPS.js → chunk-AZ7L3HFD.js} +7 -2
  30. package/chunks/{chunk-TSK2AG6J.js → chunk-CAYANSH6.js} +173 -1757
  31. package/chunks/{chunk-SAFFWQW4.js → chunk-DKSCN2AB.js} +7 -7
  32. package/chunks/{chunk-2JCCA2JL.js → chunk-DM5C5L5D.js} +3 -3
  33. package/chunks/{chunk-RWONANDA.js → chunk-DQTNI3KY.js} +5 -5
  34. package/chunks/{chunk-5JI7L7KV.js → chunk-EGZGZFAH.js} +10036 -12938
  35. package/chunks/{chunk-6LKRLK2R.js → chunk-FHC2B7LN.js} +3 -3
  36. package/chunks/{chunk-MYVT64FN.js → chunk-GHWODZMR.js} +2 -2
  37. package/chunks/{chunk-2RMLOJVB.js → chunk-GVD6SJGH.js} +2 -2
  38. package/chunks/{chunk-SF4KZ4O3.js → chunk-HLFS6WV2.js} +2 -2
  39. package/chunks/chunk-HR2TU42B.js +1228 -0
  40. package/chunks/{chunk-BFRB6HB2.js → chunk-HUNAPTKV.js} +3 -3
  41. package/chunks/chunk-IO7R7WBM.js +114 -0
  42. package/chunks/{chunk-WEBMRWEG.js → chunk-IXT64DV5.js} +656 -1868
  43. package/chunks/{chunk-3MOLBTLS.js → chunk-K2PWUPUI.js} +2 -2
  44. package/chunks/{chunk-WXQ6BJ6A.js → chunk-LCRTAQN2.js} +7 -7
  45. package/chunks/{chunk-SVJEDVYK.js → chunk-LPTRPRZR.js} +5 -5
  46. package/chunks/{chunk-CMKXP5RR.js → chunk-LYUAM3TG.js} +3 -3
  47. package/chunks/{chunk-BVAZO4WA.js → chunk-MICHDTBK.js} +3 -3
  48. package/chunks/{chunk-UCYRA73C.js → chunk-OAYUPGF6.js} +4 -4
  49. package/chunks/{chunk-XM5NLHYU.js → chunk-OWLJYJ5O.js} +14 -14
  50. package/chunks/{chunk-BKZFDZ23.js → chunk-QCUFBVIZ.js} +3 -3
  51. package/chunks/chunk-RE5EZDG2.js +5523 -0
  52. package/chunks/{chunk-ASUR522M.js → chunk-RRD4XXPU.js} +9 -9
  53. package/chunks/{chunk-AHTBZC3E.js → chunk-RSIUX3RW.js} +4 -4
  54. package/chunks/{chunk-BZNEY2ZS.js → chunk-SJBCK2EI.js} +15268 -16053
  55. package/chunks/{chunk-IOL7D5YV.js → chunk-SQCBHFWN.js} +3 -3
  56. package/chunks/chunk-TH2LW437.js +7829 -0
  57. package/chunks/{chunk-WVTBZEQO.js → chunk-TM74SSHC.js} +8 -8
  58. package/chunks/{chunk-U5FLXGHT.js → chunk-TO35Y326.js} +13 -729
  59. package/chunks/chunk-TRH2PJSN.js +547 -0
  60. package/chunks/{chunk-YYRBQVFE.js → chunk-TZFIAMWZ.js} +70 -16
  61. package/chunks/chunk-UELXHK2Y.js +1950 -0
  62. package/chunks/{chunk-RJWOYEOG.js → chunk-UEX7PFSE.js} +5 -5
  63. package/chunks/{chunk-VQG4FT5D.js → chunk-UFHN6RIU.js} +2 -2
  64. package/chunks/{chunk-JQHOLLTD.js → chunk-UU7PQP6N.js} +9 -9
  65. package/chunks/{chunk-BFR2CDV5.js → chunk-UV5QWZGE.js} +283 -153
  66. package/chunks/{chunk-WU6AFRAZ.js → chunk-V36HVTUL.js} +12 -12
  67. package/chunks/{chunk-IR537GON.js → chunk-VCSFCHAJ.js} +2 -2
  68. package/chunks/{chunk-YLMN3N25.js → chunk-VIT5ALXF.js} +3 -3
  69. package/chunks/{chunk-BATRQBOR.js → chunk-VMRRNRMR.js} +41 -41
  70. package/chunks/{chunk-72CISA2D.js → chunk-VNRY6AWF.js} +89 -41
  71. package/chunks/chunk-W6UWZFKL.js +298 -0
  72. package/chunks/{chunk-3KPWWJCI.js → chunk-XFCTUKXR.js} +88 -88
  73. package/chunks/{chunk-GMT2AZKM.js → chunk-YIQSGNAA.js} +897 -130
  74. package/chunks/codex-models-7TLJSY3L.js +17 -0
  75. package/chunks/{commands-TBC2F5CE.js → commands-NEI7L3QA.js} +2836 -1424
  76. package/chunks/corpus-v1.json +2 -2
  77. package/chunks/data/appsec-archetypes.json +2 -2
  78. package/chunks/data/chromium-archetypes.json +1 -1
  79. package/chunks/data/freebsd-archetypes.json +1 -1
  80. package/chunks/data/kernel-archetypes.json +2 -2
  81. package/chunks/db-5AP3JB4W.js +16 -0
  82. package/chunks/{disclose-EKTWSCGW.js → disclose-LDNKAVRH.js} +13 -11
  83. package/chunks/{dist-4YICS2J2.js → dist-3FNZIBB4.js} +394 -404
  84. package/chunks/{dist-4MAW5X6L.js → dist-5YHYNLI3.js} +6 -6
  85. package/chunks/{dist-FMGSR3DW.js → dist-DD4H6HMQ.js} +13 -5
  86. package/chunks/dist-KEULE5IQ.js +21914 -0
  87. package/chunks/dist-XZB53PS5.js +53 -0
  88. package/chunks/eval-runner-43BO2C4T.js +26 -0
  89. package/chunks/example-manifest.json +2 -2
  90. package/chunks/{exploit-agent-45YQOHPJ.js → exploit-agent-N4A5ELBK.js} +4 -4
  91. package/chunks/{exploit-autoclimb-UZGEMGYT.js → exploit-autoclimb-N7P6KIF5.js} +6 -6
  92. package/chunks/{exploit-climb-SG23KB2G.js → exploit-climb-WNEJUB5W.js} +12 -12
  93. package/chunks/fix-Z452M4EC.js +26 -0
  94. package/chunks/{github-issues-MJ6OYOOU.js → github-issues-IGTTWM7V.js} +7 -7
  95. package/chunks/harness-QJJJVSG4.js +22 -0
  96. package/chunks/http-conformance-U5F6GKYG.js +11 -0
  97. package/chunks/http-sender-I5XFFY35.js +10 -0
  98. package/chunks/hunt-scan-K6D2V3PX.js +36 -0
  99. package/chunks/{identity-6ZAIIWOR.js → identity-62SVRW4H.js} +5 -5
  100. package/chunks/{kernel-primitive-7U6CWHXD.js → kernel-primitive-TKUACPKD.js} +6 -6
  101. package/chunks/{kernel-vm-runner-3JAU4O6J.js → kernel-vm-runner-RAAO2PGT.js} +6 -6
  102. package/chunks/memsafety-scan-FCPAXIZE.js +16 -0
  103. package/chunks/{native-loop-RJCJPOUS.js → native-loop-2ZRJENZ3.js} +17 -18
  104. package/chunks/{npm-detectors-KB5Y5ZFX.js → npm-detectors-Z2ZIQCN4.js} +6 -6
  105. package/chunks/npm-dynamic-discovery-5J7FT3XM.js +13 -0
  106. package/chunks/orchestrate-2GWGNTBF.js +58 -0
  107. package/chunks/{pre-recon-cve-66EB6G4M.js → pre-recon-cve-X2K2P5YQ.js} +4 -4
  108. package/chunks/prepare-KYHGFWCJ.js +13 -0
  109. package/chunks/process-N245QIQG.js +12 -0
  110. package/chunks/{run-D56MPDKY.js → run-U3XU4CTC.js} +11507 -13632
  111. package/chunks/{runtime-G7YWIO3B.js → runtime-G75TEWQY.js} +10 -11
  112. package/chunks/runtime-XFWJTBUO.js +12 -0
  113. package/chunks/{scan-stream-FHI2FYZE.js → scan-stream-BMOCPKQX.js} +7 -7
  114. package/chunks/scope-WXI46UHJ.js +21 -0
  115. package/chunks/{session-store-GZ4A4KYT.js → session-store-27L3ZU73.js} +6 -6
  116. package/chunks/source-files-REHOM44I.js +12 -0
  117. package/chunks/{specdrift-WCLH6TTQ.js → specdrift-AFS54WEJ.js} +5 -5
  118. package/chunks/token-KRWP5JYA.js +72 -0
  119. package/chunks/token-util-DWTL33S3.js +8 -0
  120. package/chunks/variant-candidates-YWZORZMK.js +13 -0
  121. package/chunks/{web-recon-prepass-JJGPEOLE.js → web-recon-prepass-YVMFXCIK.js} +9 -9
  122. package/cli-path-traversal-fixture.js +352 -0
  123. package/dashboard/assets/bot-Bg1Tp9_d.js +1 -0
  124. package/dashboard/assets/dist-B_dDCPbu.js +1 -0
  125. package/dashboard/assets/findings-page-mayGhNx6.js +5 -0
  126. package/dashboard/assets/format--susmHX7.js +1 -0
  127. package/dashboard/assets/input-TuVPR3Zl.js +1 -0
  128. package/dashboard/assets/jsx-runtime-MGseXjj5.js +3 -0
  129. package/dashboard/assets/live-page-HWWHX99U.js +1 -0
  130. package/dashboard/assets/meta-tile-ckHo-w7k.js +1 -0
  131. package/dashboard/assets/operations-BxZ0OoXO.js +10 -0
  132. package/dashboard/assets/operations-CMFVrXEe.css +2 -0
  133. package/dashboard/assets/operations-app-D3d35rgo.js +46 -0
  134. package/dashboard/assets/overview-page-W_4IteEr.js +1 -0
  135. package/dashboard/assets/page-header-Bw9AJgBV.js +1 -0
  136. package/dashboard/assets/scans-page-CgzVXHnn.js +1 -0
  137. package/dashboard/assets/siren-KQj8QAnJ.js +1 -0
  138. package/dashboard/assets/table-8EDklulN.js +1 -0
  139. package/dashboard/assets/tabs-CFHPOwg8.js +1 -0
  140. package/dashboard/index.html +4 -5
  141. package/node_modules/node-addon-api/LICENSE.md +9 -0
  142. package/node_modules/node-addon-api/README.md +95 -0
  143. package/node_modules/node-addon-api/common.gypi +21 -0
  144. package/node_modules/node-addon-api/except.gypi +25 -0
  145. package/node_modules/node-addon-api/index.js +14 -0
  146. package/node_modules/node-addon-api/napi-inl.deprecated.h +186 -0
  147. package/node_modules/node-addon-api/napi-inl.h +7250 -0
  148. package/node_modules/node-addon-api/napi.h +3463 -0
  149. package/node_modules/node-addon-api/node_addon_api.gyp +42 -0
  150. package/node_modules/node-addon-api/node_api.gyp +9 -0
  151. package/node_modules/node-addon-api/noexcept.gypi +26 -0
  152. package/node_modules/node-addon-api/nothing.c +0 -0
  153. package/node_modules/node-addon-api/package-support.json +21 -0
  154. package/node_modules/node-addon-api/package.json +481 -0
  155. package/node_modules/node-addon-api/tools/README.md +73 -0
  156. package/node_modules/node-addon-api/tools/check-napi.js +99 -0
  157. package/node_modules/node-addon-api/tools/clang-format.js +71 -0
  158. package/node_modules/node-addon-api/tools/conversion.js +301 -0
  159. package/node_modules/node-gyp-build/LICENSE +21 -0
  160. package/node_modules/node-gyp-build/README.md +58 -0
  161. package/node_modules/node-gyp-build/SECURITY.md +5 -0
  162. package/node_modules/node-gyp-build/bin.js +84 -0
  163. package/node_modules/node-gyp-build/build-test.js +19 -0
  164. package/node_modules/node-gyp-build/index.js +6 -0
  165. package/node_modules/node-gyp-build/node-gyp-build.js +207 -0
  166. package/node_modules/node-gyp-build/optional.js +7 -0
  167. package/node_modules/node-gyp-build/package.json +43 -0
  168. package/node_modules/tree-sitter/LICENSE +21 -0
  169. package/node_modules/tree-sitter/README.md +90 -0
  170. package/node_modules/tree-sitter/binding.gyp +76 -0
  171. package/node_modules/tree-sitter/index.js +895 -0
  172. package/node_modules/tree-sitter/package.json +62 -0
  173. package/node_modules/tree-sitter/prebuilds/darwin-arm64/tree-sitter.node +0 -0
  174. package/node_modules/tree-sitter/prebuilds/darwin-x64/tree-sitter.node +0 -0
  175. package/node_modules/tree-sitter/prebuilds/linux-x64/tree-sitter.node +0 -0
  176. package/node_modules/tree-sitter/prebuilds/win32-x64/tree-sitter.node +0 -0
  177. package/node_modules/tree-sitter/src/addon_data.h +47 -0
  178. package/node_modules/tree-sitter/src/binding.cc +35 -0
  179. package/node_modules/tree-sitter/src/conversions.cc +140 -0
  180. package/node_modules/tree-sitter/src/conversions.h +22 -0
  181. package/node_modules/tree-sitter/src/language.cc +106 -0
  182. package/node_modules/tree-sitter/src/language.h +17 -0
  183. package/node_modules/tree-sitter/src/logger.cc +70 -0
  184. package/node_modules/tree-sitter/src/logger.h +19 -0
  185. package/node_modules/tree-sitter/src/lookaheaditerator.cc +122 -0
  186. package/node_modules/tree-sitter/src/lookaheaditerator.h +33 -0
  187. package/node_modules/tree-sitter/src/node.cc +1056 -0
  188. package/node_modules/tree-sitter/src/node.h +30 -0
  189. package/node_modules/tree-sitter/src/parser.cc +298 -0
  190. package/node_modules/tree-sitter/src/parser.h +35 -0
  191. package/node_modules/tree-sitter/src/query.cc +383 -0
  192. package/node_modules/tree-sitter/src/query.h +39 -0
  193. package/node_modules/tree-sitter/src/tree.cc +307 -0
  194. package/node_modules/tree-sitter/src/tree.h +45 -0
  195. package/node_modules/tree-sitter/src/tree_cursor.cc +213 -0
  196. package/node_modules/tree-sitter/src/tree_cursor.h +52 -0
  197. package/node_modules/tree-sitter/tree-sitter.d.ts +211 -0
  198. package/node_modules/tree-sitter/vendor/tree-sitter/LICENSE +21 -0
  199. package/node_modules/tree-sitter/vendor/tree-sitter/README.md +21 -0
  200. package/node_modules/tree-sitter/vendor/tree-sitter/lib/README.md +6 -0
  201. package/node_modules/tree-sitter/vendor/tree-sitter/lib/include/tree_sitter/api.h +1266 -0
  202. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/alloc.c +48 -0
  203. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/alloc.h +41 -0
  204. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/array.h +290 -0
  205. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/atomic.h +68 -0
  206. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/clock.h +146 -0
  207. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/error_costs.h +11 -0
  208. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/get_changed_ranges.c +501 -0
  209. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/get_changed_ranges.h +36 -0
  210. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/host.h +21 -0
  211. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/language.c +221 -0
  212. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/language.h +299 -0
  213. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/length.h +52 -0
  214. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/lexer.c +419 -0
  215. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/lexer.h +49 -0
  216. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/lib.c +14 -0
  217. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/node.c +774 -0
  218. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/parser.c +2151 -0
  219. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/parser.h +230 -0
  220. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/point.h +62 -0
  221. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/query.c +4134 -0
  222. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/reduce_action.h +34 -0
  223. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/reusable_node.h +95 -0
  224. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/stack.c +899 -0
  225. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/stack.h +133 -0
  226. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/subtree.c +1060 -0
  227. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/subtree.h +382 -0
  228. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/tree.c +165 -0
  229. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/tree.h +31 -0
  230. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/tree_cursor.c +714 -0
  231. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/tree_cursor.h +48 -0
  232. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/ICU_SHA +1 -0
  233. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/LICENSE +414 -0
  234. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/README.md +29 -0
  235. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/ptypes.h +1 -0
  236. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/umachine.h +448 -0
  237. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/urename.h +1 -0
  238. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/utf.h +1 -0
  239. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/utf16.h +733 -0
  240. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/utf8.h +881 -0
  241. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode.h +50 -0
  242. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm/stdlib-symbols.txt +23 -0
  243. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm/stdlib.c +109 -0
  244. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm/wasm-stdlib.h +1294 -0
  245. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm_store.c +1823 -0
  246. package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm_store.h +31 -0
  247. package/node_modules/tree-sitter/vendor/tree-sitter/test/fixtures/grammars/.gitkeep +0 -0
  248. package/node_modules/tree-sitter-c/LICENSE +21 -0
  249. package/node_modules/tree-sitter-c/README.md +18 -0
  250. package/node_modules/tree-sitter-c/binding.gyp +20 -0
  251. package/node_modules/tree-sitter-c/bindings/node/binding.cc +20 -0
  252. package/node_modules/tree-sitter-c/bindings/node/index.d.ts +28 -0
  253. package/node_modules/tree-sitter-c/bindings/node/index.js +7 -0
  254. package/node_modules/tree-sitter-c/grammar.js +1463 -0
  255. package/node_modules/tree-sitter-c/package.json +108 -0
  256. package/node_modules/tree-sitter-c/prebuilds/darwin-arm64/tree-sitter-c.node +0 -0
  257. package/node_modules/tree-sitter-c/prebuilds/darwin-x64/tree-sitter-c.node +0 -0
  258. package/node_modules/tree-sitter-c/prebuilds/linux-x64/tree-sitter-c.node +0 -0
  259. package/node_modules/tree-sitter-c/prebuilds/win32-x64/tree-sitter-c.node +0 -0
  260. package/node_modules/tree-sitter-c/queries/highlights.scm +81 -0
  261. package/node_modules/tree-sitter-c/queries/tags.scm +9 -0
  262. package/node_modules/tree-sitter-c/src/grammar.json +9682 -0
  263. package/node_modules/tree-sitter-c/src/node-types.json +4556 -0
  264. package/node_modules/tree-sitter-c/src/parser.c +113852 -0
  265. package/node_modules/tree-sitter-c/src/tree_sitter/alloc.h +54 -0
  266. package/node_modules/tree-sitter-c/src/tree_sitter/array.h +290 -0
  267. package/node_modules/tree-sitter-c/src/tree_sitter/parser.h +265 -0
  268. package/package.json +20 -13
  269. package/vendor/tree-sitter-0.21.1-node24.json +16 -0
  270. package/vendor/tree-sitter-0.21.1-node24.tgz +0 -0
  271. package/chunks/adapt-loop-SMH6V4PD.js +0 -18
  272. package/chunks/appsec-catalog-CBWHGTEL.js +0 -24
  273. package/chunks/chunk-242TMK6G.js +0 -110
  274. package/chunks/chunk-57ZENEX2.js +0 -169
  275. package/chunks/chunk-ADOLI6DT.js +0 -102
  276. package/chunks/chunk-ATATQACO.js +0 -471
  277. package/chunks/chunk-C2WXWFBB.js +0 -1070
  278. package/chunks/chunk-F3WBKITT.js +0 -687
  279. package/chunks/chunk-H2FFLZNK.js +0 -3
  280. package/chunks/chunk-LP3HHYQU.js +0 -245
  281. package/chunks/chunk-QI233I24.js +0 -333
  282. package/chunks/chunk-RRMJC3ZE.js +0 -105
  283. package/chunks/chunk-Z5FA2XOX.js +0 -2798
  284. package/chunks/cost-ledger-NU63MYZM.js +0 -13
  285. package/chunks/db-KFWOAUUB.js +0 -16
  286. package/chunks/eval-runner-7ZF472KV.js +0 -27
  287. package/chunks/fix-IG7LYXH3.js +0 -12
  288. package/chunks/harness-7ODOLOWU.js +0 -22
  289. package/chunks/http-conformance-DU66MZIU.js +0 -11
  290. package/chunks/http-sender-GWH2IYEA.js +0 -10
  291. package/chunks/hunt-scan-MMKUOETU.js +0 -38
  292. package/chunks/memsafety-scan-J7SECV5W.js +0 -16
  293. package/chunks/npm-dynamic-discovery-AHROOZDB.js +0 -13
  294. package/chunks/orchestrate-OC2VZN2X.js +0 -62
  295. package/chunks/pipeline-BZK5BLJR.js +0 -14
  296. package/chunks/prepare-MYY743TK.js +0 -13
  297. package/chunks/process-LQRCS5OY.js +0 -13
  298. package/chunks/replay-runner-45G3VU7X.js +0 -39
  299. package/chunks/runtime-J7PLXZNM.js +0 -12
  300. package/chunks/scope-BI7BF4ZY.js +0 -18
  301. package/chunks/source-files-PWRQR6LY.js +0 -12
  302. package/chunks/variant-candidates-YERCYMPD.js +0 -13
  303. package/dashboard/assets/0sec-icon-66SreztZ.gif +0 -0
  304. package/dashboard/assets/bot-yILPnRgD.js +0 -1
  305. package/dashboard/assets/chevron-down-BeDJ-Vka.js +0 -1
  306. package/dashboard/assets/circle-alert-BEnMBMT-.js +0 -1
  307. package/dashboard/assets/client-DRYsuOGl.js +0 -9
  308. package/dashboard/assets/copy-Bi5vzoF9.js +0 -1
  309. package/dashboard/assets/desktop-CXTQonNm.js +0 -32
  310. package/dashboard/assets/desktop-NOekk4QS.css +0 -1
  311. package/dashboard/assets/dist-CmX-h7a4.js +0 -1
  312. package/dashboard/assets/dist-DAwYQmf_.js +0 -45
  313. package/dashboard/assets/findings-page-CACW9nw2.js +0 -5
  314. package/dashboard/assets/format-PoISqsES.js +0 -1
  315. package/dashboard/assets/jsx-runtime-C7oxC63R.js +0 -1
  316. package/dashboard/assets/live-page-DrgQqQK5.js +0 -1
  317. package/dashboard/assets/meta-tile-CcskIV_o.js +0 -1
  318. package/dashboard/assets/operations-BKE8T-vY.css +0 -2
  319. package/dashboard/assets/operations-D8nUP5_m.js +0 -4
  320. package/dashboard/assets/operations-app-CQQhG54n.js +0 -2
  321. package/dashboard/assets/overview-page-DTGS8dPo.js +0 -1
  322. package/dashboard/assets/page-header-MFVvEtZW.js +0 -1
  323. package/dashboard/assets/play-Dwo-9xt6.js +0 -1
  324. package/dashboard/assets/scans-page-ChVtq8Us.js +0 -1
  325. package/dashboard/assets/search-CiooTLck.js +0 -1
  326. package/dashboard/assets/siren-CCBwTSuk.js +0 -1
  327. package/dashboard/assets/table-BYS-nIVA.js +0 -1
  328. package/dashboard/assets/tabs-DivxbhQy.js +0 -1
  329. package/dashboard/desktop.html +0 -21
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import { createRequire as __0secCreateRequire } from "node:module";
3
- const require = __0secCreateRequire(import.meta.url);
2
+ import { createRequire as __0CreateRequire } from "node:module";
3
+ const require = __0CreateRequire(import.meta.url);
4
4
  import {
5
5
  __commonJS,
6
6
  __require
7
- } from "./chunk-IR537GON.js";
7
+ } from "./chunk-VCSFCHAJ.js";
8
8
 
9
9
  // node_modules/.pnpm/yaml@2.9.0/node_modules/yaml/dist/nodes/identity.js
10
10
  var require_identity = __commonJS({
@@ -7393,1917 +7393,718 @@ function analyzeFindingForKnownMarkers(finding) {
7393
7393
  };
7394
7394
  }
7395
7395
 
7396
- // packages/core/dist/disclose/cwe.js
7397
- var CWE_MAP = {
7398
- // LLM / agent
7399
- "prompt-injection": [
7400
- { id: "CWE-1039", name: "Inadequate Detection or Handling of Adversarial Input Perturbations in AI/ML Classifier", role: "primary" },
7401
- { id: "CWE-20", name: "Improper Input Validation", role: "secondary" },
7402
- { id: "CWE-94", name: "Improper Control of Generation of Code ('Code Injection')", role: "secondary" }
7403
- ],
7404
- "jailbreak": [
7405
- { id: "CWE-1039", name: "Inadequate Detection or Handling of Adversarial Input Perturbations in AI/ML Classifier", role: "primary" },
7406
- { id: "CWE-284", name: "Improper Access Control", role: "secondary" }
7407
- ],
7408
- "system-prompt-extraction": [
7409
- { id: "CWE-200", name: "Exposure of Sensitive Information to an Unauthorized Actor", role: "primary" },
7410
- { id: "CWE-1039", name: "Inadequate Detection or Handling of Adversarial Input Perturbations in AI/ML Classifier", role: "secondary" }
7411
- ],
7412
- "data-exfiltration": [
7413
- { id: "CWE-200", name: "Exposure of Sensitive Information to an Unauthorized Actor", role: "primary" },
7414
- { id: "CWE-522", name: "Insufficiently Protected Credentials", role: "secondary" }
7415
- ],
7416
- "tool-misuse": [
7417
- { id: "CWE-284", name: "Improper Access Control", role: "primary" },
7418
- { id: "CWE-441", name: "Unintended Proxy or Intermediary ('Confused Deputy')", role: "secondary" },
7419
- { id: "CWE-285", name: "Improper Authorization", role: "secondary" }
7420
- ],
7421
- "output-manipulation": [
7422
- { id: "CWE-116", name: "Improper Encoding or Escaping of Output", role: "primary" },
7423
- { id: "CWE-74", name: "Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')", role: "secondary" }
7424
- ],
7425
- "encoding-bypass": [
7426
- { id: "CWE-176", name: "Improper Handling of Unicode Encoding", role: "primary" },
7427
- { id: "CWE-20", name: "Improper Input Validation", role: "secondary" }
7428
- ],
7429
- "multi-turn": [
7430
- { id: "CWE-1039", name: "Inadequate Detection or Handling of Adversarial Input Perturbations in AI/ML Classifier", role: "primary" },
7431
- { id: "CWE-841", name: "Improper Enforcement of Behavioral Workflow", role: "secondary" }
7432
- ],
7433
- // Source-code audit
7434
- "prototype-pollution": [
7435
- { id: "CWE-1321", name: "Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')", role: "primary" },
7436
- { id: "CWE-915", name: "Improperly Controlled Modification of Dynamically-Determined Object Attributes", role: "secondary" }
7437
- ],
7438
- "path-traversal": [
7439
- { id: "CWE-22", name: "Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')", role: "primary" },
7440
- { id: "CWE-73", name: "External Control of File Name or Path", role: "secondary" },
7441
- { id: "CWE-284", name: "Improper Access Control", role: "secondary" }
7442
- ],
7443
- "command-injection": [
7444
- { id: "CWE-78", name: "Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')", role: "primary" },
7445
- { id: "CWE-77", name: "Improper Neutralization of Special Elements used in a Command ('Command Injection')", role: "secondary" }
7446
- ],
7447
- "code-injection": [
7448
- { id: "CWE-94", name: "Improper Control of Generation of Code ('Code Injection')", role: "primary" },
7449
- { id: "CWE-95", name: "Improper Neutralization of Directives in Dynamically Evaluated Code ('Eval Injection')", role: "secondary" }
7450
- ],
7451
- "regex-dos": [
7452
- { id: "CWE-1333", name: "Inefficient Regular Expression Complexity", role: "primary" },
7453
- { id: "CWE-400", name: "Uncontrolled Resource Consumption", role: "secondary" }
7454
- ],
7455
- "unsafe-deserialization": [
7456
- { id: "CWE-502", name: "Deserialization of Untrusted Data", role: "primary" },
7457
- { id: "CWE-915", name: "Improperly Controlled Modification of Dynamically-Determined Object Attributes", role: "secondary" }
7458
- ],
7459
- "information-disclosure": [
7460
- { id: "CWE-200", name: "Exposure of Sensitive Information to an Unauthorized Actor", role: "primary" },
7461
- { id: "CWE-285", name: "Improper Authorization", role: "secondary" },
7462
- { id: "CWE-522", name: "Insufficiently Protected Credentials", role: "secondary" }
7463
- ],
7464
- "ssrf": [
7465
- { id: "CWE-918", name: "Server-Side Request Forgery (SSRF)", role: "primary" },
7466
- { id: "CWE-20", name: "Improper Input Validation", role: "secondary" },
7467
- { id: "CWE-441", name: "Unintended Proxy or Intermediary ('Confused Deputy')", role: "secondary" }
7468
- ],
7469
- "sql-injection": [
7470
- { id: "CWE-89", name: "Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')", role: "primary" }
7471
- ],
7472
- "xss": [
7473
- { id: "CWE-79", name: "Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')", role: "primary" },
7474
- { id: "CWE-80", name: "Improper Neutralization of Script-Related HTML Tags in a Web Page (Basic XSS)", role: "secondary" }
7475
- ],
7476
- "cors": [
7477
- { id: "CWE-942", name: "Permissive Cross-domain Policy with Untrusted Domains", role: "primary" },
7478
- { id: "CWE-346", name: "Origin Validation Error", role: "secondary" }
7479
- ],
7480
- "security-misconfiguration": [
7481
- { id: "CWE-1188", name: "Initialization of a Resource with an Insecure Default", role: "primary" },
7482
- { id: "CWE-16", name: "Configuration", role: "secondary" }
7483
- ],
7484
- "missing-validation": [
7485
- { id: "CWE-20", name: "Improper Input Validation", role: "primary" }
7486
- ],
7487
- "crypto-misuse": [
7488
- { id: "CWE-327", name: "Use of a Broken or Risky Cryptographic Algorithm", role: "primary" },
7489
- { id: "CWE-328", name: "Use of Weak Hash", role: "secondary" },
7490
- { id: "CWE-321", name: "Use of Hard-coded Cryptographic Key", role: "secondary" },
7491
- { id: "CWE-329", name: "Generation of Predictable IV with CBC Mode", role: "secondary" },
7492
- { id: "CWE-330", name: "Use of Insufficiently Random Values", role: "secondary" },
7493
- { id: "CWE-347", name: "Improper Verification of Cryptographic Signature", role: "secondary" }
7494
- ],
7495
- // Memory corruption / binary
7496
- "heap-overflow": [
7497
- { id: "CWE-122", name: "Heap-based Buffer Overflow", role: "primary" },
7498
- { id: "CWE-787", name: "Out-of-bounds Write", role: "secondary" }
7499
- ],
7500
- "out-of-bounds-read": [
7501
- { id: "CWE-125", name: "Out-of-bounds Read", role: "primary" }
7502
- ],
7503
- "out-of-bounds-write": [
7504
- { id: "CWE-787", name: "Out-of-bounds Write", role: "primary" },
7505
- { id: "CWE-122", name: "Heap-based Buffer Overflow", role: "secondary" }
7506
- ],
7507
- "use-after-free": [
7508
- { id: "CWE-416", name: "Use After Free", role: "primary" },
7509
- { id: "CWE-672", name: "Operation on a Resource after Expiration or Release", role: "secondary" }
7510
- ],
7511
- "stack-buffer-overflow": [
7512
- { id: "CWE-121", name: "Stack-based Buffer Overflow", role: "primary" },
7513
- { id: "CWE-787", name: "Out-of-bounds Write", role: "secondary" }
7514
- ],
7515
- "null-pointer-deref": [
7516
- { id: "CWE-476", name: "NULL Pointer Dereference", role: "primary" }
7517
- ],
7518
- "null-deref": [
7519
- { id: "CWE-476", name: "NULL Pointer Dereference", role: "primary" }
7520
- ],
7521
- "integer-overflow": [
7522
- { id: "CWE-190", name: "Integer Overflow or Wraparound", role: "primary" },
7523
- { id: "CWE-191", name: "Integer Underflow (Wrap or Wraparound)", role: "secondary" }
7524
- ],
7525
- "integer-truncation": [
7526
- { id: "CWE-197", name: "Numeric Truncation Error", role: "primary" },
7527
- { id: "CWE-681", name: "Incorrect Conversion between Numeric Types", role: "secondary" }
7528
- ],
7529
- "denial-of-service": [
7530
- { id: "CWE-400", name: "Uncontrolled Resource Consumption", role: "primary" },
7531
- { id: "CWE-833", name: "Deadlock", role: "secondary" }
7532
- ],
7533
- "race-condition": [
7534
- { id: "CWE-362", name: "Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')", role: "primary" },
7535
- { id: "CWE-367", name: "Time-of-check Time-of-use (TOCTOU) Race Condition", role: "secondary" }
7536
- ],
7537
- "toctou": [
7538
- { id: "CWE-367", name: "Time-of-check Time-of-use (TOCTOU) Race Condition", role: "primary" },
7539
- { id: "CWE-362", name: "Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')", role: "secondary" }
7540
- ],
7541
- "type-confusion": [
7542
- { id: "CWE-843", name: "Access of Resource Using Incompatible Type ('Type Confusion')", role: "primary" }
7543
- ],
7544
- "double-free": [
7545
- { id: "CWE-415", name: "Double Free", role: "primary" }
7546
- ],
7547
- "format-string": [
7548
- { id: "CWE-134", name: "Use of Externally-Controlled Format String", role: "primary" }
7549
- ],
7550
- "uninitialized-memory": [
7551
- { id: "CWE-457", name: "Use of Uninitialized Variable", role: "primary" },
7552
- { id: "CWE-908", name: "Use of Uninitialized Resource", role: "secondary" }
7553
- ],
7554
- // Supply-chain / package
7555
- "known-vulnerable-package": [
7556
- { id: "CWE-1395", name: "Dependency on Vulnerable Third-Party Component", role: "primary" },
7557
- { id: "CWE-1104", name: "Use of Unmaintained Third Party Components", role: "secondary" },
7558
- { id: "CWE-937", name: "OWASP Top Ten 2013 Category A9 - Using Components with Known Vulnerabilities", role: "secondary" }
7559
- ],
7560
- "supply-chain": [
7561
- { id: "CWE-1357", name: "Reliance on Insufficiently Trustworthy Component", role: "primary" },
7562
- { id: "CWE-506", name: "Embedded Malicious Code", role: "secondary" },
7563
- { id: "CWE-829", name: "Inclusion of Functionality from Untrusted Control Sphere", role: "secondary" }
7564
- ],
7565
- "other": [
7566
- { id: "CWE-693", name: "Protection Mechanism Failure", role: "primary" }
7567
- ]
7568
- };
7569
- function suggestCwesForCategory(category) {
7570
- return CWE_MAP[category] ?? [
7571
- { id: "CWE-693", name: "Protection Mechanism Failure", role: "primary" }
7572
- ];
7573
- }
7574
- function formatCweSection(entries) {
7575
- if (entries.length === 0)
7576
- return "";
7577
- const lines = ["# CWE", ""];
7578
- lines.push("Pick these in the GHSA form's CWE selector (multi-select):");
7579
- lines.push("");
7580
- for (const entry of entries) {
7581
- const emphasis = entry.role === "primary" ? " *(primary)*" : "";
7582
- lines.push(`- **${entry.id}**: ${entry.name}${emphasis}`);
7396
+ // packages/core/dist/disclose/poc-runtime.js
7397
+ import { spawn } from "node:child_process";
7398
+ var MAX_CAPTURE_BYTES = 1024 * 1024;
7399
+ var DEFAULT_STEP_TIMEOUT_MS = 3e4;
7400
+ var PERSONA_HEADER = "X-0-Persona";
7401
+ var TRUNCATION_MARKER = "\n\u2026[truncated at 1MiB]";
7402
+ var DEFAULT_RPS_PER_HOST = 2;
7403
+ var MAX_REDIRECT_HOPS = 5;
7404
+ var hostBuckets = /* @__PURE__ */ new Map();
7405
+ function getOrInitBucket(host, rps) {
7406
+ let bucket = hostBuckets.get(host);
7407
+ if (!bucket) {
7408
+ bucket = {
7409
+ tokens: rps,
7410
+ // full bucket on first use
7411
+ refillRatePerMs: rps / 1e3,
7412
+ capacity: rps,
7413
+ lastRefill: Date.now(),
7414
+ retryUntil: 0
7415
+ };
7416
+ hostBuckets.set(host, bucket);
7583
7417
  }
7584
- return lines.join("\n");
7585
- }
7586
-
7587
- // packages/core/dist/disclose/cvss.js
7588
- var IMPACT_BY_CATEGORY = {
7589
- "prompt-injection": { C: "L", I: "L", A: "N", scope: "U" },
7590
- "jailbreak": { C: "L", I: "L", A: "N", scope: "U" },
7591
- "system-prompt-extraction": { C: "H", I: "N", A: "N", scope: "U" },
7592
- "data-exfiltration": { C: "H", I: "N", A: "N", scope: "C" },
7593
- "tool-misuse": { C: "H", I: "H", A: "L", scope: "C" },
7594
- "output-manipulation": { C: "L", I: "H", A: "N", scope: "U" },
7595
- "encoding-bypass": { C: "L", I: "L", A: "N", scope: "U" },
7596
- "multi-turn": { C: "L", I: "L", A: "N", scope: "U" },
7597
- "prototype-pollution": { C: "H", I: "H", A: "H", scope: "U" },
7598
- "path-traversal": { C: "H", I: "H", A: "L", scope: "U" },
7599
- "command-injection": { C: "H", I: "H", A: "H", scope: "U" },
7600
- "code-injection": { C: "H", I: "H", A: "H", scope: "U" },
7601
- "regex-dos": { C: "N", I: "N", A: "H", scope: "U" },
7602
- "unsafe-deserialization": { C: "H", I: "H", A: "H", scope: "U" },
7603
- "information-disclosure": { C: "H", I: "N", A: "N", scope: "C" },
7604
- "ssrf": { C: "H", I: "N", A: "N", scope: "C" },
7605
- "sql-injection": { C: "H", I: "H", A: "H", scope: "U" },
7606
- "xss": { C: "L", I: "L", A: "N", scope: "C" },
7607
- "cors": { C: "L", I: "L", A: "N", scope: "U" },
7608
- "security-misconfiguration": { C: "L", I: "L", A: "N", scope: "U" },
7609
- "missing-validation": { C: "L", I: "L", A: "L", scope: "U" },
7610
- "crypto-misuse": { C: "H", I: "H", A: "N", scope: "U" },
7611
- "heap-overflow": { C: "H", I: "H", A: "H", scope: "U" },
7612
- "out-of-bounds-read": { C: "H", I: "N", A: "L", scope: "U" },
7613
- "out-of-bounds-write": { C: "H", I: "H", A: "H", scope: "U" },
7614
- "use-after-free": { C: "H", I: "H", A: "H", scope: "U" },
7615
- "stack-buffer-overflow": { C: "H", I: "H", A: "H", scope: "U" },
7616
- "null-pointer-deref": { C: "N", I: "N", A: "H", scope: "U" },
7617
- "null-deref": { C: "N", I: "N", A: "H", scope: "U" },
7618
- "integer-overflow": { C: "L", I: "L", A: "L", scope: "U" },
7619
- "integer-truncation": { C: "L", I: "L", A: "L", scope: "U" },
7620
- "race-condition": { C: "L", I: "L", A: "L", scope: "U" },
7621
- "denial-of-service": { C: "N", I: "N", A: "H", scope: "U" },
7622
- "toctou": { C: "L", I: "L", A: "L", scope: "U" },
7623
- "type-confusion": { C: "H", I: "H", A: "H", scope: "U" },
7624
- "double-free": { C: "H", I: "H", A: "H", scope: "U" },
7625
- "format-string": { C: "H", I: "H", A: "H", scope: "U" },
7626
- "uninitialized-memory": { C: "H", I: "N", A: "L", scope: "U" },
7627
- "known-vulnerable-package": { C: "L", I: "L", A: "L", scope: "U" },
7628
- "supply-chain": { C: "H", I: "H", A: "H", scope: "C" },
7629
- "other": { C: "L", I: "L", A: "L", scope: "U" }
7630
- };
7631
- var W = {
7632
- AV: { N: 0.85, A: 0.62, L: 0.55, P: 0.2 },
7633
- AC: { L: 0.77, H: 0.44 },
7634
- PR_U: { N: 0.85, L: 0.62, H: 0.27 },
7635
- PR_C: { N: 0.85, L: 0.68, H: 0.5 },
7636
- UI: { N: 0.85, R: 0.62 },
7637
- CIA: { N: 0, L: 0.22, H: 0.56 }
7638
- };
7639
- function roundUp(n) {
7640
- return Math.ceil(n * 10) / 10;
7641
- }
7642
- function computeBaseScore(av, ac, pr, ui, scope, c, i, a) {
7643
- const iss = 1 - (1 - W.CIA[c]) * (1 - W.CIA[i]) * (1 - W.CIA[a]);
7644
- const impact = scope === "U" ? 6.42 * iss : 7.52 * (iss - 0.029) - 3.25 * Math.pow(iss - 0.02, 15);
7645
- const prWeight = (scope === "C" ? W.PR_C : W.PR_U)[pr];
7646
- const exploit = 8.22 * W.AV[av] * W.AC[ac] * prWeight * W.UI[ui];
7647
- if (impact <= 0)
7648
- return 0;
7649
- const base = scope === "U" ? Math.min(impact + exploit, 10) : Math.min(1.08 * (impact + exploit), 10);
7650
- return roundUp(base);
7418
+ return bucket;
7651
7419
  }
7652
- function prForSeverity(severity) {
7653
- switch (severity) {
7654
- case "critical":
7655
- return "N";
7656
- case "high":
7657
- return "L";
7658
- case "medium":
7659
- case "low":
7660
- return "L";
7661
- default:
7662
- return "H";
7420
+ function refill(bucket) {
7421
+ const now = Date.now();
7422
+ const elapsed = now - bucket.lastRefill;
7423
+ if (elapsed > 0) {
7424
+ bucket.tokens = Math.min(bucket.capacity, bucket.tokens + elapsed * bucket.refillRatePerMs);
7425
+ bucket.lastRefill = now;
7663
7426
  }
7664
7427
  }
7665
- function metricsForReachability(tier) {
7666
- switch (tier) {
7667
- case "remote-unauth":
7668
- return { av: "N", pr: "N", ui: "N" };
7669
- case "proximity-rf":
7670
- return { av: "A", pr: "N", ui: "N" };
7671
- case "local-unpriv":
7672
- return { av: "L", pr: "L", ui: "N" };
7673
- case "local-priv":
7674
- return { av: "L", pr: "H", ui: "N" };
7675
- case "needs-hardware":
7676
- return { av: "P", pr: "N", ui: "N" };
7677
- case "needs-host-migration":
7678
- return { av: "L", pr: "N", ui: "R" };
7428
+ async function acquireHostToken(host, rps) {
7429
+ const bucket = getOrInitBucket(host, rps);
7430
+ while (Date.now() < bucket.retryUntil) {
7431
+ const waitMs = bucket.retryUntil - Date.now();
7432
+ await sleep(Math.min(waitMs, 1e3));
7433
+ }
7434
+ while (true) {
7435
+ refill(bucket);
7436
+ if (bucket.tokens >= 1) {
7437
+ bucket.tokens -= 1;
7438
+ return;
7439
+ }
7440
+ const tokensNeeded = 1 - bucket.tokens;
7441
+ const waitMs = Math.max(1, Math.ceil(tokensNeeded / bucket.refillRatePerMs));
7442
+ await sleep(waitMs);
7679
7443
  }
7680
7444
  }
7681
- function suggestCvss(finding) {
7682
- if (finding.cvssVector && finding.cvssScore !== void 0) {
7683
- return { vector: finding.cvssVector, score: finding.cvssScore, source: "finding" };
7684
- }
7685
- const impact = IMPACT_BY_CATEGORY[finding.category] ?? { C: "L", I: "L", A: "L", scope: "U" };
7686
- const ac = "L";
7687
- const assessed = finding.impactAssessment ? metricsForReachability(finding.impactAssessment.reachability_tier) : void 0;
7688
- const av = assessed?.av ?? "N";
7689
- const pr = assessed?.pr ?? prForSeverity(finding.severity);
7690
- const ui = assessed?.ui ?? "N";
7691
- const vector = `CVSS:3.1/AV:${av}/AC:${ac}/PR:${pr}/UI:${ui}/S:${impact.scope}/C:${impact.C}/I:${impact.I}/A:${impact.A}`;
7692
- const score = computeBaseScore(av, ac, pr, ui, impact.scope, impact.C, impact.I, impact.A);
7693
- return { vector, score, source: assessed ? "impact-assessment" : "heuristic" };
7445
+ function markHostRateLimited(host, retryAfterHeader) {
7446
+ const bucket = hostBuckets.get(host);
7447
+ if (!bucket)
7448
+ return;
7449
+ const parsed = retryAfterHeader ? parseInt(retryAfterHeader, 10) : NaN;
7450
+ const retryAfterMs = Number.isFinite(parsed) && parsed > 0 ? parsed * 1e3 : 0;
7451
+ bucket.retryUntil = Date.now() + Math.max(retryAfterMs, 6e4);
7694
7452
  }
7695
- var Cvss4ParseError = class extends Error {
7696
- constructor(message) {
7697
- super(message);
7698
- this.name = "Cvss4ParseError";
7699
- }
7700
- };
7701
- var CVSS4_ALLOWED = {
7702
- AV: /* @__PURE__ */ new Set(["N", "A", "L", "P"]),
7703
- AC: /* @__PURE__ */ new Set(["L", "H"]),
7704
- AT: /* @__PURE__ */ new Set(["N", "P"]),
7705
- PR: /* @__PURE__ */ new Set(["N", "L", "H"]),
7706
- UI: /* @__PURE__ */ new Set(["N", "P", "A"]),
7707
- VC: /* @__PURE__ */ new Set(["H", "L", "N"]),
7708
- VI: /* @__PURE__ */ new Set(["H", "L", "N"]),
7709
- VA: /* @__PURE__ */ new Set(["H", "L", "N"]),
7710
- SC: /* @__PURE__ */ new Set(["H", "L", "N"]),
7711
- SI: /* @__PURE__ */ new Set(["H", "L", "N"]),
7712
- SA: /* @__PURE__ */ new Set(["H", "L", "N"]),
7713
- // Threat
7714
- E: /* @__PURE__ */ new Set(["X", "A", "P", "U"]),
7715
- // Environmental (requirements)
7716
- CR: /* @__PURE__ */ new Set(["X", "H", "M", "L"]),
7717
- IR: /* @__PURE__ */ new Set(["X", "H", "M", "L"]),
7718
- AR: /* @__PURE__ */ new Set(["X", "H", "M", "L"]),
7719
- // Environmental (modified base)
7720
- MAV: /* @__PURE__ */ new Set(["X", "N", "A", "L", "P"]),
7721
- MAC: /* @__PURE__ */ new Set(["X", "L", "H"]),
7722
- MAT: /* @__PURE__ */ new Set(["X", "N", "P"]),
7723
- MPR: /* @__PURE__ */ new Set(["X", "N", "L", "H"]),
7724
- MUI: /* @__PURE__ */ new Set(["X", "N", "P", "A"]),
7725
- MVC: /* @__PURE__ */ new Set(["X", "H", "L", "N"]),
7726
- MVI: /* @__PURE__ */ new Set(["X", "H", "L", "N"]),
7727
- MVA: /* @__PURE__ */ new Set(["X", "H", "L", "N"]),
7728
- MSC: /* @__PURE__ */ new Set(["X", "H", "L", "N"]),
7729
- MSI: /* @__PURE__ */ new Set(["X", "S", "H", "L", "N"]),
7730
- MSA: /* @__PURE__ */ new Set(["X", "S", "H", "L", "N"]),
7731
- // Supplemental (do not affect score)
7732
- S: /* @__PURE__ */ new Set(["X", "N", "P"]),
7733
- AU: /* @__PURE__ */ new Set(["X", "N", "Y"]),
7734
- R: /* @__PURE__ */ new Set(["X", "A", "U", "I"]),
7735
- V: /* @__PURE__ */ new Set(["X", "D", "C"]),
7736
- RE: /* @__PURE__ */ new Set(["X", "L", "M", "H"]),
7737
- U: /* @__PURE__ */ new Set(["X", "Clear", "Green", "Amber", "Red"])
7738
- };
7739
- var CVSS4_BASE_KEYS = [
7740
- "AV",
7741
- "AC",
7742
- "AT",
7743
- "PR",
7744
- "UI",
7745
- "VC",
7746
- "VI",
7747
- "VA",
7748
- "SC",
7749
- "SI",
7750
- "SA"
7751
- ];
7752
- var AV_levels = { N: 0, A: 0.1, L: 0.2, P: 0.3 };
7753
- var PR_levels = { N: 0, L: 0.1, H: 0.2 };
7754
- var UI_levels = { N: 0, P: 0.1, A: 0.2 };
7755
- var AC_levels = { L: 0, H: 0.1 };
7756
- var AT_levels = { N: 0, P: 0.1 };
7757
- var VC_levels = { H: 0, L: 0.1, N: 0.2 };
7758
- var VI_levels = { H: 0, L: 0.1, N: 0.2 };
7759
- var VA_levels = { H: 0, L: 0.1, N: 0.2 };
7760
- var SC_levels = { H: 0.1, L: 0.2, N: 0.3 };
7761
- var SI_levels = { S: 0, H: 0.1, L: 0.2, N: 0.3 };
7762
- var SA_levels = { S: 0, H: 0.1, L: 0.2, N: 0.3 };
7763
- var CR_levels = { H: 0, M: 0.1, L: 0.2 };
7764
- var IR_levels = { H: 0, M: 0.1, L: 0.2 };
7765
- var AR_levels = { H: 0, M: 0.1, L: 0.2 };
7766
- var CVSS40_LOOKUP = {
7767
- "000000": 10,
7768
- "000001": 9.9,
7769
- "000010": 9.8,
7770
- "000011": 9.5,
7771
- "000020": 9.5,
7772
- "000021": 9.2,
7773
- "000100": 10,
7774
- "000101": 9.6,
7775
- "000110": 9.3,
7776
- "000111": 8.7,
7777
- "000120": 9.1,
7778
- "000121": 8.1,
7779
- "000200": 9.3,
7780
- "000201": 9,
7781
- "000210": 8.9,
7782
- "000211": 8,
7783
- "000220": 8.1,
7784
- "000221": 6.8,
7785
- "001000": 9.8,
7786
- "001001": 9.5,
7787
- "001010": 9.5,
7788
- "001011": 9.2,
7789
- "001020": 9,
7790
- "001021": 8.4,
7791
- "001100": 9.3,
7792
- "001101": 9.2,
7793
- "001110": 8.9,
7794
- "001111": 8.1,
7795
- "001120": 8.1,
7796
- "001121": 6.5,
7797
- "001200": 8.8,
7798
- "001201": 8,
7799
- "001210": 7.8,
7800
- "001211": 7,
7801
- "001220": 6.9,
7802
- "001221": 4.8,
7803
- "002001": 9.2,
7804
- "002011": 8.2,
7805
- "002021": 7.2,
7806
- "002101": 7.9,
7807
- "002111": 6.9,
7808
- "002121": 5,
7809
- "002201": 6.9,
7810
- "002211": 5.5,
7811
- "002221": 2.7,
7812
- "010000": 9.9,
7813
- "010001": 9.7,
7814
- "010010": 9.5,
7815
- "010011": 9.2,
7816
- "010020": 9.2,
7817
- "010021": 8.5,
7818
- "010100": 9.5,
7819
- "010101": 9.1,
7820
- "010110": 9,
7821
- "010111": 8.3,
7822
- "010120": 8.4,
7823
- "010121": 7.1,
7824
- "010200": 9.2,
7825
- "010201": 8.1,
7826
- "010210": 8.2,
7827
- "010211": 7.1,
7828
- "010220": 7.2,
7829
- "010221": 5.3,
7830
- "011000": 9.5,
7831
- "011001": 9.3,
7832
- "011010": 9.2,
7833
- "011011": 8.5,
7834
- "011020": 8.5,
7835
- "011021": 7.3,
7836
- "011100": 9.2,
7837
- "011101": 8.2,
7838
- "011110": 8,
7839
- "011111": 7.2,
7840
- "011120": 7,
7841
- "011121": 5.9,
7842
- "011200": 8.4,
7843
- "011201": 7,
7844
- "011210": 7.1,
7845
- "011211": 5.2,
7846
- "011220": 5,
7847
- "011221": 3,
7848
- "012001": 8.6,
7849
- "012011": 7.5,
7850
- "012021": 5.2,
7851
- "012101": 7.1,
7852
- "012111": 5.2,
7853
- "012121": 2.9,
7854
- "012201": 6.3,
7855
- "012211": 2.9,
7856
- "012221": 1.7,
7857
- "100000": 9.8,
7858
- "100001": 9.5,
7859
- "100010": 9.4,
7860
- "100011": 8.7,
7861
- "100020": 9.1,
7862
- "100021": 8.1,
7863
- "100100": 9.4,
7864
- "100101": 8.9,
7865
- "100110": 8.6,
7866
- "100111": 7.4,
7867
- "100120": 7.7,
7868
- "100121": 6.4,
7869
- "100200": 8.7,
7870
- "100201": 7.5,
7871
- "100210": 7.4,
7872
- "100211": 6.3,
7873
- "100220": 6.3,
7874
- "100221": 4.9,
7875
- "101000": 9.4,
7876
- "101001": 8.9,
7877
- "101010": 8.8,
7878
- "101011": 7.7,
7879
- "101020": 7.6,
7880
- "101021": 6.7,
7881
- "101100": 8.6,
7882
- "101101": 7.6,
7883
- "101110": 7.4,
7884
- "101111": 5.8,
7885
- "101120": 5.9,
7886
- "101121": 5,
7887
- "101200": 7.2,
7888
- "101201": 5.7,
7889
- "101210": 5.7,
7890
- "101211": 5.2,
7891
- "101220": 5.2,
7892
- "101221": 2.5,
7893
- "102001": 8.3,
7894
- "102011": 7,
7895
- "102021": 5.4,
7896
- "102101": 6.5,
7897
- "102111": 5.8,
7898
- "102121": 2.6,
7899
- "102201": 5.3,
7900
- "102211": 2.1,
7901
- "102221": 1.3,
7902
- "110000": 9.5,
7903
- "110001": 9,
7904
- "110010": 8.8,
7905
- "110011": 7.6,
7906
- "110020": 7.6,
7907
- "110021": 7,
7908
- "110100": 9,
7909
- "110101": 7.7,
7910
- "110110": 7.5,
7911
- "110111": 6.2,
7912
- "110120": 6.1,
7913
- "110121": 5.3,
7914
- "110200": 7.7,
7915
- "110201": 6.6,
7916
- "110210": 6.8,
7917
- "110211": 5.9,
7918
- "110220": 5.2,
7919
- "110221": 3,
7920
- "111000": 8.9,
7921
- "111001": 7.8,
7922
- "111010": 7.6,
7923
- "111011": 6.7,
7924
- "111020": 6.2,
7925
- "111021": 5.8,
7926
- "111100": 7.4,
7927
- "111101": 5.9,
7928
- "111110": 5.7,
7929
- "111111": 5.7,
7930
- "111120": 4.7,
7931
- "111121": 2.3,
7932
- "111200": 6.1,
7933
- "111201": 5.2,
7934
- "111210": 5.7,
7935
- "111211": 2.9,
7936
- "111220": 2.4,
7937
- "111221": 1.6,
7938
- "112001": 7.1,
7939
- "112011": 5.9,
7940
- "112021": 3,
7941
- "112101": 5.8,
7942
- "112111": 2.6,
7943
- "112121": 1.5,
7944
- "112201": 2.3,
7945
- "112211": 1.3,
7946
- "112221": 0.6,
7947
- "200000": 9.3,
7948
- "200001": 8.7,
7949
- "200010": 8.6,
7950
- "200011": 7.2,
7951
- "200020": 7.5,
7952
- "200021": 5.8,
7953
- "200100": 8.6,
7954
- "200101": 7.4,
7955
- "200110": 7.4,
7956
- "200111": 6.1,
7957
- "200120": 5.6,
7958
- "200121": 3.4,
7959
- "200200": 7,
7960
- "200201": 5.4,
7961
- "200210": 5.2,
7962
- "200211": 4,
7963
- "200220": 4,
7964
- "200221": 2.2,
7965
- "201000": 8.5,
7966
- "201001": 7.5,
7967
- "201010": 7.4,
7968
- "201011": 5.5,
7969
- "201020": 6.2,
7970
- "201021": 5.1,
7971
- "201100": 7.2,
7972
- "201101": 5.7,
7973
- "201110": 5.5,
7974
- "201111": 4.1,
7975
- "201120": 4.6,
7976
- "201121": 1.9,
7977
- "201200": 5.3,
7978
- "201201": 3.6,
7979
- "201210": 3.4,
7980
- "201211": 1.9,
7981
- "201220": 1.9,
7982
- "201221": 0.8,
7983
- "202001": 6.4,
7984
- "202011": 5.1,
7985
- "202021": 2,
7986
- "202101": 4.7,
7987
- "202111": 2.1,
7988
- "202121": 1.1,
7989
- "202201": 2.4,
7990
- "202211": 0.9,
7991
- "202221": 0.4,
7992
- "210000": 8.8,
7993
- "210001": 7.5,
7994
- "210010": 7.3,
7995
- "210011": 5.3,
7996
- "210020": 6,
7997
- "210021": 5,
7998
- "210100": 7.3,
7999
- "210101": 5.5,
8000
- "210110": 5.9,
8001
- "210111": 4,
8002
- "210120": 4.1,
8003
- "210121": 2,
8004
- "210200": 5.4,
8005
- "210201": 4.3,
8006
- "210210": 4.5,
8007
- "210211": 2.2,
8008
- "210220": 2,
8009
- "210221": 1.1,
8010
- "211000": 7.5,
8011
- "211001": 5.5,
8012
- "211010": 5.8,
8013
- "211011": 4.5,
8014
- "211020": 4,
8015
- "211021": 2.1,
8016
- "211100": 6.1,
8017
- "211101": 5.1,
8018
- "211110": 4.8,
8019
- "211111": 1.8,
8020
- "211120": 2,
8021
- "211121": 0.9,
8022
- "211200": 4.6,
8023
- "211201": 1.8,
8024
- "211210": 1.7,
8025
- "211211": 0.7,
8026
- "211220": 0.8,
8027
- "211221": 0.2,
8028
- "212001": 5.3,
8029
- "212011": 2.4,
8030
- "212021": 1.4,
8031
- "212101": 2.4,
8032
- "212111": 1.2,
8033
- "212121": 0.5,
8034
- "212201": 1,
8035
- "212211": 0.3,
8036
- "212221": 0.1
8037
- };
8038
- var CVSS40_MAX_COMPOSED = {
8039
- eq1: {
8040
- 0: ["AV:N/PR:N/UI:N/"],
8041
- 1: ["AV:A/PR:N/UI:N/", "AV:N/PR:L/UI:N/", "AV:N/PR:N/UI:P/"],
8042
- 2: ["AV:P/PR:N/UI:N/", "AV:A/PR:L/UI:P/"]
8043
- },
8044
- eq2: {
8045
- 0: ["AC:L/AT:N/"],
8046
- 1: ["AC:H/AT:N/", "AC:L/AT:P/"]
8047
- },
8048
- eq3: {
8049
- 0: { "0": ["VC:H/VI:H/VA:H/CR:H/IR:H/AR:H/"], "1": ["VC:H/VI:H/VA:L/CR:M/IR:M/AR:H/", "VC:H/VI:H/VA:H/CR:M/IR:M/AR:M/"] },
8050
- 1: { "0": ["VC:L/VI:H/VA:H/CR:H/IR:H/AR:H/", "VC:H/VI:L/VA:H/CR:H/IR:H/AR:H/"], "1": ["VC:L/VI:H/VA:L/CR:H/IR:M/AR:H/", "VC:L/VI:H/VA:H/CR:H/IR:M/AR:M/", "VC:H/VI:L/VA:H/CR:M/IR:H/AR:M/", "VC:H/VI:L/VA:L/CR:M/IR:H/AR:H/", "VC:L/VI:L/VA:H/CR:H/IR:H/AR:M/"] },
8051
- 2: { "1": ["VC:L/VI:L/VA:L/CR:H/IR:H/AR:H/"] }
8052
- },
8053
- eq4: {
8054
- 0: ["SC:H/SI:S/SA:S/"],
8055
- 1: ["SC:H/SI:H/SA:H/"],
8056
- 2: ["SC:L/SI:L/SA:L/"]
8057
- },
8058
- eq5: {
8059
- 0: ["E:A/"],
8060
- 1: ["E:P/"],
8061
- 2: ["E:U/"]
8062
- }
8063
- };
8064
- var CVSS40_MAX_SEVERITY = {
8065
- eq1: { 0: 1, 1: 4, 2: 5 },
8066
- eq2: { 0: 1, 1: 2 },
8067
- eq3eq6: { 0: { 0: 7, 1: 6 }, 1: { 0: 8, 1: 8 }, 2: { 1: 10 } },
8068
- eq4: { 0: 6, 1: 5, 2: 4 },
8069
- eq5: { 0: 1, 1: 1, 2: 1 }
8070
- };
8071
- function m4(sel, metric) {
8072
- const selected = sel[metric];
8073
- if (metric === "E" && (selected === void 0 || selected === "X"))
8074
- return "A";
8075
- if ((metric === "CR" || metric === "IR" || metric === "AR") && (selected === void 0 || selected === "X")) {
8076
- return "H";
8077
- }
8078
- const modified = sel["M" + metric];
8079
- if (modified !== void 0 && modified !== "X")
8080
- return modified;
8081
- return selected ?? "";
7453
+ function sleep(ms) {
7454
+ return new Promise((r) => setTimeout(r, ms));
8082
7455
  }
8083
- function cvss4MacroVector(sel) {
8084
- let eq1;
8085
- if (m4(sel, "AV") === "N" && m4(sel, "PR") === "N" && m4(sel, "UI") === "N") {
8086
- eq1 = "0";
8087
- } else if ((m4(sel, "AV") === "N" || m4(sel, "PR") === "N" || m4(sel, "UI") === "N") && !(m4(sel, "AV") === "N" && m4(sel, "PR") === "N" && m4(sel, "UI") === "N") && m4(sel, "AV") !== "P") {
8088
- eq1 = "1";
8089
- } else {
8090
- eq1 = "2";
8091
- }
8092
- const eq2 = m4(sel, "AC") === "L" && m4(sel, "AT") === "N" ? "0" : "1";
8093
- let eq3;
8094
- if (m4(sel, "VC") === "H" && m4(sel, "VI") === "H") {
8095
- eq3 = "0";
8096
- } else if (!(m4(sel, "VC") === "H" && m4(sel, "VI") === "H") && (m4(sel, "VC") === "H" || m4(sel, "VI") === "H" || m4(sel, "VA") === "H")) {
8097
- eq3 = "1";
8098
- } else {
8099
- eq3 = "2";
8100
- }
8101
- let eq4;
8102
- if (m4(sel, "MSI") === "S" || m4(sel, "MSA") === "S") {
8103
- eq4 = "0";
8104
- } else if (m4(sel, "SC") === "H" || m4(sel, "SI") === "H" || m4(sel, "SA") === "H") {
8105
- eq4 = "1";
8106
- } else {
8107
- eq4 = "2";
8108
- }
8109
- let eq5;
8110
- if (m4(sel, "E") === "A")
8111
- eq5 = "0";
8112
- else if (m4(sel, "E") === "P")
8113
- eq5 = "1";
8114
- else
8115
- eq5 = "2";
8116
- const eq6 = m4(sel, "CR") === "H" && m4(sel, "VC") === "H" || m4(sel, "IR") === "H" && m4(sel, "VI") === "H" || m4(sel, "AR") === "H" && m4(sel, "VA") === "H" ? "0" : "1";
8117
- return eq1 + eq2 + eq3 + eq4 + eq5 + eq6;
8118
- }
8119
- function cvss4EqMaxes(macro, eq) {
8120
- const idx = Number(macro[eq - 1]);
8121
- if (eq === 1)
8122
- return CVSS40_MAX_COMPOSED.eq1[idx];
8123
- if (eq === 2)
8124
- return CVSS40_MAX_COMPOSED.eq2[idx];
8125
- if (eq === 4)
8126
- return CVSS40_MAX_COMPOSED.eq4[idx];
8127
- return CVSS40_MAX_COMPOSED.eq5[idx];
8128
- }
8129
- function extractValueMetric(metric, str) {
8130
- const start = str.indexOf(metric) + metric.length + 1;
8131
- const extracted = str.slice(start);
8132
- const slash = extracted.indexOf("/");
8133
- return slash > 0 ? extracted.substring(0, slash) : extracted;
7456
+ function normalizeHostForMatch(value) {
7457
+ const trimmed = value.trim().toLowerCase();
7458
+ if (trimmed.startsWith("[")) {
7459
+ const end = trimmed.indexOf("]");
7460
+ return end === -1 ? trimmed : trimmed.slice(1, end);
7461
+ }
7462
+ if ((trimmed.match(/:/g) ?? []).length >= 2)
7463
+ return trimmed;
7464
+ return trimmed.replace(/:\d+$/, "");
8134
7465
  }
8135
- function computeCvss4BaseScore(sel) {
8136
- if (["VC", "VI", "VA", "SC", "SI", "SA"].every((metric) => m4(sel, metric) === "N")) {
8137
- return 0;
8138
- }
8139
- const macroVectorResult = cvss4MacroVector(sel);
8140
- let value = CVSS40_LOOKUP[macroVectorResult];
8141
- const eq1 = parseInt(macroVectorResult[0], 10);
8142
- const eq2 = parseInt(macroVectorResult[1], 10);
8143
- const eq3 = parseInt(macroVectorResult[2], 10);
8144
- const eq4 = parseInt(macroVectorResult[3], 10);
8145
- const eq5 = parseInt(macroVectorResult[4], 10);
8146
- const eq6 = parseInt(macroVectorResult[5], 10);
8147
- const eq1_next_lower_macro = `${eq1 + 1}${eq2}${eq3}${eq4}${eq5}${eq6}`;
8148
- const eq2_next_lower_macro = `${eq1}${eq2 + 1}${eq3}${eq4}${eq5}${eq6}`;
8149
- let eq3eq6_next_lower_macro = "";
8150
- let eq3eq6_next_lower_macro_left = "";
8151
- let eq3eq6_next_lower_macro_right = "";
8152
- if (eq3 === 1 && eq6 === 1) {
8153
- eq3eq6_next_lower_macro = `${eq1}${eq2}${eq3 + 1}${eq4}${eq5}${eq6}`;
8154
- } else if (eq3 === 0 && eq6 === 1) {
8155
- eq3eq6_next_lower_macro = `${eq1}${eq2}${eq3 + 1}${eq4}${eq5}${eq6}`;
8156
- } else if (eq3 === 1 && eq6 === 0) {
8157
- eq3eq6_next_lower_macro = `${eq1}${eq2}${eq3}${eq4}${eq5}${eq6 + 1}`;
8158
- } else if (eq3 === 0 && eq6 === 0) {
8159
- eq3eq6_next_lower_macro_left = `${eq1}${eq2}${eq3}${eq4}${eq5}${eq6 + 1}`;
8160
- eq3eq6_next_lower_macro_right = `${eq1}${eq2}${eq3 + 1}${eq4}${eq5}${eq6}`;
8161
- } else {
8162
- eq3eq6_next_lower_macro = `${eq1}${eq2}${eq3 + 1}${eq4}${eq5}${eq6 + 1}`;
8163
- }
8164
- const eq4_next_lower_macro = `${eq1}${eq2}${eq3}${eq4 + 1}${eq5}${eq6}`;
8165
- const eq5_next_lower_macro = `${eq1}${eq2}${eq3}${eq4}${eq5 + 1}${eq6}`;
8166
- const score_eq1_next_lower_macro = CVSS40_LOOKUP[eq1_next_lower_macro];
8167
- const score_eq2_next_lower_macro = CVSS40_LOOKUP[eq2_next_lower_macro];
8168
- let score_eq3eq6_next_lower_macro;
8169
- if (eq3 === 0 && eq6 === 0) {
8170
- const left = CVSS40_LOOKUP[eq3eq6_next_lower_macro_left];
8171
- const right = CVSS40_LOOKUP[eq3eq6_next_lower_macro_right];
8172
- score_eq3eq6_next_lower_macro = left > right ? left : right;
8173
- } else {
8174
- score_eq3eq6_next_lower_macro = CVSS40_LOOKUP[eq3eq6_next_lower_macro];
8175
- }
8176
- const score_eq4_next_lower_macro = CVSS40_LOOKUP[eq4_next_lower_macro];
8177
- const score_eq5_next_lower_macro = CVSS40_LOOKUP[eq5_next_lower_macro];
8178
- const eq1_maxes = cvss4EqMaxes(macroVectorResult, 1);
8179
- const eq2_maxes = cvss4EqMaxes(macroVectorResult, 2);
8180
- const eq3_eq6_maxes = CVSS40_MAX_COMPOSED.eq3[eq3][macroVectorResult[5]];
8181
- const eq4_maxes = cvss4EqMaxes(macroVectorResult, 4);
8182
- const eq5_maxes = cvss4EqMaxes(macroVectorResult, 5);
8183
- const max_vectors = [];
8184
- for (const a of eq1_maxes)
8185
- for (const b of eq2_maxes)
8186
- for (const c of eq3_eq6_maxes)
8187
- for (const d of eq4_maxes)
8188
- for (const e of eq5_maxes)
8189
- max_vectors.push(a + b + c + d + e);
8190
- let severity_distance_AV = 0, severity_distance_PR = 0, severity_distance_UI = 0;
8191
- let severity_distance_AC = 0, severity_distance_AT = 0;
8192
- let severity_distance_VC = 0, severity_distance_VI = 0, severity_distance_VA = 0;
8193
- let severity_distance_SC = 0, severity_distance_SI = 0, severity_distance_SA = 0;
8194
- let severity_distance_CR = 0, severity_distance_IR = 0, severity_distance_AR = 0;
8195
- for (const max_vector of max_vectors) {
8196
- severity_distance_AV = AV_levels[m4(sel, "AV")] - AV_levels[extractValueMetric("AV", max_vector)];
8197
- severity_distance_PR = PR_levels[m4(sel, "PR")] - PR_levels[extractValueMetric("PR", max_vector)];
8198
- severity_distance_UI = UI_levels[m4(sel, "UI")] - UI_levels[extractValueMetric("UI", max_vector)];
8199
- severity_distance_AC = AC_levels[m4(sel, "AC")] - AC_levels[extractValueMetric("AC", max_vector)];
8200
- severity_distance_AT = AT_levels[m4(sel, "AT")] - AT_levels[extractValueMetric("AT", max_vector)];
8201
- severity_distance_VC = VC_levels[m4(sel, "VC")] - VC_levels[extractValueMetric("VC", max_vector)];
8202
- severity_distance_VI = VI_levels[m4(sel, "VI")] - VI_levels[extractValueMetric("VI", max_vector)];
8203
- severity_distance_VA = VA_levels[m4(sel, "VA")] - VA_levels[extractValueMetric("VA", max_vector)];
8204
- severity_distance_SC = SC_levels[m4(sel, "SC")] - SC_levels[extractValueMetric("SC", max_vector)];
8205
- severity_distance_SI = SI_levels[m4(sel, "SI")] - SI_levels[extractValueMetric("SI", max_vector)];
8206
- severity_distance_SA = SA_levels[m4(sel, "SA")] - SA_levels[extractValueMetric("SA", max_vector)];
8207
- severity_distance_CR = CR_levels[m4(sel, "CR")] - CR_levels[extractValueMetric("CR", max_vector)];
8208
- severity_distance_IR = IR_levels[m4(sel, "IR")] - IR_levels[extractValueMetric("IR", max_vector)];
8209
- severity_distance_AR = AR_levels[m4(sel, "AR")] - AR_levels[extractValueMetric("AR", max_vector)];
8210
- const anyNegative = [
8211
- severity_distance_AV,
8212
- severity_distance_PR,
8213
- severity_distance_UI,
8214
- severity_distance_AC,
8215
- severity_distance_AT,
8216
- severity_distance_VC,
8217
- severity_distance_VI,
8218
- severity_distance_VA,
8219
- severity_distance_SC,
8220
- severity_distance_SI,
8221
- severity_distance_SA,
8222
- severity_distance_CR,
8223
- severity_distance_IR,
8224
- severity_distance_AR
8225
- ].some((v) => v < 0);
8226
- if (anyNegative)
7466
+ function hostMatchesAllowlist(host, allowlist) {
7467
+ if (!allowlist || allowlist.length === 0)
7468
+ return true;
7469
+ const target = normalizeHostForMatch(host);
7470
+ for (const raw of allowlist) {
7471
+ const pattern = normalizeHostForMatch(raw);
7472
+ if (!pattern)
8227
7473
  continue;
8228
- break;
8229
- }
8230
- const current_severity_distance_eq1 = severity_distance_AV + severity_distance_PR + severity_distance_UI;
8231
- const current_severity_distance_eq2 = severity_distance_AC + severity_distance_AT;
8232
- const current_severity_distance_eq3eq6 = severity_distance_VC + severity_distance_VI + severity_distance_VA + severity_distance_CR + severity_distance_IR + severity_distance_AR;
8233
- const current_severity_distance_eq4 = severity_distance_SC + severity_distance_SI + severity_distance_SA;
8234
- const step = 0.1;
8235
- const available_distance_eq1 = value - score_eq1_next_lower_macro;
8236
- const available_distance_eq2 = value - score_eq2_next_lower_macro;
8237
- const available_distance_eq3eq6 = value - score_eq3eq6_next_lower_macro;
8238
- const available_distance_eq4 = value - score_eq4_next_lower_macro;
8239
- const available_distance_eq5 = value - score_eq5_next_lower_macro;
8240
- let n_existing_lower = 0;
8241
- let normalized_severity_eq1 = 0;
8242
- let normalized_severity_eq2 = 0;
8243
- let normalized_severity_eq3eq6 = 0;
8244
- let normalized_severity_eq4 = 0;
8245
- let normalized_severity_eq5 = 0;
8246
- const maxSeverity_eq1 = CVSS40_MAX_SEVERITY.eq1[eq1] * step;
8247
- const maxSeverity_eq2 = CVSS40_MAX_SEVERITY.eq2[eq2] * step;
8248
- const maxSeverity_eq3eq6 = CVSS40_MAX_SEVERITY.eq3eq6[eq3][eq6] * step;
8249
- const maxSeverity_eq4 = CVSS40_MAX_SEVERITY.eq4[eq4] * step;
8250
- if (!Number.isNaN(available_distance_eq1)) {
8251
- n_existing_lower += 1;
8252
- normalized_severity_eq1 = available_distance_eq1 * (current_severity_distance_eq1 / maxSeverity_eq1);
8253
- }
8254
- if (!Number.isNaN(available_distance_eq2)) {
8255
- n_existing_lower += 1;
8256
- normalized_severity_eq2 = available_distance_eq2 * (current_severity_distance_eq2 / maxSeverity_eq2);
8257
- }
8258
- if (!Number.isNaN(available_distance_eq3eq6)) {
8259
- n_existing_lower += 1;
8260
- normalized_severity_eq3eq6 = available_distance_eq3eq6 * (current_severity_distance_eq3eq6 / maxSeverity_eq3eq6);
8261
- }
8262
- if (!Number.isNaN(available_distance_eq4)) {
8263
- n_existing_lower += 1;
8264
- normalized_severity_eq4 = available_distance_eq4 * (current_severity_distance_eq4 / maxSeverity_eq4);
8265
- }
8266
- if (!Number.isNaN(available_distance_eq5)) {
8267
- n_existing_lower += 1;
8268
- normalized_severity_eq5 = available_distance_eq5 * 0;
8269
- }
8270
- let mean_distance;
8271
- if (n_existing_lower === 0) {
8272
- mean_distance = 0;
8273
- } else {
8274
- mean_distance = (normalized_severity_eq1 + normalized_severity_eq2 + normalized_severity_eq3eq6 + normalized_severity_eq4 + normalized_severity_eq5) / n_existing_lower;
8275
- }
8276
- value -= mean_distance;
8277
- if (value < 0)
8278
- value = 0;
8279
- if (value > 10)
8280
- value = 10;
8281
- return Math.round(value * 10) / 10;
8282
- }
8283
- function cvss4Severity(score) {
8284
- if (score <= 0)
8285
- return "None";
8286
- if (score < 4)
8287
- return "Low";
8288
- if (score < 7)
8289
- return "Medium";
8290
- if (score < 9)
8291
- return "High";
8292
- return "Critical";
8293
- }
8294
- var CVSS4_METRIC_ORDER = [
8295
- "AV",
8296
- "AC",
8297
- "AT",
8298
- "PR",
8299
- "UI",
8300
- "VC",
8301
- "VI",
8302
- "VA",
8303
- "SC",
8304
- "SI",
8305
- "SA",
8306
- "E",
8307
- "CR",
8308
- "IR",
8309
- "AR",
8310
- "MAV",
8311
- "MAC",
8312
- "MAT",
8313
- "MPR",
8314
- "MUI",
8315
- "MVC",
8316
- "MVI",
8317
- "MVA",
8318
- "MSC",
8319
- "MSI",
8320
- "MSA",
8321
- "S",
8322
- "AU",
8323
- "R",
8324
- "V",
8325
- "RE",
8326
- "U"
8327
- ];
8328
- function parseCvss4Vector(vector) {
8329
- const trimmed = vector.trim();
8330
- if (!trimmed.startsWith("CVSS:4.0/")) {
8331
- throw new Cvss4ParseError(`Not a CVSS 4.0 vector (must start with "CVSS:4.0/"): ${vector}`);
8332
- }
8333
- const body = trimmed.slice("CVSS:4.0/".length);
8334
- const parts = body.split("/").filter((p) => p.length > 0);
8335
- if (parts.length === 0) {
8336
- throw new Cvss4ParseError(`CVSS 4.0 vector has no metrics: ${vector}`);
8337
- }
8338
- const sel = {};
8339
- for (const part of parts) {
8340
- const eq = part.indexOf(":");
8341
- if (eq < 0)
8342
- throw new Cvss4ParseError(`Malformed metric segment "${part}" in ${vector}`);
8343
- const key = part.slice(0, eq);
8344
- const val = part.slice(eq + 1);
8345
- const allowed = CVSS4_ALLOWED[key];
8346
- if (!allowed)
8347
- throw new Cvss4ParseError(`Unknown CVSS 4.0 metric "${key}" in ${vector}`);
8348
- if (!allowed.has(val)) {
8349
- throw new Cvss4ParseError(`Illegal value "${val}" for metric "${key}" in ${vector}`);
8350
- }
8351
- if (key in sel)
8352
- throw new Cvss4ParseError(`Duplicate metric "${key}" in ${vector}`);
8353
- sel[key] = val;
8354
- }
8355
- for (const base of CVSS4_BASE_KEYS) {
8356
- if (!(base in sel)) {
8357
- throw new Cvss4ParseError(`Missing mandatory base metric "${base}" in ${vector}`);
7474
+ if (pattern.startsWith("*.")) {
7475
+ const suffix = pattern.slice(1);
7476
+ if (target.endsWith(suffix) && target.length > suffix.length)
7477
+ return true;
7478
+ } else if (target === pattern) {
7479
+ return true;
8358
7480
  }
8359
7481
  }
8360
- return sel;
7482
+ return false;
8361
7483
  }
8362
- function formatCvss4Vector(sel) {
8363
- const segs = [];
8364
- for (const key of CVSS4_METRIC_ORDER) {
8365
- const v = sel[key];
8366
- if (v !== void 0 && v !== "X")
8367
- segs.push(`${key}:${v}`);
8368
- }
8369
- return `CVSS:4.0/${segs.join("/")}`;
8370
- }
8371
- function scoreCvss4Vector(vector) {
8372
- const sel = parseCvss4Vector(vector);
8373
- const score = computeCvss4BaseScore(sel);
7484
+ function scopeRequiredResult(step, target, start) {
7485
+ if (target.scopeAllowlist && target.scopeAllowlist.length > 0)
7486
+ return void 0;
8374
7487
  return {
8375
- vector: formatCvss4Vector(sel),
8376
- score,
8377
- severity: cvss4Severity(score),
8378
- macroVector: cvss4MacroVector(sel)
7488
+ stepId: step.id,
7489
+ kind: "errored",
7490
+ durationMs: Date.now() - start,
7491
+ error: "PoC reverify requires a non-empty scope allowlist"
8379
7492
  };
8380
7493
  }
8381
- function cvss4MetricsForReachability(tier) {
8382
- switch (tier) {
8383
- case "remote-unauth":
8384
- return { AV: "N", AT: "N", PR: "N", UI: "N" };
8385
- case "proximity-rf":
8386
- return { AV: "A", AT: "N", PR: "N", UI: "N" };
8387
- case "local-unpriv":
8388
- return { AV: "L", AT: "N", PR: "L", UI: "N" };
8389
- case "local-priv":
8390
- return { AV: "L", AT: "N", PR: "H", UI: "N" };
8391
- case "needs-hardware":
8392
- return { AV: "P", AT: "N", PR: "N", UI: "N" };
8393
- case "needs-host-migration":
8394
- return { AV: "L", AT: "N", PR: "N", UI: "A" };
8395
- }
7494
+ function extractUrlsFromShellCommand(cmd) {
7495
+ const matches = cmd.match(/https?:\/\/[^\s'"]+/g);
7496
+ return matches ?? [];
7497
+ }
7498
+ function dockerRegistryHost(image) {
7499
+ const separator = image.indexOf("/");
7500
+ if (separator === -1)
7501
+ return void 0;
7502
+ const firstSegment = image.slice(0, separator);
7503
+ return firstSegment.includes(".") || firstSegment.includes(":") || firstSegment === "localhost" ? firstSegment : void 0;
8396
7504
  }
8397
- function suggestCvss4(finding) {
8398
- const impact = IMPACT_BY_CATEGORY[finding.category] ?? { C: "L", I: "L", A: "L", scope: "U" };
8399
- const assessed = finding.impactAssessment ? cvss4MetricsForReachability(finding.impactAssessment.reachability_tier) : void 0;
8400
- const AV = assessed?.AV ?? "N";
8401
- const AT = assessed?.AT ?? "N";
8402
- const pr31 = assessed ? assessed.PR : prForSeverity(finding.severity);
8403
- const UI = assessed?.UI ?? "N";
8404
- const subsequent = impact.scope === "C";
8405
- const sel = {
8406
- AV,
8407
- AC: "L",
8408
- AT,
8409
- PR: pr31,
8410
- UI,
8411
- VC: impact.C,
8412
- VI: impact.I,
8413
- VA: impact.A,
8414
- SC: subsequent ? impact.C : "N",
8415
- SI: subsequent ? impact.I : "N",
8416
- SA: subsequent ? impact.A : "N"
7505
+ var deps = { spawn, fetch: globalThis.fetch };
7506
+ function setRuntimeDeps(overrides) {
7507
+ const previous = deps;
7508
+ deps = { ...previous, ...overrides };
7509
+ return () => {
7510
+ deps = previous;
8417
7511
  };
8418
- const score = computeCvss4BaseScore(sel);
7512
+ }
7513
+ async function executePocSteps(finding, target) {
7514
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
7515
+ const steps = [];
7516
+ const graph = finding.pocSteps ?? [];
7517
+ for (const step of graph) {
7518
+ const result = await executeStep(step, target);
7519
+ steps.push(result);
7520
+ if (result.kind === "errored" && step.kind !== "verify") {
7521
+ for (let i = graph.indexOf(step) + 1; i < graph.length; i++) {
7522
+ steps.push({
7523
+ stepId: graph[i].id,
7524
+ kind: "skipped",
7525
+ durationMs: 0,
7526
+ error: "skipped: an earlier step errored"
7527
+ });
7528
+ }
7529
+ break;
7530
+ }
7531
+ }
7532
+ const endedAt = (/* @__PURE__ */ new Date()).toISOString();
8419
7533
  return {
8420
- vector: formatCvss4Vector(sel),
8421
- score,
8422
- severity: cvss4Severity(score),
8423
- source: assessed ? "impact-assessment" : "heuristic"
7534
+ findingId: finding.id,
7535
+ startedAt,
7536
+ endedAt,
7537
+ steps,
7538
+ overallVerdict: aggregateVerdict(graph, steps)
8424
7539
  };
8425
7540
  }
8426
- function renderCvssSection(opts) {
8427
- const version = opts.vector.startsWith("CVSS:4.0/") ? "4.0" : opts.vector.startsWith("CVSS:3.1/") ? "3.1" : opts.vector.startsWith("CVSS:3.0/") ? "3.0" : void 0;
8428
- const label = version ? `CVSS ${version}` : "CVSS";
8429
- const rating = opts.severity ? ` (${opts.severity})` : "";
8430
- return `**${label}: ${opts.score.toFixed(1)}${rating}** \u2014 \`${opts.vector}\``;
8431
- }
8432
-
8433
- // packages/core/dist/disclose/canary.js
8434
- import { execFileSync } from "node:child_process";
8435
- import { existsSync, readFileSync } from "node:fs";
8436
- import { resolve, join } from "node:path";
8437
- function extractFileRefs(finding) {
8438
- const haystack = [
8439
- finding.description,
8440
- finding.evidence?.analysis,
8441
- finding.evidence?.request,
8442
- finding.evidence?.response
8443
- ].filter((s) => typeof s === "string" && s.length > 0).join("\n\n");
8444
- const seen = /* @__PURE__ */ new Map();
8445
- const regex = /(?<![\w/\-:])([a-zA-Z0-9_./\-]+\.(?:ts|tsx|js|jsx|mjs|cjs|py|rb|go|rs|c|h|cc|cpp|java|kt|swift|php|sh|sql))(?::(\d+)(?:-\d+)?)?/g;
8446
- let match;
8447
- while ((match = regex.exec(haystack)) !== null) {
8448
- const file = match[1];
8449
- const line = match[2] ? Number(match[2]) : void 0;
8450
- if (file.startsWith("http:") || file.startsWith("https:"))
8451
- continue;
8452
- const key = `${file}:${line ?? ""}`;
8453
- if (!seen.has(key))
8454
- seen.set(key, { file, line });
7541
+ async function executeStep(step, target) {
7542
+ const start = Date.now();
7543
+ if (target.allowProcessActions === false && (step.action.type === "shell" || step.action.type === "docker")) {
7544
+ return {
7545
+ stepId: step.id,
7546
+ kind: "errored",
7547
+ durationMs: Date.now() - start,
7548
+ error: `PoC ${step.action.type} actions require an isolated execution environment`
7549
+ };
8455
7550
  }
8456
- return Array.from(seen.values());
8457
- }
8458
- function gitCmd(repoPath, args) {
8459
7551
  try {
8460
- return execFileSync("git", args, { cwd: repoPath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf8" });
8461
- } catch {
8462
- return null;
7552
+ switch (step.action.type) {
7553
+ case "shell":
7554
+ return await runShellStep(step, step.action, target, start);
7555
+ case "http":
7556
+ return await runHttpStep(step, step.action, target, start);
7557
+ case "docker":
7558
+ return await runDockerStep(step, step.action, target, start);
7559
+ case "note":
7560
+ return {
7561
+ stepId: step.id,
7562
+ kind: "skipped",
7563
+ durationMs: Date.now() - start
7564
+ };
7565
+ default: {
7566
+ const _exhaustive = step.action;
7567
+ return {
7568
+ stepId: step.id,
7569
+ kind: "errored",
7570
+ durationMs: Date.now() - start,
7571
+ error: `unknown action type: ${JSON.stringify(_exhaustive)}`
7572
+ };
7573
+ }
7574
+ }
7575
+ } catch (err) {
7576
+ return {
7577
+ stepId: step.id,
7578
+ kind: "errored",
7579
+ durationMs: Date.now() - start,
7580
+ error: errMessage(err)
7581
+ };
8463
7582
  }
8464
7583
  }
8465
- function verifyAgainstRef(finding, options) {
8466
- const refs = extractFileRefs(finding);
8467
- const repoPath = resolve(options.repoPath);
8468
- if (options.checkout && options.ref) {
8469
- gitCmd(repoPath, ["checkout", "-q", options.ref]);
7584
+ async function runShellStep(step, action, target, start) {
7585
+ const scopeError = scopeRequiredResult(step, target, start);
7586
+ if (scopeError)
7587
+ return scopeError;
7588
+ if (target.scopeAllowlist && target.scopeAllowlist.length > 0) {
7589
+ for (const u of extractUrlsFromShellCommand(action.cmd)) {
7590
+ let host;
7591
+ try {
7592
+ host = new URL(u).host;
7593
+ } catch {
7594
+ continue;
7595
+ }
7596
+ if (!hostMatchesAllowlist(host, target.scopeAllowlist)) {
7597
+ return {
7598
+ stepId: step.id,
7599
+ kind: "errored",
7600
+ durationMs: Date.now() - start,
7601
+ error: `out-of-scope url in shell cmd: ${u} (allowlist: ${target.scopeAllowlist.join(", ")})`
7602
+ };
7603
+ }
7604
+ }
8470
7605
  }
8471
- const currentRef = options.ref ?? gitCmd(repoPath, ["rev-parse", "--abbrev-ref", "HEAD"])?.trim() ?? gitCmd(repoPath, ["rev-parse", "--short", "HEAD"])?.trim() ?? "HEAD";
8472
- if (refs.length === 0) {
7606
+ const env = { ...process.env, ...target.env ?? {} };
7607
+ const cwd = action.cwd ?? target.cwd;
7608
+ const timeoutMs = target.timeoutMs ?? DEFAULT_STEP_TIMEOUT_MS;
7609
+ const spawned = await spawnAndCapture("/bin/sh", ["-c", action.cmd], { env, cwd, timeoutMs });
7610
+ return finaliseProcessStep(step, spawned, start);
7611
+ }
7612
+ async function runDockerStep(step, action, target, start) {
7613
+ const scopeError = scopeRequiredResult(step, target, start);
7614
+ if (scopeError)
7615
+ return scopeError;
7616
+ const registryHost = dockerRegistryHost(action.image);
7617
+ if (registryHost && !hostMatchesAllowlist(registryHost, target.scopeAllowlist)) {
8473
7618
  return {
8474
- status: "unknown",
8475
- ref: currentRef,
8476
- notes: ["Could not extract any file:line references from the finding. Consider adding `server/src/.../file.ts:NNN` style citations to the description before re-running."],
8477
- refsChecked: [],
8478
- refsStillPresent: [],
8479
- refsMissing: []
7619
+ stepId: step.id,
7620
+ kind: "errored",
7621
+ durationMs: Date.now() - start,
7622
+ error: `out-of-scope docker registry: ${registryHost} (allowlist: ${target.scopeAllowlist.join(", ")})`
8480
7623
  };
8481
7624
  }
8482
- const notes = [];
8483
- const refsStillPresent = [];
8484
- const refsMissing = [];
8485
- for (const ref of refs) {
8486
- const abs = join(repoPath, ref.file);
8487
- if (!existsSync(abs)) {
8488
- refsMissing.push(ref);
8489
- notes.push(`${ref.file} \u2014 file does not exist at ${currentRef}.`);
8490
- continue;
8491
- }
8492
- if (ref.line !== void 0) {
7625
+ if (target.scopeAllowlist && target.scopeAllowlist.length > 0) {
7626
+ const dockerTokens = [action.image, ...action.args].join(" ");
7627
+ for (const u of extractUrlsFromShellCommand(dockerTokens)) {
7628
+ let host;
8493
7629
  try {
8494
- const content = readFileSync(abs, "utf8").split("\n");
8495
- if (ref.line > content.length) {
8496
- refsMissing.push(ref);
8497
- notes.push(`${ref.file}:${ref.line} \u2014 line is out of range (file has ${content.length} lines at ${currentRef}).`);
8498
- continue;
8499
- }
7630
+ host = new URL(u).host;
8500
7631
  } catch {
7632
+ continue;
7633
+ }
7634
+ if (!hostMatchesAllowlist(host, target.scopeAllowlist)) {
7635
+ return {
7636
+ stepId: step.id,
7637
+ kind: "errored",
7638
+ durationMs: Date.now() - start,
7639
+ error: `out-of-scope url in docker action: ${u} (allowlist: ${target.scopeAllowlist.join(", ")})`
7640
+ };
8501
7641
  }
8502
7642
  }
8503
- refsStillPresent.push(ref);
8504
- }
8505
- let status;
8506
- if (refsStillPresent.length === 0) {
8507
- status = refsMissing.some((r) => !existsSync(join(repoPath, r.file))) ? "file-removed" : "fixed";
8508
- } else if (refsMissing.length === 0) {
8509
- status = "still-vulnerable";
8510
- } else {
8511
- status = "partial-fix";
8512
- }
8513
- if (status === "still-vulnerable") {
8514
- notes.unshift(`All ${refsStillPresent.length} cited file${refsStillPresent.length === 1 ? "" : "s"} still resolve at ${currentRef}. Status is conservative \u2014 a human should confirm the *shape* of the code at each line hasn't been patched.`);
8515
7643
  }
8516
- return {
8517
- status,
8518
- ref: currentRef,
8519
- notes,
8520
- refsChecked: refs,
8521
- refsStillPresent,
8522
- refsMissing
8523
- };
7644
+ const env = { ...process.env, ...target.env ?? {} };
7645
+ const cwd = target.cwd;
7646
+ const timeoutMs = target.timeoutMs ?? DEFAULT_STEP_TIMEOUT_MS;
7647
+ const spawned = await spawnAndCapture("docker", ["run", "--rm", ...action.args, action.image], { env, cwd, timeoutMs });
7648
+ return finaliseProcessStep(step, spawned, start);
8524
7649
  }
8525
- function refsMatch(a, b) {
8526
- return a.file === b.file && a.line === b.line;
8527
- }
8528
- function formatPatchStatusSection(result) {
8529
- const banner = {
8530
- "still-vulnerable": `**Still vulnerable** on \`${result.ref}\`.`,
8531
- "partial-fix": `**Partial fix** on \`${result.ref}\` \u2014 some cited references changed, others remain.`,
8532
- "fixed": `**Fixed** on \`${result.ref}\`. All cited references have been edited or removed upstream.`,
8533
- "file-removed": `**Vulnerable file removed** on \`${result.ref}\`. The affected path no longer exists in the tree.`,
8534
- "unknown": `**Could not auto-verify** against \`${result.ref}\`. No machine-checkable references were extractable from the finding.`
8535
- };
8536
- const lines = [];
8537
- lines.push(banner[result.status]);
8538
- if (result.refsChecked.length > 0) {
8539
- lines.push("");
8540
- lines.push(`Refs checked (${result.refsChecked.length}):`);
8541
- for (const ref of result.refsChecked) {
8542
- const present = result.refsStillPresent.some((r) => refsMatch(r, ref));
8543
- const marker = present ? "\u2713" : "\u2717";
8544
- lines.push(`- ${marker} \`${ref.file}${ref.line ? `:${ref.line}` : ""}\``);
8545
- }
8546
- }
8547
- if (result.notes.length > 0) {
8548
- lines.push("");
8549
- for (const note of result.notes)
8550
- lines.push(`> ${note}`);
7650
+ async function runHttpStep(step, action, target, start) {
7651
+ const scopeError = scopeRequiredResult(step, target, start);
7652
+ if (scopeError)
7653
+ return scopeError;
7654
+ const url = resolveUrl(action.url, target.baseUrl);
7655
+ if (!url) {
7656
+ return {
7657
+ stepId: step.id,
7658
+ kind: "errored",
7659
+ durationMs: Date.now() - start,
7660
+ error: `http step has a relative url (${action.url}) but no target.baseUrl was provided`
7661
+ };
8551
7662
  }
8552
- return lines.join("\n");
8553
- }
8554
-
8555
- // packages/core/dist/disclose/version-range.js
8556
- import { execFileSync as execFileSync2 } from "node:child_process";
8557
- import { resolve as resolve2 } from "node:path";
8558
- function gitCmd2(repoPath, args) {
7663
+ let host;
8559
7664
  try {
8560
- return execFileSync2("git", args, {
8561
- cwd: repoPath,
8562
- stdio: ["ignore", "pipe", "pipe"],
8563
- encoding: "utf8",
8564
- maxBuffer: 4 * 1024 * 1024
8565
- }).trim();
7665
+ host = new URL(url).host;
8566
7666
  } catch {
8567
- return null;
8568
- }
8569
- }
8570
- function listTags(repoPath, limit, glob) {
8571
- const baseArgs = ["tag"];
8572
- if (glob)
8573
- baseArgs.push("-l", glob);
8574
- const byVersion = gitCmd2(repoPath, [...baseArgs, "--sort=-v:refname"]);
8575
- if (byVersion && byVersion.length > 0) {
8576
- return byVersion.split("\n").filter(Boolean).slice(0, limit);
8577
- }
8578
- const byDate = gitCmd2(repoPath, [...baseArgs, "--sort=-creatordate"]);
8579
- if (!byDate)
8580
- return [];
8581
- return byDate.split("\n").filter(Boolean).slice(0, limit);
8582
- }
8583
- function fileExistsAtRef(repoPath, ref, filePath) {
8584
- const out = gitCmd2(repoPath, ["cat-file", "-e", `${ref}:${filePath}`]);
8585
- return out !== null;
8586
- }
8587
- function lineExistsAtRef(repoPath, ref, filePath, line) {
8588
- const content = gitCmd2(repoPath, ["show", `${ref}:${filePath}`]);
8589
- if (content === null)
8590
- return false;
8591
- const lineCount = content.split("\n").length;
8592
- return line <= lineCount;
8593
- }
8594
- function findingPresentAtRef(repoPath, ref, refs) {
8595
- if (refs.length === 0)
8596
- return false;
8597
- for (const r of refs) {
8598
- if (!fileExistsAtRef(repoPath, ref, r.file))
8599
- return false;
8600
- if (r.line !== void 0 && !lineExistsAtRef(repoPath, ref, r.file, r.line))
8601
- return false;
8602
- }
8603
- return true;
8604
- }
8605
- function detectVersionRange(finding, options) {
8606
- const repoPath = resolve2(options.repoPath);
8607
- const tagLimit = options.tagLimit ?? 30;
8608
- const refs = extractFileRefs(finding);
8609
- const notes = [];
8610
- if (refs.length === 0) {
8611
7667
  return {
8612
- affectedTags: [],
8613
- presentOnHead: false,
8614
- status: "indeterminate",
8615
- notes: ["Could not extract file:line references from the finding. Add explicit `path/to/file.ts:NNN` citations to the description and re-run."]
7668
+ stepId: step.id,
7669
+ kind: "errored",
7670
+ durationMs: Date.now() - start,
7671
+ error: `http step url is not a valid URL: ${url}`
8616
7672
  };
8617
7673
  }
8618
- const tags = listTags(repoPath, tagLimit, options.tagGlob);
8619
- const presentOnHead = findingPresentAtRef(repoPath, "HEAD", refs);
8620
- if (tags.length === 0) {
8621
- notes.push(`No tags found in ${repoPath}${options.tagGlob ? ` matching '${options.tagGlob}'` : ""}.`);
7674
+ if (!hostMatchesAllowlist(host, target.scopeAllowlist)) {
8622
7675
  return {
8623
- affectedTags: [],
8624
- presentOnHead,
8625
- status: "no-tags",
8626
- notes
7676
+ stepId: step.id,
7677
+ kind: "errored",
7678
+ durationMs: Date.now() - start,
7679
+ error: `out-of-scope host: ${host} (allowlist: ${target.scopeAllowlist.join(", ")})`
8627
7680
  };
8628
7681
  }
8629
- const classified = tags.map((tag) => ({
8630
- tag,
8631
- present: findingPresentAtRef(repoPath, tag, refs)
8632
- }));
8633
- const affectedTags = classified.filter((c) => c.present).map((c) => c.tag);
8634
- const introducedIn = affectedTags[affectedTags.length - 1];
8635
- let fixedIn;
8636
- const firstPresentIdx = classified.findIndex((c) => c.present);
8637
- if (firstPresentIdx > 0) {
8638
- fixedIn = classified[firstPresentIdx - 1]?.tag;
8639
- }
8640
- let status;
8641
- if (presentOnHead)
8642
- status = "present-on-head";
8643
- else if (affectedTags.length > 0)
8644
- status = "removed-upstream";
8645
- else
8646
- status = "indeterminate";
8647
- if (affectedTags.length === tagLimit) {
8648
- notes.push(`Hit the ${tagLimit}-tag walk limit \u2014 the introducing tag may be older than reported. Pass --tag-limit to extend.`);
7682
+ const rps = target.rpsPerHost ?? DEFAULT_RPS_PER_HOST;
7683
+ await acquireHostToken(host, rps);
7684
+ const headers = mergePersonaHeaders(action.headers ?? {}, target);
7685
+ const timeoutMs = target.timeoutMs ?? DEFAULT_STEP_TIMEOUT_MS;
7686
+ const ac = new AbortController();
7687
+ const timer = setTimeout(() => ac.abort(), timeoutMs);
7688
+ let finalResponse;
7689
+ let body = "";
7690
+ let currentUrl = url;
7691
+ let redirectCount = 0;
7692
+ try {
7693
+ while (true) {
7694
+ finalResponse = await deps.fetch(currentUrl, {
7695
+ method: action.method,
7696
+ headers,
7697
+ body: action.body,
7698
+ signal: ac.signal,
7699
+ redirect: "manual"
7700
+ });
7701
+ const status = finalResponse.status;
7702
+ const isRedirect = [301, 302, 303, 307, 308].includes(status);
7703
+ if (!isRedirect) {
7704
+ body = await readBodyCapped(finalResponse);
7705
+ if (status === 429) {
7706
+ const retryAfter = finalResponse.headers.get("retry-after");
7707
+ markHostRateLimited(host, retryAfter);
7708
+ }
7709
+ break;
7710
+ }
7711
+ redirectCount++;
7712
+ if (redirectCount > MAX_REDIRECT_HOPS) {
7713
+ try {
7714
+ finalResponse.body?.cancel();
7715
+ } catch {
7716
+ }
7717
+ clearTimeout(timer);
7718
+ return {
7719
+ stepId: step.id,
7720
+ kind: "errored",
7721
+ durationMs: Date.now() - start,
7722
+ error: `too many redirects (exceeded ${MAX_REDIRECT_HOPS} hops)`
7723
+ };
7724
+ }
7725
+ const location = finalResponse.headers.get("location");
7726
+ if (!location) {
7727
+ body = await readBodyCapped(finalResponse);
7728
+ break;
7729
+ }
7730
+ const nextUrlStr = new URL(location, currentUrl).toString();
7731
+ const nextHost = new URL(nextUrlStr).host;
7732
+ if (!hostMatchesAllowlist(nextHost, target.scopeAllowlist)) {
7733
+ try {
7734
+ finalResponse.body?.cancel();
7735
+ } catch {
7736
+ }
7737
+ clearTimeout(timer);
7738
+ return {
7739
+ stepId: step.id,
7740
+ kind: "errored",
7741
+ durationMs: Date.now() - start,
7742
+ error: `redirect to out-of-scope host: ${nextHost} (allowlist: ${target.scopeAllowlist.join(", ")})`
7743
+ };
7744
+ }
7745
+ try {
7746
+ finalResponse.body?.cancel();
7747
+ } catch {
7748
+ }
7749
+ currentUrl = nextUrlStr;
7750
+ }
7751
+ } catch (err) {
7752
+ clearTimeout(timer);
7753
+ const aborted = ac.signal.aborted;
7754
+ return {
7755
+ stepId: step.id,
7756
+ kind: "errored",
7757
+ durationMs: Date.now() - start,
7758
+ error: aborted ? `timeout after ${timeoutMs}ms` : errMessage(err)
7759
+ };
7760
+ } finally {
7761
+ clearTimeout(timer);
8649
7762
  }
7763
+ const verdict = evaluateExpect(step.expect, {
7764
+ status: finalResponse.status,
7765
+ body
7766
+ });
8650
7767
  return {
8651
- affectedTags,
8652
- introducedIn,
8653
- fixedIn,
8654
- presentOnHead,
8655
- status,
8656
- notes
7768
+ stepId: step.id,
7769
+ kind: verdict.kind,
7770
+ observedStatus: finalResponse.status,
7771
+ observedResponseBody: body,
7772
+ durationMs: Date.now() - start,
7773
+ ...verdict.error ? { error: verdict.error } : {}
8657
7774
  };
8658
7775
  }
8659
- function formatVersionRangeLine(result) {
8660
- switch (result.status) {
8661
- case "present-on-head":
8662
- if (result.introducedIn) {
8663
- return `\`>= ${result.introducedIn}\`, including the repo's current \`HEAD\`. Confirmed on: ${result.affectedTags.map((t) => "`" + t + "`").join(", ")}.`;
8664
- }
8665
- return "Present on the repo's current `HEAD` (no tagged introduction point detected).";
8666
- case "removed-upstream":
8667
- if (result.introducedIn && result.fixedIn) {
8668
- return `\`>= ${result.introducedIn}\`, \`< ${result.fixedIn}\`. Confirmed affected: ${result.affectedTags.map((t) => "`" + t + "`").join(", ")}. Fixed from \`${result.fixedIn}\` onward.`;
8669
- }
8670
- if (result.introducedIn) {
8671
- return `\`>= ${result.introducedIn}\`. Confirmed affected: ${result.affectedTags.map((t) => "`" + t + "`").join(", ")}. Fixed upstream at HEAD.`;
8672
- }
8673
- return "Removed upstream since the last release.";
8674
- case "no-tags":
8675
- return "_No release tags available in the target repo to infer a range._";
8676
- case "indeterminate":
8677
- default:
8678
- return "_Could not auto-detect a version range \u2014 add file:line citations to the finding and re-run._";
8679
- }
8680
- }
8681
-
8682
- // packages/core/dist/disclose/template.js
8683
- var EmptyPocError = class extends Error {
8684
- findingId;
8685
- constructor(findingId) {
8686
- super(`Finding ${findingId} has no PoC content (pocSteps, evidence, or screenshots) \u2014 refusing to render advisory.`);
8687
- this.name = "EmptyPocError";
8688
- this.findingId = findingId;
8689
- }
8690
- };
8691
- var SENSITIVE_HEADER_NAMES = /* @__PURE__ */ new Set([
8692
- "authorization",
8693
- "proxy-authorization",
8694
- "cookie",
8695
- "set-cookie",
8696
- "x-auth-token",
8697
- "x-api-key",
8698
- "x-csrf-token",
8699
- "x-xsrf-token"
8700
- ]);
8701
- var AWS_KEY_RE = /\bAKIA[0-9A-Z]{16}\b/g;
8702
- var JWT_RE = /\b[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+={0,2}\b/g;
8703
- var INLINE_BEARER_RE = /\b(Bearer)\s+([^\s"'`]+)/gi;
8704
- var INLINE_CURL_HEADER_RE = /(-H|--header)(\s+|=)(["']?)([A-Za-z][A-Za-z0-9-]*)\s*:\s*([^"'\n]*)\3/gi;
8705
- function redactSensitiveHeaders(text) {
8706
- if (!text)
8707
- return text;
8708
- let out = redactAuthHeaders(text);
8709
- out = out.replace(AWS_KEY_RE, "<REDACTED-AWS-KEY>");
8710
- out = out.replace(JWT_RE, (match) => {
8711
- if (match.length < 80)
8712
- return match;
8713
- return "<REDACTED-JWT>";
8714
- });
8715
- return out;
8716
- }
8717
- function redactAuthHeaders(text) {
8718
- if (!text)
8719
- return text;
8720
- const lines = text.split("\n");
8721
- const redactedLines = lines.map((line) => {
8722
- const m = /^(\s*)([A-Za-z][A-Za-z0-9-]*)\s*:\s*(.*)$/.exec(line);
8723
- if (m && SENSITIVE_HEADER_NAMES.has(m[2].toLowerCase())) {
8724
- return `${m[1]}${m[2]}: <REDACTED-${m[2]}>`;
8725
- }
8726
- return line;
8727
- });
8728
- let out = redactedLines.join("\n");
8729
- out = out.replace(INLINE_CURL_HEADER_RE, (match, flag, sep, quote, name, _value) => {
8730
- if (!SENSITIVE_HEADER_NAMES.has(name.toLowerCase()))
8731
- return match;
8732
- return `${flag}${sep}${quote}${name}: <REDACTED-${name}>${quote}`;
8733
- });
8734
- return out.replace(INLINE_BEARER_RE, "$1 <REDACTED-Bearer>");
8735
- }
8736
- function reachabilityLabel(tier) {
8737
- switch (tier) {
8738
- case "remote-unauth":
8739
- return "remote, unauthenticated \u2014 reachable over the network with no credentials";
8740
- case "proximity-rf":
8741
- return "RF/physical proximity \u2014 attacker must be within radio range (NFC/BLE/Wi-Fi)";
8742
- case "local-unpriv":
8743
- return "local, unprivileged \u2014 requires an unprivileged account on the host";
8744
- case "local-priv":
8745
- return "local, privileged \u2014 requires an already-privileged local account";
8746
- case "needs-hardware":
8747
- return "requires specific or attacker-supplied hardware";
8748
- case "needs-host-migration":
8749
- return "requires the victim to mount/import an attacker-supplied artifact";
8750
- }
8751
- }
8752
- function weaponizabilityLabel(w) {
8753
- switch (w) {
8754
- case "rce":
8755
- return "remote code execution";
8756
- case "lpe-to-root":
8757
- return "local privilege escalation to root/SYSTEM";
8758
- case "info-leak":
8759
- return "information disclosure";
8760
- case "dos-crash":
8761
- return "denial of service (crash)";
7776
+ function resolveUrl(stepUrl, baseUrl) {
7777
+ try {
7778
+ new URL(stepUrl);
7779
+ return stepUrl;
7780
+ } catch {
8762
7781
  }
8763
- }
8764
- function severityHeading(severity) {
8765
- const upper = severity.toUpperCase();
8766
- return upper === "CRITICAL" || upper === "HIGH" || upper === "MEDIUM" || upper === "LOW" ? upper : severity;
8767
- }
8768
- function slugifyTitle(title, max = 80) {
8769
- return title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, max);
8770
- }
8771
- function indentEvidenceBlock(raw, lang = "") {
8772
- const trimmed = raw.trim();
8773
- if (!trimmed)
8774
- return "";
8775
- return "```" + lang + "\n" + trimmed + "\n```";
8776
- }
8777
- function renderPocSteps(finding) {
8778
- if (!finding.pocSteps || finding.pocSteps.length === 0)
8779
- return [];
8780
- const lines = ["**Step graph:**", ""];
8781
- for (const [index, step] of finding.pocSteps.entries()) {
8782
- lines.push(`${index + 1}. **${step.kind}** \u2014 ${step.summary} _(id: \`${step.id}\`)_`);
8783
- if (step.action.type === "shell") {
8784
- lines.push("", indentEvidenceBlock(step.action.cmd, "bash"));
8785
- } else if (step.action.type === "http") {
8786
- const method = step.action.method.toUpperCase();
8787
- lines.push("", indentEvidenceBlock(`${method} ${step.action.url}${step.action.body ? `
8788
-
8789
- ${step.action.body}` : ""}`, "http"));
8790
- } else if (step.action.type === "docker") {
8791
- lines.push("", indentEvidenceBlock(`docker run ${step.action.image} ${step.action.args.join(" ")}`.trim(), "bash"));
8792
- } else {
8793
- lines.push("", step.action.text);
8794
- }
8795
- if (step.expect) {
8796
- lines.push("", `Expected result: \`${step.expect.type}\``);
8797
- }
8798
- lines.push("");
7782
+ if (!baseUrl)
7783
+ return null;
7784
+ try {
7785
+ return new URL(stepUrl, baseUrl).toString();
7786
+ } catch {
7787
+ return null;
8799
7788
  }
8800
- return lines;
8801
7789
  }
8802
- function renderAdvisoryMarkdown(finding, ctx = {}) {
8803
- const cwes = suggestCwesForCategory(finding.category);
8804
- const cvss = suggestCvss(finding);
8805
- const severity = severityHeading(finding.severity);
8806
- const rank = { critical: "1", high: "2", medium: "3", low: "4", info: "5" };
8807
- const filenameSlug = slugifyTitle(finding.title);
8808
- const filename = `${rank[finding.severity] ?? "9"}-${finding.severity}-${filenameSlug}.md`;
8809
- let affectedLine;
8810
- if (ctx.versionRange) {
8811
- affectedLine = formatVersionRangeLine(ctx.versionRange);
8812
- } else if (ctx.target) {
8813
- affectedLine = `\`${ctx.target}\`${ctx.targetRef ? ` at \`${ctx.targetRef}\`` : ""}${ctx.commitHash ? ` (commit \`${ctx.commitHash.slice(0, 12)}\`)` : ""}`;
8814
- } else {
8815
- affectedLine = "_Pass `--repo <path>` to `0sec-cli disclose` to auto-detect the affected version range from git tags._";
8816
- }
8817
- const cvssSource = cvss.source === "finding" ? "populated on the finding by 0sec" : cvss.source === "impact-assessment" ? "exploitability metrics derived from 0sec's reachability assessment; impact from category \u2014 verify against your deployment" : "heuristic from category + severity \u2014 override in the GHSA editor if the operator disagrees";
8818
- const remediation = finding.remediation;
8819
- const suggestedFixParts = [];
8820
- if (remediation?.summary)
8821
- suggestedFixParts.push(remediation.summary);
8822
- if (remediation?.steps?.length) {
8823
- suggestedFixParts.push(remediation.steps.map((step, i) => `${i + 1}. ${step}`).join("\n"));
8824
- }
8825
- if (remediation?.codeExample?.after) {
8826
- const lang = remediation.codeExample.language || "";
8827
- suggestedFixParts.push(remediation.codeExample.before ? `**Before:**
8828
-
8829
- \`\`\`${lang}
8830
- ${remediation.codeExample.before}
8831
- \`\`\`
8832
-
8833
- **After:**
8834
-
8835
- \`\`\`${lang}
8836
- ${remediation.codeExample.after}
8837
- \`\`\`` : `\`\`\`${lang}
8838
- ${remediation.codeExample.after}
8839
- \`\`\``);
8840
- } else if (ctx.siblingFix) {
8841
- const ref = `${ctx.siblingFix.fileRef.file}${ctx.siblingFix.fileRef.line ? `:${ctx.siblingFix.fileRef.line}` : ""}`;
8842
- suggestedFixParts.push(`**Correct pattern already present in the repo at \`${ref}\`** *(extracted by 0sec):*
8843
-
8844
- \`\`\`${ctx.siblingFix.language}
8845
- ${ctx.siblingFix.snippet}
8846
- \`\`\``);
8847
- }
8848
- const suggestedFix = suggestedFixParts.length > 0 ? suggestedFixParts.join("\n\n") : "_To fill in: copy-paste the correct pattern from a sibling handler in the same repo._";
8849
- const evidenceAnalysis = finding.evidence?.analysis?.trim() ?? "";
8850
- const out = [];
8851
- out.push("# Title", "");
8852
- out.push(finding.title, "");
8853
- out.push("# Severity", "");
8854
- out.push(`**${severity}** \u2014 ${cvss.vector} (~${cvss.score.toFixed(1)})`, "");
8855
- out.push(`_CVSS source: ${cvssSource}._`, "");
8856
- const impactAssessment = finding.impactAssessment;
8857
- if (impactAssessment) {
8858
- out.push("# Impact", "");
8859
- out.push(`**Attacker gains:** ${weaponizabilityLabel(impactAssessment.weaponizability)}`, "");
8860
- out.push(`**Attack prerequisites:** ${reachabilityLabel(impactAssessment.reachability_tier)}`, "");
8861
- if (impactAssessment.blast_radius) {
8862
- out.push(`**Blast radius:** ${impactAssessment.blast_radius}`, "");
8863
- }
8864
- if (impactAssessment.rationale) {
8865
- out.push(`_${impactAssessment.rationale}_`, "");
7790
+ function mergePersonaHeaders(stepHeaders, target) {
7791
+ const merged = {};
7792
+ let personaName;
7793
+ for (const [k, v] of Object.entries(stepHeaders)) {
7794
+ if (k.toLowerCase() === PERSONA_HEADER.toLowerCase()) {
7795
+ personaName = v;
7796
+ continue;
8866
7797
  }
7798
+ merged[k] = v;
8867
7799
  }
8868
- out.push(formatCweSection(cwes), "");
8869
- out.push("# Affected versions", "");
8870
- out.push(affectedLine, "");
8871
- if (ctx.osecVersion || ctx.scanId) {
8872
- const bits = [];
8873
- if (ctx.osecVersion)
8874
- bits.push(`0sec \`${ctx.osecVersion}\``);
8875
- if (ctx.scanId)
8876
- bits.push(`scan \`${ctx.scanId.slice(0, 8)}\``);
8877
- const canaryPositive = ctx.patchStatus?.status === "still-vulnerable";
8878
- const behaviouralPositive = ctx.pocExecution?.overallVerdict === "exploit_still_works";
8879
- if (canaryPositive && behaviouralPositive) {
8880
- out.push(`> Code-verified by ${bits.join(", ")}.`, "");
8881
- } else {
8882
- out.push(`_Generated by ${bits.join(", ")}._`, "");
7800
+ if (!personaName)
7801
+ return merged;
7802
+ const persona = target.personas?.[personaName];
7803
+ if (!persona)
7804
+ return merged;
7805
+ if (persona.headers) {
7806
+ for (const [k, v] of Object.entries(persona.headers)) {
7807
+ if (!(k in merged))
7808
+ merged[k] = v;
8883
7809
  }
8884
7810
  }
8885
- out.push("## Summary", "");
8886
- out.push(finding.description.trim(), "");
8887
- if (evidenceAnalysis && evidenceAnalysis !== finding.description.trim()) {
8888
- out.push("## Analysis", "");
8889
- out.push(evidenceAnalysis, "");
8890
- }
8891
- const pocStepsBlock = renderPocSteps(finding);
8892
- const hasRequest = !!finding.evidence?.request?.trim();
8893
- const hasResponse = !!finding.evidence?.response?.trim();
8894
- const hasScreenshots = !!ctx.screenshots && ctx.screenshots.length > 0;
8895
- if (pocStepsBlock.length === 0 && !hasRequest && !hasResponse && !hasScreenshots) {
8896
- throw new EmptyPocError(finding.id);
8897
- }
8898
- out.push("## PoC", "");
8899
- if (pocStepsBlock.length > 0) {
8900
- const redactedSteps = redactSensitiveHeaders(pocStepsBlock.join("\n")).split("\n");
8901
- out.push(...redactedSteps);
8902
- }
8903
- if (hasScreenshots) {
8904
- for (const shot of ctx.screenshots) {
8905
- const width = shot.width ? ` width="${shot.width}"` : "";
8906
- out.push(`<img${width} alt="${shot.alt}" src="${shot.relativePath}" />`, "");
8907
- if (shot.caption) {
8908
- out.push(`> ${shot.caption}`, "");
8909
- }
8910
- }
8911
- }
8912
- if (hasRequest) {
8913
- out.push("**Request:**", "");
8914
- out.push(indentEvidenceBlock(redactSensitiveHeaders(finding.evidence.request), "http"), "");
8915
- }
8916
- if (hasResponse) {
8917
- out.push("**Response:**", "");
8918
- out.push(indentEvidenceBlock(redactSensitiveHeaders(finding.evidence.response), "http"), "");
8919
- }
8920
- out.push("## Suggested fix", "");
8921
- out.push(suggestedFix, "");
8922
- out.push("## Patch status", "");
8923
- if (ctx.patchStatus) {
8924
- out.push(formatPatchStatusSection(ctx.patchStatus), "");
8925
- } else {
8926
- out.push("_Pass `--repo <path>` to `0sec-cli disclose` to auto-verify this against the target's current HEAD or a specific tag._", "");
7811
+ if (persona.cookies && !("cookie" in lowerKeys(merged))) {
7812
+ merged["Cookie"] = persona.cookies;
8927
7813
  }
8928
- if (ctx.pocExecution) {
8929
- const verdict = ctx.pocExecution.overallVerdict === "exploit_still_works" ? "**Behavioural check: exploit still reproducible.**" : ctx.pocExecution.overallVerdict === "exploit_broken" ? "**Behavioural check: exploit no longer reproducible.**" : "**Behavioural check: could not run.**";
8930
- out.push(verdict, "");
8931
- out.push(`> Verdict: \`${ctx.pocExecution.overallVerdict}\` (${ctx.pocExecution.steps.length} step${ctx.pocExecution.steps.length === 1 ? "" : "s"} executed).`, "");
8932
- }
8933
- out.push("## Credits", "");
8934
- out.push("Discovered by **0sec**, 0sec's AI-assisted security engine ([0sec.ai](https://0sec.ai)).", "", "Reporter: _(your github handle)_", "");
8935
- return {
8936
- filename,
8937
- markdown: out.join("\n").replace(/\n{3,}/g, "\n\n"),
8938
- cvssVector: cvss.vector,
8939
- cvssScore: cvss.score,
8940
- primaryCwe: cwes[0]?.id ?? "",
8941
- severity: finding.severity
8942
- };
8943
- }
8944
- function buildAffectedLine(finding, ctx) {
8945
- if (ctx.versionRange)
8946
- return formatVersionRangeLine(ctx.versionRange);
8947
- if (ctx.target) {
8948
- return `\`${ctx.target}\`${ctx.targetRef ? ` at \`${ctx.targetRef}\`` : ""}${ctx.commitHash ? ` (commit \`${ctx.commitHash.slice(0, 12)}\`)` : ""}`;
8949
- }
8950
- return "_Affected component/version: to be filled in by the operator before submission._";
8951
- }
8952
- function buildImpactNarrative(finding) {
8953
- const a = finding.impactAssessment;
8954
- if (!a) {
8955
- return `This ${finding.category.replace(/-/g, " ")} issue is rated **${severityHeading(finding.severity)}**. ` + finding.description.trim();
8956
- }
8957
- const parts = [];
8958
- parts.push(`An attacker gains **${weaponizabilityLabel(a.weaponizability)}**. Attack prerequisites: ${reachabilityLabel(a.reachability_tier)}.`);
8959
- if (a.blast_radius)
8960
- parts.push(`**Blast radius:** ${a.blast_radius}`);
8961
- if (a.rationale)
8962
- parts.push(a.rationale);
8963
- return parts.join("\n\n");
7814
+ return merged;
8964
7815
  }
8965
- function buildAttackScenario(finding) {
8966
- const a = finding.impactAssessment;
8967
- if (!a)
8968
- return "";
8969
- return `1. Attacker position: ${reachabilityLabel(a.reachability_tier)}.
8970
- 2. Trigger the ${finding.category.replace(/-/g, " ")} condition described above.
8971
- 3. Result: ${weaponizabilityLabel(a.weaponizability)}${a.blast_radius ? ` \u2014 ${a.blast_radius}` : ""}.`;
7816
+ function lowerKeys(obj) {
7817
+ const out = {};
7818
+ for (const [k, v] of Object.entries(obj))
7819
+ out[k.toLowerCase()] = v;
7820
+ return out;
8972
7821
  }
8973
- function buildStepsToReproduce(finding) {
8974
- const block = renderPocSteps(finding);
8975
- if (block.length === 0)
7822
+ async function readBodyCapped(response) {
7823
+ if (!response.body)
8976
7824
  return "";
8977
- return redactSensitiveHeaders(block.join("\n"));
7825
+ const reader = response.body.getReader();
7826
+ const decoder = new TextDecoder("utf-8", { fatal: false });
7827
+ let captured = "";
7828
+ let truncated = false;
7829
+ while (true) {
7830
+ const { value, done } = await reader.read();
7831
+ if (done)
7832
+ break;
7833
+ if (value) {
7834
+ const chunk = decoder.decode(value, { stream: true });
7835
+ if (captured.length + chunk.length > MAX_CAPTURE_BYTES) {
7836
+ captured += chunk.slice(0, MAX_CAPTURE_BYTES - captured.length);
7837
+ truncated = true;
7838
+ try {
7839
+ await reader.cancel();
7840
+ } catch {
7841
+ }
7842
+ break;
7843
+ }
7844
+ captured += chunk;
7845
+ }
7846
+ }
7847
+ return truncated ? captured + TRUNCATION_MARKER : captured;
8978
7848
  }
8979
- function buildPocEvidence(finding, ctx) {
8980
- const out = [];
8981
- if (ctx.screenshots && ctx.screenshots.length > 0) {
8982
- for (const shot of ctx.screenshots) {
8983
- const width = shot.width ? ` width="${shot.width}"` : "";
8984
- out.push(`<img${width} alt="${shot.alt}" src="${shot.relativePath}" />`, "");
8985
- if (shot.caption)
8986
- out.push(`> ${shot.caption}`, "");
8987
- }
8988
- }
8989
- if (finding.evidence?.request?.trim()) {
8990
- out.push("**Request:**", "", indentEvidenceBlock(redactSensitiveHeaders(finding.evidence.request), "http"), "");
8991
- }
8992
- if (finding.evidence?.response?.trim()) {
8993
- out.push("**Response:**", "", indentEvidenceBlock(redactSensitiveHeaders(finding.evidence.response), "http"), "");
8994
- }
8995
- return out.join("\n").trim();
8996
- }
8997
- function buildRemediation(finding, ctx) {
8998
- const remediation = finding.remediation;
8999
- const parts = [];
9000
- if (remediation?.summary)
9001
- parts.push(remediation.summary);
9002
- if (remediation?.steps?.length) {
9003
- parts.push(remediation.steps.map((step, i) => `${i + 1}. ${step}`).join("\n"));
9004
- }
9005
- if (remediation?.codeExample?.after) {
9006
- const lang = remediation.codeExample.language || "";
9007
- parts.push(remediation.codeExample.before ? `**Before:**
9008
-
9009
- \`\`\`${lang}
9010
- ${remediation.codeExample.before}
9011
- \`\`\`
9012
-
9013
- **After:**
9014
-
9015
- \`\`\`${lang}
9016
- ${remediation.codeExample.after}
9017
- \`\`\`` : `\`\`\`${lang}
9018
- ${remediation.codeExample.after}
9019
- \`\`\``);
9020
- } else if (ctx.siblingFix) {
9021
- const ref = `${ctx.siblingFix.fileRef.file}${ctx.siblingFix.fileRef.line ? `:${ctx.siblingFix.fileRef.line}` : ""}`;
9022
- parts.push(`**Correct pattern already present in the repo at \`${ref}\`** *(extracted by 0sec):*
9023
-
9024
- \`\`\`${ctx.siblingFix.language}
9025
- ${ctx.siblingFix.snippet}
9026
- \`\`\``);
9027
- }
9028
- return parts.length > 0 ? parts.join("\n\n") : "_Recommended fix: apply input validation / correct handling per the referenced CWE guidance._";
9029
- }
9030
- function buildReferences(finding, cwes) {
9031
- const lines = [];
9032
- for (const cwe of cwes) {
9033
- const num = cwe.id.replace(/^CWE-/i, "");
9034
- lines.push(`- [${cwe.id}: ${cwe.name}](https://cwe.mitre.org/data/definitions/${num}.html)`);
9035
- }
9036
- for (const ref of finding.remediation?.references ?? []) {
9037
- lines.push(`- ${ref}`);
9038
- }
9039
- return lines.length > 0 ? lines.join("\n") : "_No external references._";
7849
+ function spawnAndCapture(cmd, args, opts) {
7850
+ return new Promise((resolveP) => {
7851
+ let child;
7852
+ try {
7853
+ child = deps.spawn(cmd, args, {
7854
+ env: opts.env,
7855
+ cwd: opts.cwd,
7856
+ stdio: ["ignore", "pipe", "pipe"]
7857
+ });
7858
+ } catch (err) {
7859
+ resolveP({
7860
+ exitCode: null,
7861
+ stdout: "",
7862
+ stderr: "",
7863
+ timedOut: false,
7864
+ error: errMessage(err)
7865
+ });
7866
+ return;
7867
+ }
7868
+ let stdout = "";
7869
+ let stderr = "";
7870
+ let stdoutTruncated = false;
7871
+ let stderrTruncated = false;
7872
+ let timedOut = false;
7873
+ let settled = false;
7874
+ const timer = setTimeout(() => {
7875
+ timedOut = true;
7876
+ try {
7877
+ child.kill("SIGKILL");
7878
+ } catch {
7879
+ }
7880
+ }, opts.timeoutMs);
7881
+ child.stdout?.on("data", (chunk) => {
7882
+ const s = typeof chunk === "string" ? chunk : chunk.toString("utf8");
7883
+ if (stdout.length + s.length > MAX_CAPTURE_BYTES) {
7884
+ if (!stdoutTruncated) {
7885
+ stdout += s.slice(0, MAX_CAPTURE_BYTES - stdout.length);
7886
+ stdoutTruncated = true;
7887
+ }
7888
+ return;
7889
+ }
7890
+ stdout += s;
7891
+ });
7892
+ child.stderr?.on("data", (chunk) => {
7893
+ const s = typeof chunk === "string" ? chunk : chunk.toString("utf8");
7894
+ if (stderr.length + s.length > MAX_CAPTURE_BYTES) {
7895
+ if (!stderrTruncated) {
7896
+ stderr += s.slice(0, MAX_CAPTURE_BYTES - stderr.length);
7897
+ stderrTruncated = true;
7898
+ }
7899
+ return;
7900
+ }
7901
+ stderr += s;
7902
+ });
7903
+ const settle = (exit, errorMsg) => {
7904
+ if (settled)
7905
+ return;
7906
+ settled = true;
7907
+ clearTimeout(timer);
7908
+ resolveP({
7909
+ exitCode: exit,
7910
+ stdout: stdoutTruncated ? stdout + TRUNCATION_MARKER : stdout,
7911
+ stderr: stderrTruncated ? stderr + TRUNCATION_MARKER : stderr,
7912
+ timedOut,
7913
+ error: errorMsg
7914
+ });
7915
+ };
7916
+ child.on("error", (err) => {
7917
+ settle(null, errMessage(err));
7918
+ });
7919
+ child.on("close", (code) => {
7920
+ settle(code);
7921
+ });
7922
+ });
9040
7923
  }
9041
- function bugcrowdPriority(severity) {
9042
- switch (severity) {
9043
- case "critical":
9044
- return "P1 (Critical)";
9045
- case "high":
9046
- return "P2 (High)";
9047
- case "medium":
9048
- return "P3 (Medium)";
9049
- case "low":
9050
- return "P4 (Low)";
9051
- default:
9052
- return "P5 (Informational)";
7924
+ function finaliseProcessStep(step, spawned, start) {
7925
+ const durationMs = Date.now() - start;
7926
+ if (spawned.timedOut) {
7927
+ return {
7928
+ stepId: step.id,
7929
+ kind: "errored",
7930
+ observedStdout: spawned.stdout,
7931
+ observedStderr: spawned.stderr,
7932
+ durationMs,
7933
+ error: `timeout after ${durationMs}ms`
7934
+ };
9053
7935
  }
9054
- }
9055
- function immunefiSeverity(severity) {
9056
- switch (severity) {
9057
- case "critical":
9058
- return "Critical \u2014 direct loss/freezing of funds or protocol insolvency";
9059
- case "high":
9060
- return "High \u2014 significant impact to funds or protocol integrity";
9061
- case "medium":
9062
- return "Medium \u2014 limited impact, bounded or conditional";
9063
- default:
9064
- return "Low \u2014 informational / minor impact";
7936
+ if (spawned.error && spawned.exitCode === null) {
7937
+ return {
7938
+ stepId: step.id,
7939
+ kind: "errored",
7940
+ observedStdout: spawned.stdout,
7941
+ observedStderr: spawned.stderr,
7942
+ durationMs,
7943
+ error: spawned.error
7944
+ };
9065
7945
  }
9066
- }
9067
- function buildCommonParts(finding, ctx) {
9068
- const cwes = suggestCwesForCategory(finding.category);
9069
- const cvss = suggestCvss(finding);
9070
- const cvss4 = suggestCvss4(finding);
9071
- const severity = severityHeading(finding.severity);
9072
- const steps = buildStepsToReproduce(finding);
9073
- const poc = buildPocEvidence(finding, ctx);
9074
- if (!steps && !poc)
9075
- throw new EmptyPocError(finding.id);
9076
- return {
9077
- cvss,
9078
- cwes,
9079
- severity,
9080
- title: finding.title,
9081
- summary: finding.description.trim(),
9082
- impact: buildImpactNarrative(finding),
9083
- attackScenario: buildAttackScenario(finding),
9084
- steps,
9085
- poc,
9086
- affected: buildAffectedLine(finding, ctx),
9087
- remediation: buildRemediation(finding, ctx),
9088
- references: buildReferences(finding, cwes),
9089
- severityCvss31: renderCvssSection({ vector: cvss.vector, score: cvss.score, severity }),
9090
- severityCvss40: renderCvssSection({
9091
- vector: cvss4.vector,
9092
- score: cvss4.score,
9093
- severity: cvss4.severity
9094
- })
7946
+ const verdict = evaluateExpect(step.expect, {
7947
+ exitCode: spawned.exitCode,
7948
+ stdout: spawned.stdout
7949
+ });
7950
+ const result = {
7951
+ stepId: step.id,
7952
+ kind: verdict.kind,
7953
+ observedStdout: spawned.stdout,
7954
+ observedStderr: spawned.stderr,
7955
+ durationMs
9095
7956
  };
7957
+ if (spawned.exitCode !== null)
7958
+ result.observedExit = spawned.exitCode;
7959
+ if (verdict.error)
7960
+ result.error = verdict.error;
7961
+ return result;
9096
7962
  }
9097
- function assembleReport(platform, parts, sections) {
9098
- const out = [`# ${parts.title}`, ""];
9099
- for (const s of sections) {
9100
- out.push(`## ${s.heading}`, "", s.body, "");
7963
+ function evaluateExpect(expect, obs) {
7964
+ if (!expect) {
7965
+ return { kind: "passed" };
7966
+ }
7967
+ switch (expect.type) {
7968
+ case "exit-zero": {
7969
+ if (obs.exitCode === 0)
7970
+ return { kind: "passed" };
7971
+ return {
7972
+ kind: "failed",
7973
+ error: `expected exit-zero, got exitCode=${String(obs.exitCode ?? "unknown")}`
7974
+ };
7975
+ }
7976
+ case "http-status": {
7977
+ const wanted = Array.isArray(expect.status) ? expect.status : [expect.status];
7978
+ if (typeof obs.status === "number" && wanted.includes(obs.status)) {
7979
+ return { kind: "passed" };
7980
+ }
7981
+ return {
7982
+ kind: "failed",
7983
+ error: `expected http-status in [${wanted.join(",")}], got ${String(obs.status ?? "no-response")}`
7984
+ };
7985
+ }
7986
+ case "body-contains": {
7987
+ const haystack = obs.body ?? obs.stdout ?? "";
7988
+ if (haystack.includes(expect.text))
7989
+ return { kind: "passed" };
7990
+ return {
7991
+ kind: "failed",
7992
+ error: `expected body-contains '${expect.text}', not found in observed output`
7993
+ };
7994
+ }
7995
+ case "body-matches": {
7996
+ const haystack = obs.body ?? obs.stdout ?? "";
7997
+ let re;
7998
+ try {
7999
+ re = new RegExp(expect.pattern);
8000
+ } catch (err) {
8001
+ return { kind: "errored", error: `invalid regex: ${errMessage(err)}` };
8002
+ }
8003
+ if (re.test(haystack))
8004
+ return { kind: "passed" };
8005
+ return {
8006
+ kind: "failed",
8007
+ error: `expected body-matches /${expect.pattern}/, no match in observed output`
8008
+ };
8009
+ }
8010
+ case "file-exists": {
8011
+ return {
8012
+ kind: "errored",
8013
+ error: "file-exists predicate cannot be evaluated against a network target; rewrite as a shell action with `[ -e <path> ]`"
8014
+ };
8015
+ }
8016
+ default: {
8017
+ const _exhaustive = expect;
8018
+ return {
8019
+ kind: "errored",
8020
+ error: `unknown expect type: ${JSON.stringify(_exhaustive)}`
8021
+ };
8022
+ }
9101
8023
  }
9102
- return {
9103
- platform,
9104
- title: parts.title,
9105
- markdown: out.join("\n").replace(/\n{3,}/g, "\n\n"),
9106
- cvssVector: parts.cvss.vector,
9107
- cvssScore: parts.cvss.score,
9108
- severity: parts.severity,
9109
- sections
9110
- };
9111
8024
  }
9112
- function stepsBodyOrPoc(parts) {
9113
- return parts.steps || "_See the Proof of Concept section below for the reproduction._";
9114
- }
9115
- var HACKERONE_TEMPLATE = {
9116
- id: "hackerone",
9117
- label: "HackerOne",
9118
- description: "H1 field order: Summary \u2192 Steps To Reproduce \u2192 PoC \u2192 Impact \u2192 Severity (CVSS) \u2192 Remediation \u2192 Supporting Material.",
9119
- requiredSections: [
9120
- "Summary",
9121
- "Steps To Reproduce",
9122
- "Proof of Concept",
9123
- "Impact",
9124
- "Severity",
9125
- "Remediation",
9126
- "Supporting Material / References"
9127
- ],
9128
- render(finding, ctx = {}) {
9129
- const parts = buildCommonParts(finding, ctx);
9130
- const sections = [
9131
- { heading: "Summary", body: parts.summary },
9132
- { heading: "Affected Asset", body: parts.affected },
9133
- { heading: "Steps To Reproduce", body: stepsBodyOrPoc(parts) },
9134
- { heading: "Proof of Concept", body: parts.poc || "_See Steps To Reproduce._" },
9135
- { heading: "Impact", body: parts.impact },
9136
- { heading: "Severity", body: `${parts.severityCvss31}
9137
-
9138
- _${cvssSourceLabel(parts.cvss)}_` },
9139
- { heading: "Remediation", body: parts.remediation },
9140
- { heading: "Supporting Material / References", body: parts.references }
9141
- ];
9142
- return assembleReport("hackerone", parts, sections);
9143
- }
9144
- };
9145
- var BUGCROWD_TEMPLATE = {
9146
- id: "bugcrowd",
9147
- label: "Bugcrowd",
9148
- description: "Bugcrowd VRT-first: leads with Business Impact + VRT priority (P1\u2013P5), then Vulnerability Details, Steps, PoC, Remediation.",
9149
- requiredSections: [
9150
- "Vulnerability Details",
9151
- "Business Impact",
9152
- "Bugcrowd VRT / Priority",
9153
- "Steps to Reproduce",
9154
- "Proof of Concept",
9155
- "Remediation",
9156
- "References"
9157
- ],
9158
- render(finding, ctx = {}) {
9159
- const parts = buildCommonParts(finding, ctx);
9160
- const sections = [
9161
- { heading: "Business Impact", body: parts.impact },
9162
- {
9163
- heading: "Bugcrowd VRT / Priority",
9164
- body: `**${bugcrowdPriority(finding.severity)}**
9165
-
9166
- ${parts.severityCvss31}`
9167
- },
9168
- { heading: "Vulnerability Details", body: parts.summary },
9169
- { heading: "Affected Target", body: parts.affected },
9170
- { heading: "Steps to Reproduce", body: stepsBodyOrPoc(parts) },
9171
- { heading: "Proof of Concept", body: parts.poc || "_See Steps to Reproduce._" },
9172
- { heading: "Remediation", body: parts.remediation },
9173
- { heading: "References", body: parts.references }
9174
- ];
9175
- return assembleReport("bugcrowd", parts, sections);
9176
- }
9177
- };
9178
- var INTIGRITI_TEMPLATE = {
9179
- id: "intigriti",
9180
- label: "Intigriti",
9181
- description: "Intigriti order: Summary \u2192 Domain/Endpoint \u2192 Vulnerability Type (CWE) \u2192 Impact \u2192 Steps \u2192 PoC \u2192 Severity (CVSS) \u2192 Recommended Fix.",
9182
- requiredSections: [
9183
- "Summary",
9184
- "Domain / Endpoint",
9185
- "Vulnerability Type",
9186
- "Impact",
9187
- "Steps to Reproduce",
9188
- "Proof of Concept",
9189
- "Severity",
9190
- "Recommended Fix"
9191
- ],
9192
- render(finding, ctx = {}) {
9193
- const parts = buildCommonParts(finding, ctx);
9194
- const primaryCwe = parts.cwes[0];
9195
- const sections = [
9196
- { heading: "Summary", body: parts.summary },
9197
- { heading: "Domain / Endpoint", body: parts.affected },
9198
- {
9199
- heading: "Vulnerability Type",
9200
- body: primaryCwe ? `${primaryCwe.id}: ${primaryCwe.name} (category: \`${finding.category}\`)` : `Category: \`${finding.category}\``
9201
- },
9202
- { heading: "Impact", body: parts.impact },
9203
- { heading: "Steps to Reproduce", body: stepsBodyOrPoc(parts) },
9204
- { heading: "Proof of Concept", body: parts.poc || "_See Steps to Reproduce._" },
9205
- { heading: "Severity", body: parts.severityCvss31 },
9206
- { heading: "Recommended Fix", body: parts.remediation },
9207
- { heading: "References", body: parts.references }
9208
- ];
9209
- return assembleReport("intigriti", parts, sections);
9210
- }
9211
- };
9212
- var IMMUNEFI_TEMPLATE = {
9213
- id: "immunefi",
9214
- label: "Immunefi (web3)",
9215
- description: "Immunefi web3 order: Bug Description \u2192 Impact (funds/assets at risk) \u2192 Impact-in-Detail \u2192 Attack Scenario \u2192 PoC \u2192 Affected Assets \u2192 Recommendation. Impact-based severity + CVSS 4.0.",
9216
- requiredSections: [
9217
- "Bug Description",
9218
- "Impact",
9219
- "Severity",
9220
- "Attack Scenario",
9221
- "Proof of Concept",
9222
- "Affected Assets",
9223
- "Recommendation"
9224
- ],
9225
- render(finding, ctx = {}) {
9226
- const parts = buildCommonParts(finding, ctx);
9227
- const sections = [
9228
- { heading: "Bug Description", body: parts.summary },
9229
- { heading: "Impact", body: parts.impact },
9230
- {
9231
- heading: "Severity",
9232
- body: `**${immunefiSeverity(finding.severity)}**
9233
-
9234
- ${parts.severityCvss40}
9235
-
9236
- ${parts.severityCvss31}`
9237
- },
9238
- {
9239
- heading: "Attack Scenario",
9240
- body: parts.attackScenario || stepsBodyOrPoc(parts)
9241
- },
9242
- {
9243
- heading: "Proof of Concept",
9244
- body: [parts.steps, parts.poc].filter(Boolean).join("\n\n") || "_Attach a runnable PoC / test before submission._"
9245
- },
9246
- { heading: "Affected Assets", body: parts.affected },
9247
- { heading: "Recommendation", body: parts.remediation },
9248
- { heading: "References", body: parts.references }
9249
- ];
9250
- return assembleReport("immunefi", parts, sections);
9251
- }
9252
- };
9253
- var GENERIC_TEMPLATE = {
9254
- id: "generic",
9255
- label: "Generic / Default",
9256
- description: "Platform-neutral, impact-first structure: Summary \u2192 Impact \u2192 Affected \u2192 Steps \u2192 PoC \u2192 Severity (CVSS) \u2192 Remediation \u2192 References.",
9257
- requiredSections: [
9258
- "Summary",
9259
- "Impact",
9260
- "Affected Assets",
9261
- "Steps to Reproduce",
9262
- "Proof of Concept",
9263
- "Severity",
9264
- "Remediation",
9265
- "References"
9266
- ],
9267
- render(finding, ctx = {}) {
9268
- const parts = buildCommonParts(finding, ctx);
9269
- const sections = [
9270
- { heading: "Summary", body: parts.summary },
9271
- { heading: "Impact", body: parts.impact },
9272
- { heading: "Affected Assets", body: parts.affected },
9273
- { heading: "Steps to Reproduce", body: stepsBodyOrPoc(parts) },
9274
- { heading: "Proof of Concept", body: parts.poc || "_See Steps to Reproduce._" },
9275
- { heading: "Severity", body: `${parts.severityCvss31}
9276
-
9277
- _${cvssSourceLabel(parts.cvss)}_` },
9278
- { heading: "Remediation", body: parts.remediation },
9279
- { heading: "References", body: parts.references }
9280
- ];
9281
- return assembleReport("generic", parts, sections);
9282
- }
9283
- };
9284
- function cvssSourceLabel(cvss) {
9285
- return cvss.source === "finding" ? "CVSS source: populated on the finding by 0sec." : cvss.source === "impact-assessment" ? "CVSS source: exploitability derived from 0sec's reachability assessment; impact from category \u2014 verify against your deployment." : "CVSS source: heuristic from category + severity \u2014 verify before submission.";
8025
+ function aggregateVerdict(graph, steps) {
8026
+ if (graph.length === 0) {
8027
+ return "could_not_run";
8028
+ }
8029
+ const byId = new Map(steps.map((s) => [s.stepId, s]));
8030
+ let reachedExploitOrVerify = false;
8031
+ for (const step of graph) {
8032
+ const result = byId.get(step.id);
8033
+ if (!result)
8034
+ continue;
8035
+ if (step.kind === "exploit" || step.kind === "verify") {
8036
+ reachedExploitOrVerify = true;
8037
+ }
8038
+ if (result.kind === "errored" && (step.kind === "setup" || step.kind === "auth" || step.kind === "prerequisite")) {
8039
+ return "could_not_run";
8040
+ }
8041
+ }
8042
+ const verifySteps = graph.filter((s) => s.kind === "verify");
8043
+ if (verifySteps.length > 0) {
8044
+ let anyFailed = false;
8045
+ let anyErrored = false;
8046
+ let allPassed = true;
8047
+ for (const v of verifySteps) {
8048
+ const result = byId.get(v.id);
8049
+ if (!result || result.kind === "skipped") {
8050
+ allPassed = false;
8051
+ anyErrored = true;
8052
+ continue;
8053
+ }
8054
+ if (result.kind === "failed") {
8055
+ anyFailed = true;
8056
+ allPassed = false;
8057
+ } else if (result.kind === "errored") {
8058
+ anyErrored = true;
8059
+ allPassed = false;
8060
+ }
8061
+ }
8062
+ if (allPassed)
8063
+ return "exploit_still_works";
8064
+ if (anyFailed)
8065
+ return "exploit_broken";
8066
+ if (anyErrored)
8067
+ return "could_not_run";
8068
+ }
8069
+ const exploitSteps = graph.filter((s) => s.kind === "exploit");
8070
+ if (exploitSteps.length > 0) {
8071
+ let anyFailed = false;
8072
+ let anyErrored = false;
8073
+ let allPassed = true;
8074
+ for (const e of exploitSteps) {
8075
+ const result = byId.get(e.id);
8076
+ if (!result || result.kind === "skipped") {
8077
+ allPassed = false;
8078
+ anyErrored = true;
8079
+ continue;
8080
+ }
8081
+ if (result.kind === "failed") {
8082
+ anyFailed = true;
8083
+ allPassed = false;
8084
+ } else if (result.kind === "errored") {
8085
+ anyErrored = true;
8086
+ allPassed = false;
8087
+ }
8088
+ }
8089
+ if (allPassed)
8090
+ return "exploit_still_works";
8091
+ if (anyFailed)
8092
+ return "exploit_broken";
8093
+ if (anyErrored)
8094
+ return "could_not_run";
8095
+ }
8096
+ return reachedExploitOrVerify ? "exploit_still_works" : "could_not_run";
9286
8097
  }
9287
- var TEMPLATE_REGISTRY = {
9288
- hackerone: HACKERONE_TEMPLATE,
9289
- bugcrowd: BUGCROWD_TEMPLATE,
9290
- intigriti: INTIGRITI_TEMPLATE,
9291
- immunefi: IMMUNEFI_TEMPLATE,
9292
- generic: GENERIC_TEMPLATE
9293
- };
9294
- var REPORT_PLATFORMS = Object.values(TEMPLATE_REGISTRY).map((t) => ({
9295
- id: t.id,
9296
- label: t.label,
9297
- description: t.description
9298
- }));
9299
- function reportTemplate(platform) {
9300
- if (platform && platform in TEMPLATE_REGISTRY) {
9301
- return TEMPLATE_REGISTRY[platform];
8098
+ function errMessage(err) {
8099
+ if (err instanceof Error)
8100
+ return err.message;
8101
+ if (typeof err === "string")
8102
+ return err;
8103
+ try {
8104
+ return JSON.stringify(err);
8105
+ } catch {
8106
+ return String(err);
9302
8107
  }
9303
- return GENERIC_TEMPLATE;
9304
- }
9305
- function renderPlatformReport(finding, platform, ctx = {}) {
9306
- return reportTemplate(platform).render(finding, ctx);
9307
8108
  }
9308
8109
 
9309
8110
  export {
@@ -9311,27 +8112,14 @@ export {
9311
8112
  hasKnownMarkerText,
9312
8113
  detectKnownMarkers,
9313
8114
  analyzeFindingForKnownMarkers,
9314
- suggestCwesForCategory,
9315
- formatCweSection,
9316
- suggestCvss,
9317
- Cvss4ParseError,
9318
- computeCvss4BaseScore,
9319
- cvss4Severity,
9320
- parseCvss4Vector,
9321
- formatCvss4Vector,
9322
- scoreCvss4Vector,
9323
- suggestCvss4,
9324
- renderCvssSection,
9325
- extractFileRefs,
9326
- verifyAgainstRef,
9327
- formatPatchStatusSection,
9328
- detectVersionRange,
9329
- formatVersionRangeLine,
9330
- EmptyPocError,
9331
- redactSensitiveHeaders,
9332
- redactAuthHeaders,
9333
- renderAdvisoryMarkdown,
9334
- REPORT_PLATFORMS,
9335
- reportTemplate,
9336
- renderPlatformReport
8115
+ MAX_CAPTURE_BYTES,
8116
+ DEFAULT_STEP_TIMEOUT_MS,
8117
+ acquireHostToken,
8118
+ markHostRateLimited,
8119
+ setRuntimeDeps,
8120
+ executePocSteps,
8121
+ resolveUrl,
8122
+ mergePersonaHeaders,
8123
+ evaluateExpect,
8124
+ aggregateVerdict
9337
8125
  };