0sec-cli 0.21.4 → 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.
- package/0.js +56 -56
- package/README.md +48 -63
- package/chunks/{adapt-loop-IGBRQAXO.js → adapt-loop-7I57LXXR.js} +4 -4
- package/chunks/{artifact-scraper-LNQJUORS.js → artifact-scraper-PYZ3RU3O.js} +2 -2
- package/chunks/{assumption-mining-4MJTP6H5.js → assumption-mining-MFLF43IR.js} +16 -16
- package/chunks/{chunk-Z3IKZX3X.js → chunk-23DG5YKS.js} +1 -1
- package/chunks/{chunk-BACXRTQ4.js → chunk-2GV4HQKE.js} +87 -767
- package/chunks/{chunk-QZVG3BG4.js → chunk-5IBCBQEH.js} +1 -2
- package/chunks/{chunk-NDJU5ZZ7.js → chunk-5MWAG3FT.js} +3 -3
- package/chunks/{chunk-PC6RCKQV.js → chunk-76KSBWOQ.js} +59 -26
- package/chunks/chunk-7DEHG7YT.js +2143 -0
- package/chunks/{chunk-CL5KAUM6.js → chunk-7UFUALR2.js} +274 -8
- package/chunks/{chunk-IMGWPNQM.js → chunk-CAYANSH6.js} +67 -574
- package/chunks/{chunk-P6YG6TEZ.js → chunk-DKSCN2AB.js} +1 -1
- package/chunks/{chunk-O6SD4A36.js → chunk-DM5C5L5D.js} +1 -1
- package/chunks/{chunk-FAH6V4QM.js → chunk-EGZGZFAH.js} +1116 -2291
- package/chunks/chunk-HR2TU42B.js +1228 -0
- package/chunks/{chunk-TF46UWFU.js → chunk-HUNAPTKV.js} +1 -1
- package/chunks/chunk-IO7R7WBM.js +114 -0
- package/chunks/{chunk-W4JOXE4N.js → chunk-IXT64DV5.js} +709 -1929
- package/chunks/{chunk-HBKCGJAV.js → chunk-LCRTAQN2.js} +1 -1
- package/chunks/{chunk-WPQLBN4S.js → chunk-LPTRPRZR.js} +1 -1
- package/chunks/{chunk-Y5H6E24H.js → chunk-LYUAM3TG.js} +1 -1
- package/chunks/{chunk-NOPBXZUV.js → chunk-MICHDTBK.js} +1 -1
- package/chunks/{chunk-CAJJRUTV.js → chunk-OAYUPGF6.js} +1 -1
- package/chunks/{chunk-FWAYJ2IV.js → chunk-OWLJYJ5O.js} +8 -8
- package/chunks/chunk-RE5EZDG2.js +5523 -0
- package/chunks/{chunk-RF5QGKLR.js → chunk-RRD4XXPU.js} +3 -3
- package/chunks/{chunk-2WSXFFJZ.js → chunk-RSIUX3RW.js} +2 -2
- package/chunks/{chunk-ANDKY54G.js → chunk-SJBCK2EI.js} +4019 -7299
- package/chunks/{chunk-G34QP2XW.js → chunk-TM74SSHC.js} +1 -1
- package/chunks/{chunk-VOAXLO4A.js → chunk-TO35Y326.js} +5 -721
- package/chunks/{chunk-SBMB4OL3.js → chunk-TZFIAMWZ.js} +62 -8
- package/chunks/chunk-UELXHK2Y.js +1950 -0
- package/chunks/{chunk-YHWWF4QY.js → chunk-UU7PQP6N.js} +3 -3
- package/chunks/{chunk-E2UOY5PJ.js → chunk-UV5QWZGE.js} +12 -70
- package/chunks/{chunk-YA4PUM4H.js → chunk-VMRRNRMR.js} +1 -1
- package/chunks/{chunk-WZISK5VC.js → chunk-VNRY6AWF.js} +53 -7
- package/chunks/{chunk-ER3SUMYJ.js → chunk-W6UWZFKL.js} +0 -195
- package/chunks/{chunk-5T6D5BVY.js → chunk-XFCTUKXR.js} +1 -1
- package/chunks/{chunk-YPOA3W4O.js → chunk-YIQSGNAA.js} +875 -108
- package/chunks/{codex-models-TYYV4JNN.js → codex-models-7TLJSY3L.js} +5 -3
- package/chunks/{commands-WF5RG4I2.js → commands-NEI7L3QA.js} +2151 -3642
- package/chunks/{db-U3WQZVAO.js → db-5AP3JB4W.js} +3 -3
- package/chunks/{disclose-67GZCDBO.js → disclose-LDNKAVRH.js} +10 -8
- package/chunks/{dist-F6X62TQK.js → dist-3FNZIBB4.js} +223 -192
- package/chunks/{dist-EVTN3UTT.js → dist-5YHYNLI3.js} +2 -2
- package/chunks/{dist-ACC3DZUZ.js → dist-DD4H6HMQ.js} +3 -1
- package/chunks/{eval-runner-SA6OUGHZ.js → eval-runner-43BO2C4T.js} +11 -11
- package/chunks/{exploit-agent-36Q7XQFP.js → exploit-agent-N4A5ELBK.js} +1 -1
- package/chunks/{exploit-autoclimb-J4OTSTZ6.js → exploit-autoclimb-N7P6KIF5.js} +1 -1
- package/chunks/{exploit-climb-PYEJDIC4.js → exploit-climb-WNEJUB5W.js} +2 -2
- package/chunks/fix-Z452M4EC.js +26 -0
- package/chunks/{harness-GDUMKGSE.js → harness-QJJJVSG4.js} +3 -3
- package/chunks/{hunt-scan-UDJSCISU.js → hunt-scan-K6D2V3PX.js} +14 -14
- package/chunks/{identity-JTIVJSV7.js → identity-62SVRW4H.js} +1 -1
- package/chunks/{kernel-primitive-F2IXUFAX.js → kernel-primitive-TKUACPKD.js} +2 -2
- package/chunks/{kernel-vm-runner-276LHIOV.js → kernel-vm-runner-RAAO2PGT.js} +2 -2
- package/chunks/{memsafety-scan-NHUOGTEX.js → memsafety-scan-FCPAXIZE.js} +2 -2
- package/chunks/{native-loop-3BSYVDUI.js → native-loop-2ZRJENZ3.js} +10 -10
- package/chunks/{npm-detectors-VIYJXKFQ.js → npm-detectors-Z2ZIQCN4.js} +2 -2
- package/chunks/orchestrate-2GWGNTBF.js +58 -0
- package/chunks/{process-PNMC36JI.js → process-N245QIQG.js} +1 -4
- package/chunks/{run-CBGE6DRQ.js → run-U3XU4CTC.js} +9940 -12572
- package/chunks/{runtime-PXO5G6UV.js → runtime-G75TEWQY.js} +4 -5
- package/chunks/{scope-NJHIDDTN.js → scope-WXI46UHJ.js} +4 -1
- package/chunks/{session-store-46WBZM22.js → session-store-27L3ZU73.js} +2 -2
- package/chunks/{variant-candidates-UH2WC2HA.js → variant-candidates-YWZORZMK.js} +3 -3
- package/chunks/{web-recon-prepass-SFXU44SS.js → web-recon-prepass-YVMFXCIK.js} +3 -3
- package/cli-path-traversal-fixture.js +352 -0
- package/dashboard/assets/bot-Bg1Tp9_d.js +1 -0
- package/dashboard/assets/dist-B_dDCPbu.js +1 -0
- package/dashboard/assets/findings-page-mayGhNx6.js +5 -0
- package/dashboard/assets/format--susmHX7.js +1 -0
- package/dashboard/assets/input-TuVPR3Zl.js +1 -0
- package/dashboard/assets/jsx-runtime-MGseXjj5.js +3 -0
- package/dashboard/assets/live-page-HWWHX99U.js +1 -0
- package/dashboard/assets/meta-tile-ckHo-w7k.js +1 -0
- package/dashboard/assets/operations-BxZ0OoXO.js +10 -0
- package/dashboard/assets/operations-app-D3d35rgo.js +46 -0
- package/dashboard/assets/overview-page-W_4IteEr.js +1 -0
- package/dashboard/assets/page-header-Bw9AJgBV.js +1 -0
- package/dashboard/assets/scans-page-CgzVXHnn.js +1 -0
- package/dashboard/assets/siren-KQj8QAnJ.js +1 -0
- package/dashboard/assets/table-8EDklulN.js +1 -0
- package/dashboard/assets/tabs-CFHPOwg8.js +1 -0
- package/dashboard/index.html +2 -3
- package/node_modules/node-addon-api/LICENSE.md +9 -0
- package/node_modules/node-addon-api/README.md +95 -0
- package/node_modules/node-addon-api/common.gypi +21 -0
- package/node_modules/node-addon-api/except.gypi +25 -0
- package/node_modules/node-addon-api/index.js +14 -0
- package/node_modules/node-addon-api/napi-inl.deprecated.h +186 -0
- package/node_modules/node-addon-api/napi-inl.h +7250 -0
- package/node_modules/node-addon-api/napi.h +3463 -0
- package/node_modules/node-addon-api/node_addon_api.gyp +42 -0
- package/node_modules/node-addon-api/node_api.gyp +9 -0
- package/node_modules/node-addon-api/noexcept.gypi +26 -0
- package/node_modules/node-addon-api/nothing.c +0 -0
- package/node_modules/node-addon-api/package-support.json +21 -0
- package/node_modules/node-addon-api/package.json +481 -0
- package/node_modules/node-addon-api/tools/README.md +73 -0
- package/node_modules/node-addon-api/tools/check-napi.js +99 -0
- package/node_modules/node-addon-api/tools/clang-format.js +71 -0
- package/node_modules/node-addon-api/tools/conversion.js +301 -0
- package/node_modules/node-gyp-build/LICENSE +21 -0
- package/node_modules/node-gyp-build/README.md +58 -0
- package/node_modules/node-gyp-build/SECURITY.md +5 -0
- package/node_modules/node-gyp-build/bin.js +84 -0
- package/node_modules/node-gyp-build/build-test.js +19 -0
- package/node_modules/node-gyp-build/index.js +6 -0
- package/node_modules/node-gyp-build/node-gyp-build.js +207 -0
- package/node_modules/node-gyp-build/optional.js +7 -0
- package/node_modules/node-gyp-build/package.json +43 -0
- package/node_modules/tree-sitter/LICENSE +21 -0
- package/node_modules/tree-sitter/README.md +90 -0
- package/node_modules/tree-sitter/binding.gyp +76 -0
- package/node_modules/tree-sitter/index.js +895 -0
- package/node_modules/tree-sitter/package.json +62 -0
- package/node_modules/tree-sitter/prebuilds/darwin-arm64/tree-sitter.node +0 -0
- package/node_modules/tree-sitter/prebuilds/darwin-x64/tree-sitter.node +0 -0
- package/node_modules/tree-sitter/prebuilds/linux-x64/tree-sitter.node +0 -0
- package/node_modules/tree-sitter/prebuilds/win32-x64/tree-sitter.node +0 -0
- package/node_modules/tree-sitter/src/addon_data.h +47 -0
- package/node_modules/tree-sitter/src/binding.cc +35 -0
- package/node_modules/tree-sitter/src/conversions.cc +140 -0
- package/node_modules/tree-sitter/src/conversions.h +22 -0
- package/node_modules/tree-sitter/src/language.cc +106 -0
- package/node_modules/tree-sitter/src/language.h +17 -0
- package/node_modules/tree-sitter/src/logger.cc +70 -0
- package/node_modules/tree-sitter/src/logger.h +19 -0
- package/node_modules/tree-sitter/src/lookaheaditerator.cc +122 -0
- package/node_modules/tree-sitter/src/lookaheaditerator.h +33 -0
- package/node_modules/tree-sitter/src/node.cc +1056 -0
- package/node_modules/tree-sitter/src/node.h +30 -0
- package/node_modules/tree-sitter/src/parser.cc +298 -0
- package/node_modules/tree-sitter/src/parser.h +35 -0
- package/node_modules/tree-sitter/src/query.cc +383 -0
- package/node_modules/tree-sitter/src/query.h +39 -0
- package/node_modules/tree-sitter/src/tree.cc +307 -0
- package/node_modules/tree-sitter/src/tree.h +45 -0
- package/node_modules/tree-sitter/src/tree_cursor.cc +213 -0
- package/node_modules/tree-sitter/src/tree_cursor.h +52 -0
- package/node_modules/tree-sitter/tree-sitter.d.ts +211 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/LICENSE +21 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/README.md +21 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/README.md +6 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/include/tree_sitter/api.h +1266 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/alloc.c +48 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/alloc.h +41 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/array.h +290 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/atomic.h +68 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/clock.h +146 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/error_costs.h +11 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/get_changed_ranges.c +501 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/get_changed_ranges.h +36 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/host.h +21 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/language.c +221 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/language.h +299 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/length.h +52 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/lexer.c +419 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/lexer.h +49 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/lib.c +14 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/node.c +774 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/parser.c +2151 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/parser.h +230 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/point.h +62 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/query.c +4134 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/reduce_action.h +34 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/reusable_node.h +95 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/stack.c +899 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/stack.h +133 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/subtree.c +1060 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/subtree.h +382 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/tree.c +165 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/tree.h +31 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/tree_cursor.c +714 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/tree_cursor.h +48 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/ICU_SHA +1 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/LICENSE +414 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/README.md +29 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/ptypes.h +1 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/umachine.h +448 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/urename.h +1 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/utf.h +1 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/utf16.h +733 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode/utf8.h +881 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/unicode.h +50 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm/stdlib-symbols.txt +23 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm/stdlib.c +109 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm/wasm-stdlib.h +1294 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm_store.c +1823 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/lib/src/wasm_store.h +31 -0
- package/node_modules/tree-sitter/vendor/tree-sitter/test/fixtures/grammars/.gitkeep +0 -0
- package/node_modules/tree-sitter-c/LICENSE +21 -0
- package/node_modules/tree-sitter-c/README.md +18 -0
- package/node_modules/tree-sitter-c/binding.gyp +20 -0
- package/node_modules/tree-sitter-c/bindings/node/binding.cc +20 -0
- package/node_modules/tree-sitter-c/bindings/node/index.d.ts +28 -0
- package/node_modules/tree-sitter-c/bindings/node/index.js +7 -0
- package/node_modules/tree-sitter-c/grammar.js +1463 -0
- package/node_modules/tree-sitter-c/package.json +108 -0
- package/node_modules/tree-sitter-c/prebuilds/darwin-arm64/tree-sitter-c.node +0 -0
- package/node_modules/tree-sitter-c/prebuilds/darwin-x64/tree-sitter-c.node +0 -0
- package/node_modules/tree-sitter-c/prebuilds/linux-x64/tree-sitter-c.node +0 -0
- package/node_modules/tree-sitter-c/prebuilds/win32-x64/tree-sitter-c.node +0 -0
- package/node_modules/tree-sitter-c/queries/highlights.scm +81 -0
- package/node_modules/tree-sitter-c/queries/tags.scm +9 -0
- package/node_modules/tree-sitter-c/src/grammar.json +9682 -0
- package/node_modules/tree-sitter-c/src/node-types.json +4556 -0
- package/node_modules/tree-sitter-c/src/parser.c +113852 -0
- package/node_modules/tree-sitter-c/src/tree_sitter/alloc.h +54 -0
- package/node_modules/tree-sitter-c/src/tree_sitter/array.h +290 -0
- package/node_modules/tree-sitter-c/src/tree_sitter/parser.h +265 -0
- package/package.json +10 -3
- package/vendor/tree-sitter-0.21.1-node24.json +16 -0
- package/vendor/tree-sitter-0.21.1-node24.tgz +0 -0
- package/chunks/chunk-CGHCEN7W.js +0 -169
- package/chunks/chunk-CXKDWFNO.js +0 -102
- package/chunks/chunk-GIQKESMN.js +0 -687
- package/chunks/chunk-HPQZHOIU.js +0 -67
- package/chunks/chunk-PD2BBBKT.js +0 -245
- package/chunks/chunk-WF5W75WY.js +0 -1070
- package/chunks/fix-J2KBRJDV.js +0 -12
- package/chunks/orchestrate-DHBFRTSI.js +0 -59
- package/chunks/replay-runner-LK2XFIVG.js +0 -39
- package/dashboard/assets/bot-yILPnRgD.js +0 -1
- package/dashboard/assets/chevron-down-BeDJ-Vka.js +0 -1
- package/dashboard/assets/circle-alert-BEnMBMT-.js +0 -1
- package/dashboard/assets/client-DRYsuOGl.js +0 -9
- package/dashboard/assets/copy-Bi5vzoF9.js +0 -1
- package/dashboard/assets/desktop-BT7RkC4q.js +0 -32
- package/dashboard/assets/desktop-OaBI0E0e.css +0 -1
- package/dashboard/assets/dist-CmX-h7a4.js +0 -1
- package/dashboard/assets/dist-DAwYQmf_.js +0 -45
- package/dashboard/assets/findings-page-B4rwF6fZ.js +0 -5
- package/dashboard/assets/format-LNQSSpn6.js +0 -1
- package/dashboard/assets/jsx-runtime-C7oxC63R.js +0 -1
- package/dashboard/assets/live-page-DoNwpPAO.js +0 -1
- package/dashboard/assets/meta-tile-BMtBC-Qq.js +0 -1
- package/dashboard/assets/operations-app-ER0gg7GN.js +0 -2
- package/dashboard/assets/operations-e2CGYKB1.js +0 -4
- package/dashboard/assets/overview-page-CmeWH17A.js +0 -1
- package/dashboard/assets/page-header-CIJyycfz.js +0 -1
- package/dashboard/assets/play-Dwo-9xt6.js +0 -1
- package/dashboard/assets/scans-page-CuhzWhHx.js +0 -1
- package/dashboard/assets/search-CiooTLck.js +0 -1
- package/dashboard/assets/siren-CCBwTSuk.js +0 -1
- package/dashboard/assets/table-BgsSBdke.js +0 -1
- package/dashboard/assets/tabs-vn6v7Bk6.js +0 -1
- package/dashboard/desktop.html +0 -21
|
@@ -7333,2013 +7333,793 @@ var require_dist = __commonJS({
|
|
|
7333
7333
|
}
|
|
7334
7334
|
});
|
|
7335
7335
|
|
|
7336
|
-
// packages/core/dist/disclose/
|
|
7337
|
-
var
|
|
7338
|
-
|
|
7339
|
-
|
|
7340
|
-
|
|
7341
|
-
|
|
7342
|
-
|
|
7343
|
-
],
|
|
7344
|
-
"jailbreak": [
|
|
7345
|
-
{ id: "CWE-1039", name: "Inadequate Detection or Handling of Adversarial Input Perturbations in AI/ML Classifier", role: "primary" },
|
|
7346
|
-
{ id: "CWE-284", name: "Improper Access Control", role: "secondary" }
|
|
7347
|
-
],
|
|
7348
|
-
"system-prompt-extraction": [
|
|
7349
|
-
{ id: "CWE-200", name: "Exposure of Sensitive Information to an Unauthorized Actor", role: "primary" },
|
|
7350
|
-
{ id: "CWE-1039", name: "Inadequate Detection or Handling of Adversarial Input Perturbations in AI/ML Classifier", role: "secondary" }
|
|
7351
|
-
],
|
|
7352
|
-
"data-exfiltration": [
|
|
7353
|
-
{ id: "CWE-200", name: "Exposure of Sensitive Information to an Unauthorized Actor", role: "primary" },
|
|
7354
|
-
{ id: "CWE-522", name: "Insufficiently Protected Credentials", role: "secondary" }
|
|
7355
|
-
],
|
|
7356
|
-
"tool-misuse": [
|
|
7357
|
-
{ id: "CWE-284", name: "Improper Access Control", role: "primary" },
|
|
7358
|
-
{ id: "CWE-441", name: "Unintended Proxy or Intermediary ('Confused Deputy')", role: "secondary" },
|
|
7359
|
-
{ id: "CWE-285", name: "Improper Authorization", role: "secondary" }
|
|
7360
|
-
],
|
|
7361
|
-
"output-manipulation": [
|
|
7362
|
-
{ id: "CWE-116", name: "Improper Encoding or Escaping of Output", role: "primary" },
|
|
7363
|
-
{ id: "CWE-74", name: "Improper Neutralization of Special Elements in Output Used by a Downstream Component ('Injection')", role: "secondary" }
|
|
7364
|
-
],
|
|
7365
|
-
"encoding-bypass": [
|
|
7366
|
-
{ id: "CWE-176", name: "Improper Handling of Unicode Encoding", role: "primary" },
|
|
7367
|
-
{ id: "CWE-20", name: "Improper Input Validation", role: "secondary" }
|
|
7368
|
-
],
|
|
7369
|
-
"multi-turn": [
|
|
7370
|
-
{ id: "CWE-1039", name: "Inadequate Detection or Handling of Adversarial Input Perturbations in AI/ML Classifier", role: "primary" },
|
|
7371
|
-
{ id: "CWE-841", name: "Improper Enforcement of Behavioral Workflow", role: "secondary" }
|
|
7372
|
-
],
|
|
7373
|
-
// Source-code audit
|
|
7374
|
-
"prototype-pollution": [
|
|
7375
|
-
{ id: "CWE-1321", name: "Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution')", role: "primary" },
|
|
7376
|
-
{ id: "CWE-915", name: "Improperly Controlled Modification of Dynamically-Determined Object Attributes", role: "secondary" }
|
|
7377
|
-
],
|
|
7378
|
-
"path-traversal": [
|
|
7379
|
-
{ id: "CWE-22", name: "Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')", role: "primary" },
|
|
7380
|
-
{ id: "CWE-73", name: "External Control of File Name or Path", role: "secondary" },
|
|
7381
|
-
{ id: "CWE-284", name: "Improper Access Control", role: "secondary" }
|
|
7382
|
-
],
|
|
7383
|
-
"command-injection": [
|
|
7384
|
-
{ id: "CWE-78", name: "Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')", role: "primary" },
|
|
7385
|
-
{ id: "CWE-77", name: "Improper Neutralization of Special Elements used in a Command ('Command Injection')", role: "secondary" }
|
|
7386
|
-
],
|
|
7387
|
-
"code-injection": [
|
|
7388
|
-
{ id: "CWE-94", name: "Improper Control of Generation of Code ('Code Injection')", role: "primary" },
|
|
7389
|
-
{ id: "CWE-95", name: "Improper Neutralization of Directives in Dynamically Evaluated Code ('Eval Injection')", role: "secondary" }
|
|
7390
|
-
],
|
|
7391
|
-
"regex-dos": [
|
|
7392
|
-
{ id: "CWE-1333", name: "Inefficient Regular Expression Complexity", role: "primary" },
|
|
7393
|
-
{ id: "CWE-400", name: "Uncontrolled Resource Consumption", role: "secondary" }
|
|
7394
|
-
],
|
|
7395
|
-
"unsafe-deserialization": [
|
|
7396
|
-
{ id: "CWE-502", name: "Deserialization of Untrusted Data", role: "primary" },
|
|
7397
|
-
{ id: "CWE-915", name: "Improperly Controlled Modification of Dynamically-Determined Object Attributes", role: "secondary" }
|
|
7398
|
-
],
|
|
7399
|
-
"information-disclosure": [
|
|
7400
|
-
{ id: "CWE-200", name: "Exposure of Sensitive Information to an Unauthorized Actor", role: "primary" },
|
|
7401
|
-
{ id: "CWE-285", name: "Improper Authorization", role: "secondary" },
|
|
7402
|
-
{ id: "CWE-522", name: "Insufficiently Protected Credentials", role: "secondary" }
|
|
7403
|
-
],
|
|
7404
|
-
"ssrf": [
|
|
7405
|
-
{ id: "CWE-918", name: "Server-Side Request Forgery (SSRF)", role: "primary" },
|
|
7406
|
-
{ id: "CWE-20", name: "Improper Input Validation", role: "secondary" },
|
|
7407
|
-
{ id: "CWE-441", name: "Unintended Proxy or Intermediary ('Confused Deputy')", role: "secondary" }
|
|
7408
|
-
],
|
|
7409
|
-
"sql-injection": [
|
|
7410
|
-
{ id: "CWE-89", name: "Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')", role: "primary" }
|
|
7411
|
-
],
|
|
7412
|
-
"xss": [
|
|
7413
|
-
{ id: "CWE-79", name: "Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')", role: "primary" },
|
|
7414
|
-
{ id: "CWE-80", name: "Improper Neutralization of Script-Related HTML Tags in a Web Page (Basic XSS)", role: "secondary" }
|
|
7415
|
-
],
|
|
7416
|
-
"cors": [
|
|
7417
|
-
{ id: "CWE-942", name: "Permissive Cross-domain Policy with Untrusted Domains", role: "primary" },
|
|
7418
|
-
{ id: "CWE-346", name: "Origin Validation Error", role: "secondary" }
|
|
7419
|
-
],
|
|
7420
|
-
"security-misconfiguration": [
|
|
7421
|
-
{ id: "CWE-1188", name: "Initialization of a Resource with an Insecure Default", role: "primary" },
|
|
7422
|
-
{ id: "CWE-16", name: "Configuration", role: "secondary" }
|
|
7423
|
-
],
|
|
7424
|
-
"missing-validation": [
|
|
7425
|
-
{ id: "CWE-20", name: "Improper Input Validation", role: "primary" }
|
|
7426
|
-
],
|
|
7427
|
-
"crypto-misuse": [
|
|
7428
|
-
{ id: "CWE-327", name: "Use of a Broken or Risky Cryptographic Algorithm", role: "primary" },
|
|
7429
|
-
{ id: "CWE-328", name: "Use of Weak Hash", role: "secondary" },
|
|
7430
|
-
{ id: "CWE-321", name: "Use of Hard-coded Cryptographic Key", role: "secondary" },
|
|
7431
|
-
{ id: "CWE-329", name: "Generation of Predictable IV with CBC Mode", role: "secondary" },
|
|
7432
|
-
{ id: "CWE-330", name: "Use of Insufficiently Random Values", role: "secondary" },
|
|
7433
|
-
{ id: "CWE-347", name: "Improper Verification of Cryptographic Signature", role: "secondary" }
|
|
7434
|
-
],
|
|
7435
|
-
// Memory corruption / binary
|
|
7436
|
-
"heap-overflow": [
|
|
7437
|
-
{ id: "CWE-122", name: "Heap-based Buffer Overflow", role: "primary" },
|
|
7438
|
-
{ id: "CWE-787", name: "Out-of-bounds Write", role: "secondary" }
|
|
7439
|
-
],
|
|
7440
|
-
"out-of-bounds-read": [
|
|
7441
|
-
{ id: "CWE-125", name: "Out-of-bounds Read", role: "primary" }
|
|
7442
|
-
],
|
|
7443
|
-
"out-of-bounds-write": [
|
|
7444
|
-
{ id: "CWE-787", name: "Out-of-bounds Write", role: "primary" },
|
|
7445
|
-
{ id: "CWE-122", name: "Heap-based Buffer Overflow", role: "secondary" }
|
|
7446
|
-
],
|
|
7447
|
-
"use-after-free": [
|
|
7448
|
-
{ id: "CWE-416", name: "Use After Free", role: "primary" },
|
|
7449
|
-
{ id: "CWE-672", name: "Operation on a Resource after Expiration or Release", role: "secondary" }
|
|
7450
|
-
],
|
|
7451
|
-
"stack-buffer-overflow": [
|
|
7452
|
-
{ id: "CWE-121", name: "Stack-based Buffer Overflow", role: "primary" },
|
|
7453
|
-
{ id: "CWE-787", name: "Out-of-bounds Write", role: "secondary" }
|
|
7454
|
-
],
|
|
7455
|
-
"null-pointer-deref": [
|
|
7456
|
-
{ id: "CWE-476", name: "NULL Pointer Dereference", role: "primary" }
|
|
7457
|
-
],
|
|
7458
|
-
"null-deref": [
|
|
7459
|
-
{ id: "CWE-476", name: "NULL Pointer Dereference", role: "primary" }
|
|
7460
|
-
],
|
|
7461
|
-
"integer-overflow": [
|
|
7462
|
-
{ id: "CWE-190", name: "Integer Overflow or Wraparound", role: "primary" },
|
|
7463
|
-
{ id: "CWE-191", name: "Integer Underflow (Wrap or Wraparound)", role: "secondary" }
|
|
7464
|
-
],
|
|
7465
|
-
"integer-truncation": [
|
|
7466
|
-
{ id: "CWE-197", name: "Numeric Truncation Error", role: "primary" },
|
|
7467
|
-
{ id: "CWE-681", name: "Incorrect Conversion between Numeric Types", role: "secondary" }
|
|
7468
|
-
],
|
|
7469
|
-
"denial-of-service": [
|
|
7470
|
-
{ id: "CWE-400", name: "Uncontrolled Resource Consumption", role: "primary" },
|
|
7471
|
-
{ id: "CWE-833", name: "Deadlock", role: "secondary" }
|
|
7472
|
-
],
|
|
7473
|
-
"race-condition": [
|
|
7474
|
-
{ id: "CWE-362", name: "Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')", role: "primary" },
|
|
7475
|
-
{ id: "CWE-367", name: "Time-of-check Time-of-use (TOCTOU) Race Condition", role: "secondary" }
|
|
7476
|
-
],
|
|
7477
|
-
"toctou": [
|
|
7478
|
-
{ id: "CWE-367", name: "Time-of-check Time-of-use (TOCTOU) Race Condition", role: "primary" },
|
|
7479
|
-
{ id: "CWE-362", name: "Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')", role: "secondary" }
|
|
7480
|
-
],
|
|
7481
|
-
"type-confusion": [
|
|
7482
|
-
{ id: "CWE-843", name: "Access of Resource Using Incompatible Type ('Type Confusion')", role: "primary" }
|
|
7483
|
-
],
|
|
7484
|
-
"double-free": [
|
|
7485
|
-
{ id: "CWE-415", name: "Double Free", role: "primary" }
|
|
7486
|
-
],
|
|
7487
|
-
"format-string": [
|
|
7488
|
-
{ id: "CWE-134", name: "Use of Externally-Controlled Format String", role: "primary" }
|
|
7489
|
-
],
|
|
7490
|
-
"uninitialized-memory": [
|
|
7491
|
-
{ id: "CWE-457", name: "Use of Uninitialized Variable", role: "primary" },
|
|
7492
|
-
{ id: "CWE-908", name: "Use of Uninitialized Resource", role: "secondary" }
|
|
7493
|
-
],
|
|
7494
|
-
// Supply-chain / package
|
|
7495
|
-
"known-vulnerable-package": [
|
|
7496
|
-
{ id: "CWE-1395", name: "Dependency on Vulnerable Third-Party Component", role: "primary" },
|
|
7497
|
-
{ id: "CWE-1104", name: "Use of Unmaintained Third Party Components", role: "secondary" },
|
|
7498
|
-
{ id: "CWE-937", name: "OWASP Top Ten 2013 Category A9 - Using Components with Known Vulnerabilities", role: "secondary" }
|
|
7499
|
-
],
|
|
7500
|
-
"supply-chain": [
|
|
7501
|
-
{ id: "CWE-1357", name: "Reliance on Insufficiently Trustworthy Component", role: "primary" },
|
|
7502
|
-
{ id: "CWE-506", name: "Embedded Malicious Code", role: "secondary" },
|
|
7503
|
-
{ id: "CWE-829", name: "Inclusion of Functionality from Untrusted Control Sphere", role: "secondary" }
|
|
7504
|
-
],
|
|
7505
|
-
"other": [
|
|
7506
|
-
{ id: "CWE-693", name: "Protection Mechanism Failure", role: "primary" }
|
|
7507
|
-
]
|
|
7508
|
-
};
|
|
7509
|
-
function suggestCwesForCategory(category) {
|
|
7510
|
-
return CWE_MAP[category] ?? [
|
|
7511
|
-
{ id: "CWE-693", name: "Protection Mechanism Failure", role: "primary" }
|
|
7512
|
-
];
|
|
7336
|
+
// packages/core/dist/disclose/known-marker.js
|
|
7337
|
+
var SOURCE_MARKER_RE = /\b(TODO|FIXME|XXX|HACK)\b(?:[(:]\s*(.*?)\s*[):])?|(\bknown[ -](?:limitation|issue)s?\b|\bdocumented[ -]limitation\b)/gi;
|
|
7338
|
+
function hasKnownMarkerText(source) {
|
|
7339
|
+
SOURCE_MARKER_RE.lastIndex = 0;
|
|
7340
|
+
const matched = SOURCE_MARKER_RE.test(source);
|
|
7341
|
+
SOURCE_MARKER_RE.lastIndex = 0;
|
|
7342
|
+
return matched;
|
|
7513
7343
|
}
|
|
7514
|
-
function
|
|
7515
|
-
|
|
7516
|
-
|
|
7517
|
-
|
|
7518
|
-
|
|
7519
|
-
|
|
7520
|
-
|
|
7521
|
-
|
|
7522
|
-
|
|
7344
|
+
function detectKnownMarkers(source, filePath) {
|
|
7345
|
+
const lines = source.split("\n");
|
|
7346
|
+
const markers = [];
|
|
7347
|
+
for (let i = 0; i < lines.length; i++) {
|
|
7348
|
+
const line = lines[i];
|
|
7349
|
+
SOURCE_MARKER_RE.lastIndex = 0;
|
|
7350
|
+
let match;
|
|
7351
|
+
while ((match = SOURCE_MARKER_RE.exec(line)) !== null) {
|
|
7352
|
+
const tag = match[1];
|
|
7353
|
+
const phrase = match[3];
|
|
7354
|
+
const markerText = tag ?? phrase ?? match[0];
|
|
7355
|
+
const contextLines = [];
|
|
7356
|
+
if (i > 0)
|
|
7357
|
+
contextLines.push(lines[i - 1]);
|
|
7358
|
+
contextLines.push(line);
|
|
7359
|
+
if (i < lines.length - 1)
|
|
7360
|
+
contextLines.push(lines[i + 1]);
|
|
7361
|
+
markers.push({
|
|
7362
|
+
marker: markerText.toLowerCase(),
|
|
7363
|
+
line: line.length > 200 ? line.slice(0, 100) + "..." + line.slice(line.length - 97) : line,
|
|
7364
|
+
lineNumber: i + 1,
|
|
7365
|
+
sourcePath: filePath,
|
|
7366
|
+
context: contextLines.join("\n")
|
|
7367
|
+
});
|
|
7368
|
+
}
|
|
7523
7369
|
}
|
|
7524
|
-
return
|
|
7525
|
-
|
|
7526
|
-
|
|
7527
|
-
|
|
7528
|
-
var IMPACT_BY_CATEGORY = {
|
|
7529
|
-
"prompt-injection": { C: "L", I: "L", A: "N", scope: "U" },
|
|
7530
|
-
"jailbreak": { C: "L", I: "L", A: "N", scope: "U" },
|
|
7531
|
-
"system-prompt-extraction": { C: "H", I: "N", A: "N", scope: "U" },
|
|
7532
|
-
"data-exfiltration": { C: "H", I: "N", A: "N", scope: "C" },
|
|
7533
|
-
"tool-misuse": { C: "H", I: "H", A: "L", scope: "C" },
|
|
7534
|
-
"output-manipulation": { C: "L", I: "H", A: "N", scope: "U" },
|
|
7535
|
-
"encoding-bypass": { C: "L", I: "L", A: "N", scope: "U" },
|
|
7536
|
-
"multi-turn": { C: "L", I: "L", A: "N", scope: "U" },
|
|
7537
|
-
"prototype-pollution": { C: "H", I: "H", A: "H", scope: "U" },
|
|
7538
|
-
"path-traversal": { C: "H", I: "H", A: "L", scope: "U" },
|
|
7539
|
-
"command-injection": { C: "H", I: "H", A: "H", scope: "U" },
|
|
7540
|
-
"code-injection": { C: "H", I: "H", A: "H", scope: "U" },
|
|
7541
|
-
"regex-dos": { C: "N", I: "N", A: "H", scope: "U" },
|
|
7542
|
-
"unsafe-deserialization": { C: "H", I: "H", A: "H", scope: "U" },
|
|
7543
|
-
"information-disclosure": { C: "H", I: "N", A: "N", scope: "C" },
|
|
7544
|
-
"ssrf": { C: "H", I: "N", A: "N", scope: "C" },
|
|
7545
|
-
"sql-injection": { C: "H", I: "H", A: "H", scope: "U" },
|
|
7546
|
-
"xss": { C: "L", I: "L", A: "N", scope: "C" },
|
|
7547
|
-
"cors": { C: "L", I: "L", A: "N", scope: "U" },
|
|
7548
|
-
"security-misconfiguration": { C: "L", I: "L", A: "N", scope: "U" },
|
|
7549
|
-
"missing-validation": { C: "L", I: "L", A: "L", scope: "U" },
|
|
7550
|
-
"crypto-misuse": { C: "H", I: "H", A: "N", scope: "U" },
|
|
7551
|
-
"heap-overflow": { C: "H", I: "H", A: "H", scope: "U" },
|
|
7552
|
-
"out-of-bounds-read": { C: "H", I: "N", A: "L", scope: "U" },
|
|
7553
|
-
"out-of-bounds-write": { C: "H", I: "H", A: "H", scope: "U" },
|
|
7554
|
-
"use-after-free": { C: "H", I: "H", A: "H", scope: "U" },
|
|
7555
|
-
"stack-buffer-overflow": { C: "H", I: "H", A: "H", scope: "U" },
|
|
7556
|
-
"null-pointer-deref": { C: "N", I: "N", A: "H", scope: "U" },
|
|
7557
|
-
"null-deref": { C: "N", I: "N", A: "H", scope: "U" },
|
|
7558
|
-
"integer-overflow": { C: "L", I: "L", A: "L", scope: "U" },
|
|
7559
|
-
"integer-truncation": { C: "L", I: "L", A: "L", scope: "U" },
|
|
7560
|
-
"race-condition": { C: "L", I: "L", A: "L", scope: "U" },
|
|
7561
|
-
"denial-of-service": { C: "N", I: "N", A: "H", scope: "U" },
|
|
7562
|
-
"toctou": { C: "L", I: "L", A: "L", scope: "U" },
|
|
7563
|
-
"type-confusion": { C: "H", I: "H", A: "H", scope: "U" },
|
|
7564
|
-
"double-free": { C: "H", I: "H", A: "H", scope: "U" },
|
|
7565
|
-
"format-string": { C: "H", I: "H", A: "H", scope: "U" },
|
|
7566
|
-
"uninitialized-memory": { C: "H", I: "N", A: "L", scope: "U" },
|
|
7567
|
-
"known-vulnerable-package": { C: "L", I: "L", A: "L", scope: "U" },
|
|
7568
|
-
"supply-chain": { C: "H", I: "H", A: "H", scope: "C" },
|
|
7569
|
-
"other": { C: "L", I: "L", A: "L", scope: "U" }
|
|
7570
|
-
};
|
|
7571
|
-
var W = {
|
|
7572
|
-
AV: { N: 0.85, A: 0.62, L: 0.55, P: 0.2 },
|
|
7573
|
-
AC: { L: 0.77, H: 0.44 },
|
|
7574
|
-
PR_U: { N: 0.85, L: 0.62, H: 0.27 },
|
|
7575
|
-
PR_C: { N: 0.85, L: 0.68, H: 0.5 },
|
|
7576
|
-
UI: { N: 0.85, R: 0.62 },
|
|
7577
|
-
CIA: { N: 0, L: 0.22, H: 0.56 }
|
|
7578
|
-
};
|
|
7579
|
-
function roundUp(n) {
|
|
7580
|
-
return Math.ceil(n * 10) / 10;
|
|
7581
|
-
}
|
|
7582
|
-
function computeBaseScore(av, ac, pr, ui, scope, c, i, a) {
|
|
7583
|
-
const iss = 1 - (1 - W.CIA[c]) * (1 - W.CIA[i]) * (1 - W.CIA[a]);
|
|
7584
|
-
const impact = scope === "U" ? 6.42 * iss : 7.52 * (iss - 0.029) - 3.25 * Math.pow(iss - 0.02, 15);
|
|
7585
|
-
const prWeight = (scope === "C" ? W.PR_C : W.PR_U)[pr];
|
|
7586
|
-
const exploit = 8.22 * W.AV[av] * W.AC[ac] * prWeight * W.UI[ui];
|
|
7587
|
-
if (impact <= 0)
|
|
7588
|
-
return 0;
|
|
7589
|
-
const base = scope === "U" ? Math.min(impact + exploit, 10) : Math.min(1.08 * (impact + exploit), 10);
|
|
7590
|
-
return roundUp(base);
|
|
7370
|
+
return {
|
|
7371
|
+
hasKnownMarker: markers.length > 0,
|
|
7372
|
+
markers
|
|
7373
|
+
};
|
|
7591
7374
|
}
|
|
7592
|
-
function
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
|
|
7599
|
-
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7375
|
+
function analyzeFindingForKnownMarkers(finding) {
|
|
7376
|
+
const texts = [];
|
|
7377
|
+
if (finding.evidence?.analysis)
|
|
7378
|
+
texts.push(finding.evidence.analysis);
|
|
7379
|
+
if (finding.description)
|
|
7380
|
+
texts.push(finding.description);
|
|
7381
|
+
if (finding.evidence?.request)
|
|
7382
|
+
texts.push(finding.evidence.request);
|
|
7383
|
+
if (finding.evidence?.response)
|
|
7384
|
+
texts.push(finding.evidence.response);
|
|
7385
|
+
const allMarkers = [];
|
|
7386
|
+
for (const text of texts) {
|
|
7387
|
+
const signal = detectKnownMarkers(text);
|
|
7388
|
+
allMarkers.push(...signal.markers);
|
|
7603
7389
|
}
|
|
7390
|
+
return {
|
|
7391
|
+
hasKnownMarker: allMarkers.length > 0,
|
|
7392
|
+
markers: allMarkers
|
|
7393
|
+
};
|
|
7604
7394
|
}
|
|
7605
|
-
|
|
7606
|
-
|
|
7607
|
-
|
|
7608
|
-
|
|
7609
|
-
|
|
7610
|
-
|
|
7611
|
-
|
|
7612
|
-
|
|
7613
|
-
|
|
7614
|
-
|
|
7615
|
-
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
|
|
7619
|
-
|
|
7620
|
-
|
|
7395
|
+
|
|
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);
|
|
7621
7417
|
}
|
|
7418
|
+
return bucket;
|
|
7622
7419
|
}
|
|
7623
|
-
function
|
|
7624
|
-
|
|
7625
|
-
|
|
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;
|
|
7626
7426
|
}
|
|
7627
|
-
const impact = IMPACT_BY_CATEGORY[finding.category] ?? { C: "L", I: "L", A: "L", scope: "U" };
|
|
7628
|
-
const ac = "L";
|
|
7629
|
-
const assessed = finding.impactAssessment ? metricsForReachability(finding.impactAssessment.reachability_tier) : void 0;
|
|
7630
|
-
const av = assessed?.av ?? "N";
|
|
7631
|
-
const pr = assessed?.pr ?? prForSeverity(finding.severity);
|
|
7632
|
-
const ui = assessed?.ui ?? "N";
|
|
7633
|
-
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}`;
|
|
7634
|
-
const score = computeBaseScore(av, ac, pr, ui, impact.scope, impact.C, impact.I, impact.A);
|
|
7635
|
-
return { vector, score, source: assessed ? "impact-assessment" : "heuristic" };
|
|
7636
7427
|
}
|
|
7637
|
-
|
|
7638
|
-
|
|
7639
|
-
|
|
7640
|
-
|
|
7641
|
-
|
|
7642
|
-
}
|
|
7643
|
-
|
|
7644
|
-
|
|
7645
|
-
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
|
|
7650
|
-
|
|
7651
|
-
|
|
7652
|
-
SC: /* @__PURE__ */ new Set(["H", "L", "N"]),
|
|
7653
|
-
SI: /* @__PURE__ */ new Set(["H", "L", "N"]),
|
|
7654
|
-
SA: /* @__PURE__ */ new Set(["H", "L", "N"]),
|
|
7655
|
-
// Threat
|
|
7656
|
-
E: /* @__PURE__ */ new Set(["X", "A", "P", "U"]),
|
|
7657
|
-
// Environmental (requirements)
|
|
7658
|
-
CR: /* @__PURE__ */ new Set(["X", "H", "M", "L"]),
|
|
7659
|
-
IR: /* @__PURE__ */ new Set(["X", "H", "M", "L"]),
|
|
7660
|
-
AR: /* @__PURE__ */ new Set(["X", "H", "M", "L"]),
|
|
7661
|
-
// Environmental (modified base)
|
|
7662
|
-
MAV: /* @__PURE__ */ new Set(["X", "N", "A", "L", "P"]),
|
|
7663
|
-
MAC: /* @__PURE__ */ new Set(["X", "L", "H"]),
|
|
7664
|
-
MAT: /* @__PURE__ */ new Set(["X", "N", "P"]),
|
|
7665
|
-
MPR: /* @__PURE__ */ new Set(["X", "N", "L", "H"]),
|
|
7666
|
-
MUI: /* @__PURE__ */ new Set(["X", "N", "P", "A"]),
|
|
7667
|
-
MVC: /* @__PURE__ */ new Set(["X", "H", "L", "N"]),
|
|
7668
|
-
MVI: /* @__PURE__ */ new Set(["X", "H", "L", "N"]),
|
|
7669
|
-
MVA: /* @__PURE__ */ new Set(["X", "H", "L", "N"]),
|
|
7670
|
-
MSC: /* @__PURE__ */ new Set(["X", "H", "L", "N"]),
|
|
7671
|
-
MSI: /* @__PURE__ */ new Set(["X", "S", "H", "L", "N"]),
|
|
7672
|
-
MSA: /* @__PURE__ */ new Set(["X", "S", "H", "L", "N"]),
|
|
7673
|
-
// Supplemental (do not affect score)
|
|
7674
|
-
S: /* @__PURE__ */ new Set(["X", "N", "P"]),
|
|
7675
|
-
AU: /* @__PURE__ */ new Set(["X", "N", "Y"]),
|
|
7676
|
-
R: /* @__PURE__ */ new Set(["X", "A", "U", "I"]),
|
|
7677
|
-
V: /* @__PURE__ */ new Set(["X", "D", "C"]),
|
|
7678
|
-
RE: /* @__PURE__ */ new Set(["X", "L", "M", "H"]),
|
|
7679
|
-
U: /* @__PURE__ */ new Set(["X", "Clear", "Green", "Amber", "Red"])
|
|
7680
|
-
};
|
|
7681
|
-
var CVSS4_BASE_KEYS = [
|
|
7682
|
-
"AV",
|
|
7683
|
-
"AC",
|
|
7684
|
-
"AT",
|
|
7685
|
-
"PR",
|
|
7686
|
-
"UI",
|
|
7687
|
-
"VC",
|
|
7688
|
-
"VI",
|
|
7689
|
-
"VA",
|
|
7690
|
-
"SC",
|
|
7691
|
-
"SI",
|
|
7692
|
-
"SA"
|
|
7693
|
-
];
|
|
7694
|
-
var AV_levels = { N: 0, A: 0.1, L: 0.2, P: 0.3 };
|
|
7695
|
-
var PR_levels = { N: 0, L: 0.1, H: 0.2 };
|
|
7696
|
-
var UI_levels = { N: 0, P: 0.1, A: 0.2 };
|
|
7697
|
-
var AC_levels = { L: 0, H: 0.1 };
|
|
7698
|
-
var AT_levels = { N: 0, P: 0.1 };
|
|
7699
|
-
var VC_levels = { H: 0, L: 0.1, N: 0.2 };
|
|
7700
|
-
var VI_levels = { H: 0, L: 0.1, N: 0.2 };
|
|
7701
|
-
var VA_levels = { H: 0, L: 0.1, N: 0.2 };
|
|
7702
|
-
var SC_levels = { H: 0.1, L: 0.2, N: 0.3 };
|
|
7703
|
-
var SI_levels = { S: 0, H: 0.1, L: 0.2, N: 0.3 };
|
|
7704
|
-
var SA_levels = { S: 0, H: 0.1, L: 0.2, N: 0.3 };
|
|
7705
|
-
var CR_levels = { H: 0, M: 0.1, L: 0.2 };
|
|
7706
|
-
var IR_levels = { H: 0, M: 0.1, L: 0.2 };
|
|
7707
|
-
var AR_levels = { H: 0, M: 0.1, L: 0.2 };
|
|
7708
|
-
var CVSS40_LOOKUP = {
|
|
7709
|
-
"000000": 10,
|
|
7710
|
-
"000001": 9.9,
|
|
7711
|
-
"000010": 9.8,
|
|
7712
|
-
"000011": 9.5,
|
|
7713
|
-
"000020": 9.5,
|
|
7714
|
-
"000021": 9.2,
|
|
7715
|
-
"000100": 10,
|
|
7716
|
-
"000101": 9.6,
|
|
7717
|
-
"000110": 9.3,
|
|
7718
|
-
"000111": 8.7,
|
|
7719
|
-
"000120": 9.1,
|
|
7720
|
-
"000121": 8.1,
|
|
7721
|
-
"000200": 9.3,
|
|
7722
|
-
"000201": 9,
|
|
7723
|
-
"000210": 8.9,
|
|
7724
|
-
"000211": 8,
|
|
7725
|
-
"000220": 8.1,
|
|
7726
|
-
"000221": 6.8,
|
|
7727
|
-
"001000": 9.8,
|
|
7728
|
-
"001001": 9.5,
|
|
7729
|
-
"001010": 9.5,
|
|
7730
|
-
"001011": 9.2,
|
|
7731
|
-
"001020": 9,
|
|
7732
|
-
"001021": 8.4,
|
|
7733
|
-
"001100": 9.3,
|
|
7734
|
-
"001101": 9.2,
|
|
7735
|
-
"001110": 8.9,
|
|
7736
|
-
"001111": 8.1,
|
|
7737
|
-
"001120": 8.1,
|
|
7738
|
-
"001121": 6.5,
|
|
7739
|
-
"001200": 8.8,
|
|
7740
|
-
"001201": 8,
|
|
7741
|
-
"001210": 7.8,
|
|
7742
|
-
"001211": 7,
|
|
7743
|
-
"001220": 6.9,
|
|
7744
|
-
"001221": 4.8,
|
|
7745
|
-
"002001": 9.2,
|
|
7746
|
-
"002011": 8.2,
|
|
7747
|
-
"002021": 7.2,
|
|
7748
|
-
"002101": 7.9,
|
|
7749
|
-
"002111": 6.9,
|
|
7750
|
-
"002121": 5,
|
|
7751
|
-
"002201": 6.9,
|
|
7752
|
-
"002211": 5.5,
|
|
7753
|
-
"002221": 2.7,
|
|
7754
|
-
"010000": 9.9,
|
|
7755
|
-
"010001": 9.7,
|
|
7756
|
-
"010010": 9.5,
|
|
7757
|
-
"010011": 9.2,
|
|
7758
|
-
"010020": 9.2,
|
|
7759
|
-
"010021": 8.5,
|
|
7760
|
-
"010100": 9.5,
|
|
7761
|
-
"010101": 9.1,
|
|
7762
|
-
"010110": 9,
|
|
7763
|
-
"010111": 8.3,
|
|
7764
|
-
"010120": 8.4,
|
|
7765
|
-
"010121": 7.1,
|
|
7766
|
-
"010200": 9.2,
|
|
7767
|
-
"010201": 8.1,
|
|
7768
|
-
"010210": 8.2,
|
|
7769
|
-
"010211": 7.1,
|
|
7770
|
-
"010220": 7.2,
|
|
7771
|
-
"010221": 5.3,
|
|
7772
|
-
"011000": 9.5,
|
|
7773
|
-
"011001": 9.3,
|
|
7774
|
-
"011010": 9.2,
|
|
7775
|
-
"011011": 8.5,
|
|
7776
|
-
"011020": 8.5,
|
|
7777
|
-
"011021": 7.3,
|
|
7778
|
-
"011100": 9.2,
|
|
7779
|
-
"011101": 8.2,
|
|
7780
|
-
"011110": 8,
|
|
7781
|
-
"011111": 7.2,
|
|
7782
|
-
"011120": 7,
|
|
7783
|
-
"011121": 5.9,
|
|
7784
|
-
"011200": 8.4,
|
|
7785
|
-
"011201": 7,
|
|
7786
|
-
"011210": 7.1,
|
|
7787
|
-
"011211": 5.2,
|
|
7788
|
-
"011220": 5,
|
|
7789
|
-
"011221": 3,
|
|
7790
|
-
"012001": 8.6,
|
|
7791
|
-
"012011": 7.5,
|
|
7792
|
-
"012021": 5.2,
|
|
7793
|
-
"012101": 7.1,
|
|
7794
|
-
"012111": 5.2,
|
|
7795
|
-
"012121": 2.9,
|
|
7796
|
-
"012201": 6.3,
|
|
7797
|
-
"012211": 2.9,
|
|
7798
|
-
"012221": 1.7,
|
|
7799
|
-
"100000": 9.8,
|
|
7800
|
-
"100001": 9.5,
|
|
7801
|
-
"100010": 9.4,
|
|
7802
|
-
"100011": 8.7,
|
|
7803
|
-
"100020": 9.1,
|
|
7804
|
-
"100021": 8.1,
|
|
7805
|
-
"100100": 9.4,
|
|
7806
|
-
"100101": 8.9,
|
|
7807
|
-
"100110": 8.6,
|
|
7808
|
-
"100111": 7.4,
|
|
7809
|
-
"100120": 7.7,
|
|
7810
|
-
"100121": 6.4,
|
|
7811
|
-
"100200": 8.7,
|
|
7812
|
-
"100201": 7.5,
|
|
7813
|
-
"100210": 7.4,
|
|
7814
|
-
"100211": 6.3,
|
|
7815
|
-
"100220": 6.3,
|
|
7816
|
-
"100221": 4.9,
|
|
7817
|
-
"101000": 9.4,
|
|
7818
|
-
"101001": 8.9,
|
|
7819
|
-
"101010": 8.8,
|
|
7820
|
-
"101011": 7.7,
|
|
7821
|
-
"101020": 7.6,
|
|
7822
|
-
"101021": 6.7,
|
|
7823
|
-
"101100": 8.6,
|
|
7824
|
-
"101101": 7.6,
|
|
7825
|
-
"101110": 7.4,
|
|
7826
|
-
"101111": 5.8,
|
|
7827
|
-
"101120": 5.9,
|
|
7828
|
-
"101121": 5,
|
|
7829
|
-
"101200": 7.2,
|
|
7830
|
-
"101201": 5.7,
|
|
7831
|
-
"101210": 5.7,
|
|
7832
|
-
"101211": 5.2,
|
|
7833
|
-
"101220": 5.2,
|
|
7834
|
-
"101221": 2.5,
|
|
7835
|
-
"102001": 8.3,
|
|
7836
|
-
"102011": 7,
|
|
7837
|
-
"102021": 5.4,
|
|
7838
|
-
"102101": 6.5,
|
|
7839
|
-
"102111": 5.8,
|
|
7840
|
-
"102121": 2.6,
|
|
7841
|
-
"102201": 5.3,
|
|
7842
|
-
"102211": 2.1,
|
|
7843
|
-
"102221": 1.3,
|
|
7844
|
-
"110000": 9.5,
|
|
7845
|
-
"110001": 9,
|
|
7846
|
-
"110010": 8.8,
|
|
7847
|
-
"110011": 7.6,
|
|
7848
|
-
"110020": 7.6,
|
|
7849
|
-
"110021": 7,
|
|
7850
|
-
"110100": 9,
|
|
7851
|
-
"110101": 7.7,
|
|
7852
|
-
"110110": 7.5,
|
|
7853
|
-
"110111": 6.2,
|
|
7854
|
-
"110120": 6.1,
|
|
7855
|
-
"110121": 5.3,
|
|
7856
|
-
"110200": 7.7,
|
|
7857
|
-
"110201": 6.6,
|
|
7858
|
-
"110210": 6.8,
|
|
7859
|
-
"110211": 5.9,
|
|
7860
|
-
"110220": 5.2,
|
|
7861
|
-
"110221": 3,
|
|
7862
|
-
"111000": 8.9,
|
|
7863
|
-
"111001": 7.8,
|
|
7864
|
-
"111010": 7.6,
|
|
7865
|
-
"111011": 6.7,
|
|
7866
|
-
"111020": 6.2,
|
|
7867
|
-
"111021": 5.8,
|
|
7868
|
-
"111100": 7.4,
|
|
7869
|
-
"111101": 5.9,
|
|
7870
|
-
"111110": 5.7,
|
|
7871
|
-
"111111": 5.7,
|
|
7872
|
-
"111120": 4.7,
|
|
7873
|
-
"111121": 2.3,
|
|
7874
|
-
"111200": 6.1,
|
|
7875
|
-
"111201": 5.2,
|
|
7876
|
-
"111210": 5.7,
|
|
7877
|
-
"111211": 2.9,
|
|
7878
|
-
"111220": 2.4,
|
|
7879
|
-
"111221": 1.6,
|
|
7880
|
-
"112001": 7.1,
|
|
7881
|
-
"112011": 5.9,
|
|
7882
|
-
"112021": 3,
|
|
7883
|
-
"112101": 5.8,
|
|
7884
|
-
"112111": 2.6,
|
|
7885
|
-
"112121": 1.5,
|
|
7886
|
-
"112201": 2.3,
|
|
7887
|
-
"112211": 1.3,
|
|
7888
|
-
"112221": 0.6,
|
|
7889
|
-
"200000": 9.3,
|
|
7890
|
-
"200001": 8.7,
|
|
7891
|
-
"200010": 8.6,
|
|
7892
|
-
"200011": 7.2,
|
|
7893
|
-
"200020": 7.5,
|
|
7894
|
-
"200021": 5.8,
|
|
7895
|
-
"200100": 8.6,
|
|
7896
|
-
"200101": 7.4,
|
|
7897
|
-
"200110": 7.4,
|
|
7898
|
-
"200111": 6.1,
|
|
7899
|
-
"200120": 5.6,
|
|
7900
|
-
"200121": 3.4,
|
|
7901
|
-
"200200": 7,
|
|
7902
|
-
"200201": 5.4,
|
|
7903
|
-
"200210": 5.2,
|
|
7904
|
-
"200211": 4,
|
|
7905
|
-
"200220": 4,
|
|
7906
|
-
"200221": 2.2,
|
|
7907
|
-
"201000": 8.5,
|
|
7908
|
-
"201001": 7.5,
|
|
7909
|
-
"201010": 7.4,
|
|
7910
|
-
"201011": 5.5,
|
|
7911
|
-
"201020": 6.2,
|
|
7912
|
-
"201021": 5.1,
|
|
7913
|
-
"201100": 7.2,
|
|
7914
|
-
"201101": 5.7,
|
|
7915
|
-
"201110": 5.5,
|
|
7916
|
-
"201111": 4.1,
|
|
7917
|
-
"201120": 4.6,
|
|
7918
|
-
"201121": 1.9,
|
|
7919
|
-
"201200": 5.3,
|
|
7920
|
-
"201201": 3.6,
|
|
7921
|
-
"201210": 3.4,
|
|
7922
|
-
"201211": 1.9,
|
|
7923
|
-
"201220": 1.9,
|
|
7924
|
-
"201221": 0.8,
|
|
7925
|
-
"202001": 6.4,
|
|
7926
|
-
"202011": 5.1,
|
|
7927
|
-
"202021": 2,
|
|
7928
|
-
"202101": 4.7,
|
|
7929
|
-
"202111": 2.1,
|
|
7930
|
-
"202121": 1.1,
|
|
7931
|
-
"202201": 2.4,
|
|
7932
|
-
"202211": 0.9,
|
|
7933
|
-
"202221": 0.4,
|
|
7934
|
-
"210000": 8.8,
|
|
7935
|
-
"210001": 7.5,
|
|
7936
|
-
"210010": 7.3,
|
|
7937
|
-
"210011": 5.3,
|
|
7938
|
-
"210020": 6,
|
|
7939
|
-
"210021": 5,
|
|
7940
|
-
"210100": 7.3,
|
|
7941
|
-
"210101": 5.5,
|
|
7942
|
-
"210110": 5.9,
|
|
7943
|
-
"210111": 4,
|
|
7944
|
-
"210120": 4.1,
|
|
7945
|
-
"210121": 2,
|
|
7946
|
-
"210200": 5.4,
|
|
7947
|
-
"210201": 4.3,
|
|
7948
|
-
"210210": 4.5,
|
|
7949
|
-
"210211": 2.2,
|
|
7950
|
-
"210220": 2,
|
|
7951
|
-
"210221": 1.1,
|
|
7952
|
-
"211000": 7.5,
|
|
7953
|
-
"211001": 5.5,
|
|
7954
|
-
"211010": 5.8,
|
|
7955
|
-
"211011": 4.5,
|
|
7956
|
-
"211020": 4,
|
|
7957
|
-
"211021": 2.1,
|
|
7958
|
-
"211100": 6.1,
|
|
7959
|
-
"211101": 5.1,
|
|
7960
|
-
"211110": 4.8,
|
|
7961
|
-
"211111": 1.8,
|
|
7962
|
-
"211120": 2,
|
|
7963
|
-
"211121": 0.9,
|
|
7964
|
-
"211200": 4.6,
|
|
7965
|
-
"211201": 1.8,
|
|
7966
|
-
"211210": 1.7,
|
|
7967
|
-
"211211": 0.7,
|
|
7968
|
-
"211220": 0.8,
|
|
7969
|
-
"211221": 0.2,
|
|
7970
|
-
"212001": 5.3,
|
|
7971
|
-
"212011": 2.4,
|
|
7972
|
-
"212021": 1.4,
|
|
7973
|
-
"212101": 2.4,
|
|
7974
|
-
"212111": 1.2,
|
|
7975
|
-
"212121": 0.5,
|
|
7976
|
-
"212201": 1,
|
|
7977
|
-
"212211": 0.3,
|
|
7978
|
-
"212221": 0.1
|
|
7979
|
-
};
|
|
7980
|
-
var CVSS40_MAX_COMPOSED = {
|
|
7981
|
-
eq1: {
|
|
7982
|
-
0: ["AV:N/PR:N/UI:N/"],
|
|
7983
|
-
1: ["AV:A/PR:N/UI:N/", "AV:N/PR:L/UI:N/", "AV:N/PR:N/UI:P/"],
|
|
7984
|
-
2: ["AV:P/PR:N/UI:N/", "AV:A/PR:L/UI:P/"]
|
|
7985
|
-
},
|
|
7986
|
-
eq2: {
|
|
7987
|
-
0: ["AC:L/AT:N/"],
|
|
7988
|
-
1: ["AC:H/AT:N/", "AC:L/AT:P/"]
|
|
7989
|
-
},
|
|
7990
|
-
eq3: {
|
|
7991
|
-
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/"] },
|
|
7992
|
-
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/"] },
|
|
7993
|
-
2: { "1": ["VC:L/VI:L/VA:L/CR:H/IR:H/AR:H/"] }
|
|
7994
|
-
},
|
|
7995
|
-
eq4: {
|
|
7996
|
-
0: ["SC:H/SI:S/SA:S/"],
|
|
7997
|
-
1: ["SC:H/SI:H/SA:H/"],
|
|
7998
|
-
2: ["SC:L/SI:L/SA:L/"]
|
|
7999
|
-
},
|
|
8000
|
-
eq5: {
|
|
8001
|
-
0: ["E:A/"],
|
|
8002
|
-
1: ["E:P/"],
|
|
8003
|
-
2: ["E:U/"]
|
|
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);
|
|
8004
7443
|
}
|
|
8005
|
-
};
|
|
8006
|
-
var CVSS40_MAX_SEVERITY = {
|
|
8007
|
-
eq1: { 0: 1, 1: 4, 2: 5 },
|
|
8008
|
-
eq2: { 0: 1, 1: 2 },
|
|
8009
|
-
eq3eq6: { 0: { 0: 7, 1: 6 }, 1: { 0: 8, 1: 8 }, 2: { 1: 10 } },
|
|
8010
|
-
eq4: { 0: 6, 1: 5, 2: 4 },
|
|
8011
|
-
eq5: { 0: 1, 1: 1, 2: 1 }
|
|
8012
|
-
};
|
|
8013
|
-
function m4(sel, metric) {
|
|
8014
|
-
const selected = sel[metric];
|
|
8015
|
-
if (metric === "E" && (selected === void 0 || selected === "X"))
|
|
8016
|
-
return "A";
|
|
8017
|
-
if ((metric === "CR" || metric === "IR" || metric === "AR") && (selected === void 0 || selected === "X")) {
|
|
8018
|
-
return "H";
|
|
8019
|
-
}
|
|
8020
|
-
const modified = sel["M" + metric];
|
|
8021
|
-
if (modified !== void 0 && modified !== "X")
|
|
8022
|
-
return modified;
|
|
8023
|
-
return selected ?? "";
|
|
8024
7444
|
}
|
|
8025
|
-
function
|
|
8026
|
-
|
|
8027
|
-
if (
|
|
8028
|
-
|
|
8029
|
-
|
|
8030
|
-
|
|
8031
|
-
|
|
8032
|
-
eq1 = "2";
|
|
8033
|
-
}
|
|
8034
|
-
const eq2 = m4(sel, "AC") === "L" && m4(sel, "AT") === "N" ? "0" : "1";
|
|
8035
|
-
let eq3;
|
|
8036
|
-
if (m4(sel, "VC") === "H" && m4(sel, "VI") === "H") {
|
|
8037
|
-
eq3 = "0";
|
|
8038
|
-
} else if (!(m4(sel, "VC") === "H" && m4(sel, "VI") === "H") && (m4(sel, "VC") === "H" || m4(sel, "VI") === "H" || m4(sel, "VA") === "H")) {
|
|
8039
|
-
eq3 = "1";
|
|
8040
|
-
} else {
|
|
8041
|
-
eq3 = "2";
|
|
8042
|
-
}
|
|
8043
|
-
let eq4;
|
|
8044
|
-
if (m4(sel, "MSI") === "S" || m4(sel, "MSA") === "S") {
|
|
8045
|
-
eq4 = "0";
|
|
8046
|
-
} else if (m4(sel, "SC") === "H" || m4(sel, "SI") === "H" || m4(sel, "SA") === "H") {
|
|
8047
|
-
eq4 = "1";
|
|
8048
|
-
} else {
|
|
8049
|
-
eq4 = "2";
|
|
8050
|
-
}
|
|
8051
|
-
let eq5;
|
|
8052
|
-
if (m4(sel, "E") === "A")
|
|
8053
|
-
eq5 = "0";
|
|
8054
|
-
else if (m4(sel, "E") === "P")
|
|
8055
|
-
eq5 = "1";
|
|
8056
|
-
else
|
|
8057
|
-
eq5 = "2";
|
|
8058
|
-
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";
|
|
8059
|
-
return eq1 + eq2 + eq3 + eq4 + eq5 + eq6;
|
|
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);
|
|
8060
7452
|
}
|
|
8061
|
-
function
|
|
8062
|
-
|
|
8063
|
-
if (eq === 1)
|
|
8064
|
-
return CVSS40_MAX_COMPOSED.eq1[idx];
|
|
8065
|
-
if (eq === 2)
|
|
8066
|
-
return CVSS40_MAX_COMPOSED.eq2[idx];
|
|
8067
|
-
if (eq === 4)
|
|
8068
|
-
return CVSS40_MAX_COMPOSED.eq4[idx];
|
|
8069
|
-
return CVSS40_MAX_COMPOSED.eq5[idx];
|
|
7453
|
+
function sleep(ms) {
|
|
7454
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
8070
7455
|
}
|
|
8071
|
-
function
|
|
8072
|
-
const
|
|
8073
|
-
|
|
8074
|
-
|
|
8075
|
-
|
|
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+$/, "");
|
|
8076
7465
|
}
|
|
8077
|
-
function
|
|
8078
|
-
if (
|
|
8079
|
-
return
|
|
8080
|
-
|
|
8081
|
-
const
|
|
8082
|
-
|
|
8083
|
-
|
|
8084
|
-
const eq2 = parseInt(macroVectorResult[1], 10);
|
|
8085
|
-
const eq3 = parseInt(macroVectorResult[2], 10);
|
|
8086
|
-
const eq4 = parseInt(macroVectorResult[3], 10);
|
|
8087
|
-
const eq5 = parseInt(macroVectorResult[4], 10);
|
|
8088
|
-
const eq6 = parseInt(macroVectorResult[5], 10);
|
|
8089
|
-
const eq1_next_lower_macro = `${eq1 + 1}${eq2}${eq3}${eq4}${eq5}${eq6}`;
|
|
8090
|
-
const eq2_next_lower_macro = `${eq1}${eq2 + 1}${eq3}${eq4}${eq5}${eq6}`;
|
|
8091
|
-
let eq3eq6_next_lower_macro = "";
|
|
8092
|
-
let eq3eq6_next_lower_macro_left = "";
|
|
8093
|
-
let eq3eq6_next_lower_macro_right = "";
|
|
8094
|
-
if (eq3 === 1 && eq6 === 1) {
|
|
8095
|
-
eq3eq6_next_lower_macro = `${eq1}${eq2}${eq3 + 1}${eq4}${eq5}${eq6}`;
|
|
8096
|
-
} else if (eq3 === 0 && eq6 === 1) {
|
|
8097
|
-
eq3eq6_next_lower_macro = `${eq1}${eq2}${eq3 + 1}${eq4}${eq5}${eq6}`;
|
|
8098
|
-
} else if (eq3 === 1 && eq6 === 0) {
|
|
8099
|
-
eq3eq6_next_lower_macro = `${eq1}${eq2}${eq3}${eq4}${eq5}${eq6 + 1}`;
|
|
8100
|
-
} else if (eq3 === 0 && eq6 === 0) {
|
|
8101
|
-
eq3eq6_next_lower_macro_left = `${eq1}${eq2}${eq3}${eq4}${eq5}${eq6 + 1}`;
|
|
8102
|
-
eq3eq6_next_lower_macro_right = `${eq1}${eq2}${eq3 + 1}${eq4}${eq5}${eq6}`;
|
|
8103
|
-
} else {
|
|
8104
|
-
eq3eq6_next_lower_macro = `${eq1}${eq2}${eq3 + 1}${eq4}${eq5}${eq6 + 1}`;
|
|
8105
|
-
}
|
|
8106
|
-
const eq4_next_lower_macro = `${eq1}${eq2}${eq3}${eq4 + 1}${eq5}${eq6}`;
|
|
8107
|
-
const eq5_next_lower_macro = `${eq1}${eq2}${eq3}${eq4}${eq5 + 1}${eq6}`;
|
|
8108
|
-
const score_eq1_next_lower_macro = CVSS40_LOOKUP[eq1_next_lower_macro];
|
|
8109
|
-
const score_eq2_next_lower_macro = CVSS40_LOOKUP[eq2_next_lower_macro];
|
|
8110
|
-
let score_eq3eq6_next_lower_macro;
|
|
8111
|
-
if (eq3 === 0 && eq6 === 0) {
|
|
8112
|
-
const left = CVSS40_LOOKUP[eq3eq6_next_lower_macro_left];
|
|
8113
|
-
const right = CVSS40_LOOKUP[eq3eq6_next_lower_macro_right];
|
|
8114
|
-
score_eq3eq6_next_lower_macro = left > right ? left : right;
|
|
8115
|
-
} else {
|
|
8116
|
-
score_eq3eq6_next_lower_macro = CVSS40_LOOKUP[eq3eq6_next_lower_macro];
|
|
8117
|
-
}
|
|
8118
|
-
const score_eq4_next_lower_macro = CVSS40_LOOKUP[eq4_next_lower_macro];
|
|
8119
|
-
const score_eq5_next_lower_macro = CVSS40_LOOKUP[eq5_next_lower_macro];
|
|
8120
|
-
const eq1_maxes = cvss4EqMaxes(macroVectorResult, 1);
|
|
8121
|
-
const eq2_maxes = cvss4EqMaxes(macroVectorResult, 2);
|
|
8122
|
-
const eq3_eq6_maxes = CVSS40_MAX_COMPOSED.eq3[eq3][macroVectorResult[5]];
|
|
8123
|
-
const eq4_maxes = cvss4EqMaxes(macroVectorResult, 4);
|
|
8124
|
-
const eq5_maxes = cvss4EqMaxes(macroVectorResult, 5);
|
|
8125
|
-
const max_vectors = [];
|
|
8126
|
-
for (const a of eq1_maxes)
|
|
8127
|
-
for (const b of eq2_maxes)
|
|
8128
|
-
for (const c of eq3_eq6_maxes)
|
|
8129
|
-
for (const d of eq4_maxes)
|
|
8130
|
-
for (const e of eq5_maxes)
|
|
8131
|
-
max_vectors.push(a + b + c + d + e);
|
|
8132
|
-
let severity_distance_AV = 0, severity_distance_PR = 0, severity_distance_UI = 0;
|
|
8133
|
-
let severity_distance_AC = 0, severity_distance_AT = 0;
|
|
8134
|
-
let severity_distance_VC = 0, severity_distance_VI = 0, severity_distance_VA = 0;
|
|
8135
|
-
let severity_distance_SC = 0, severity_distance_SI = 0, severity_distance_SA = 0;
|
|
8136
|
-
let severity_distance_CR = 0, severity_distance_IR = 0, severity_distance_AR = 0;
|
|
8137
|
-
for (const max_vector of max_vectors) {
|
|
8138
|
-
severity_distance_AV = AV_levels[m4(sel, "AV")] - AV_levels[extractValueMetric("AV", max_vector)];
|
|
8139
|
-
severity_distance_PR = PR_levels[m4(sel, "PR")] - PR_levels[extractValueMetric("PR", max_vector)];
|
|
8140
|
-
severity_distance_UI = UI_levels[m4(sel, "UI")] - UI_levels[extractValueMetric("UI", max_vector)];
|
|
8141
|
-
severity_distance_AC = AC_levels[m4(sel, "AC")] - AC_levels[extractValueMetric("AC", max_vector)];
|
|
8142
|
-
severity_distance_AT = AT_levels[m4(sel, "AT")] - AT_levels[extractValueMetric("AT", max_vector)];
|
|
8143
|
-
severity_distance_VC = VC_levels[m4(sel, "VC")] - VC_levels[extractValueMetric("VC", max_vector)];
|
|
8144
|
-
severity_distance_VI = VI_levels[m4(sel, "VI")] - VI_levels[extractValueMetric("VI", max_vector)];
|
|
8145
|
-
severity_distance_VA = VA_levels[m4(sel, "VA")] - VA_levels[extractValueMetric("VA", max_vector)];
|
|
8146
|
-
severity_distance_SC = SC_levels[m4(sel, "SC")] - SC_levels[extractValueMetric("SC", max_vector)];
|
|
8147
|
-
severity_distance_SI = SI_levels[m4(sel, "SI")] - SI_levels[extractValueMetric("SI", max_vector)];
|
|
8148
|
-
severity_distance_SA = SA_levels[m4(sel, "SA")] - SA_levels[extractValueMetric("SA", max_vector)];
|
|
8149
|
-
severity_distance_CR = CR_levels[m4(sel, "CR")] - CR_levels[extractValueMetric("CR", max_vector)];
|
|
8150
|
-
severity_distance_IR = IR_levels[m4(sel, "IR")] - IR_levels[extractValueMetric("IR", max_vector)];
|
|
8151
|
-
severity_distance_AR = AR_levels[m4(sel, "AR")] - AR_levels[extractValueMetric("AR", max_vector)];
|
|
8152
|
-
const anyNegative = [
|
|
8153
|
-
severity_distance_AV,
|
|
8154
|
-
severity_distance_PR,
|
|
8155
|
-
severity_distance_UI,
|
|
8156
|
-
severity_distance_AC,
|
|
8157
|
-
severity_distance_AT,
|
|
8158
|
-
severity_distance_VC,
|
|
8159
|
-
severity_distance_VI,
|
|
8160
|
-
severity_distance_VA,
|
|
8161
|
-
severity_distance_SC,
|
|
8162
|
-
severity_distance_SI,
|
|
8163
|
-
severity_distance_SA,
|
|
8164
|
-
severity_distance_CR,
|
|
8165
|
-
severity_distance_IR,
|
|
8166
|
-
severity_distance_AR
|
|
8167
|
-
].some((v) => v < 0);
|
|
8168
|
-
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)
|
|
8169
7473
|
continue;
|
|
8170
|
-
|
|
8171
|
-
|
|
8172
|
-
|
|
8173
|
-
|
|
8174
|
-
|
|
8175
|
-
|
|
8176
|
-
const step = 0.1;
|
|
8177
|
-
const available_distance_eq1 = value - score_eq1_next_lower_macro;
|
|
8178
|
-
const available_distance_eq2 = value - score_eq2_next_lower_macro;
|
|
8179
|
-
const available_distance_eq3eq6 = value - score_eq3eq6_next_lower_macro;
|
|
8180
|
-
const available_distance_eq4 = value - score_eq4_next_lower_macro;
|
|
8181
|
-
const available_distance_eq5 = value - score_eq5_next_lower_macro;
|
|
8182
|
-
let n_existing_lower = 0;
|
|
8183
|
-
let normalized_severity_eq1 = 0;
|
|
8184
|
-
let normalized_severity_eq2 = 0;
|
|
8185
|
-
let normalized_severity_eq3eq6 = 0;
|
|
8186
|
-
let normalized_severity_eq4 = 0;
|
|
8187
|
-
let normalized_severity_eq5 = 0;
|
|
8188
|
-
const maxSeverity_eq1 = CVSS40_MAX_SEVERITY.eq1[eq1] * step;
|
|
8189
|
-
const maxSeverity_eq2 = CVSS40_MAX_SEVERITY.eq2[eq2] * step;
|
|
8190
|
-
const maxSeverity_eq3eq6 = CVSS40_MAX_SEVERITY.eq3eq6[eq3][eq6] * step;
|
|
8191
|
-
const maxSeverity_eq4 = CVSS40_MAX_SEVERITY.eq4[eq4] * step;
|
|
8192
|
-
if (!Number.isNaN(available_distance_eq1)) {
|
|
8193
|
-
n_existing_lower += 1;
|
|
8194
|
-
normalized_severity_eq1 = available_distance_eq1 * (current_severity_distance_eq1 / maxSeverity_eq1);
|
|
8195
|
-
}
|
|
8196
|
-
if (!Number.isNaN(available_distance_eq2)) {
|
|
8197
|
-
n_existing_lower += 1;
|
|
8198
|
-
normalized_severity_eq2 = available_distance_eq2 * (current_severity_distance_eq2 / maxSeverity_eq2);
|
|
8199
|
-
}
|
|
8200
|
-
if (!Number.isNaN(available_distance_eq3eq6)) {
|
|
8201
|
-
n_existing_lower += 1;
|
|
8202
|
-
normalized_severity_eq3eq6 = available_distance_eq3eq6 * (current_severity_distance_eq3eq6 / maxSeverity_eq3eq6);
|
|
8203
|
-
}
|
|
8204
|
-
if (!Number.isNaN(available_distance_eq4)) {
|
|
8205
|
-
n_existing_lower += 1;
|
|
8206
|
-
normalized_severity_eq4 = available_distance_eq4 * (current_severity_distance_eq4 / maxSeverity_eq4);
|
|
8207
|
-
}
|
|
8208
|
-
if (!Number.isNaN(available_distance_eq5)) {
|
|
8209
|
-
n_existing_lower += 1;
|
|
8210
|
-
normalized_severity_eq5 = available_distance_eq5 * 0;
|
|
8211
|
-
}
|
|
8212
|
-
let mean_distance;
|
|
8213
|
-
if (n_existing_lower === 0) {
|
|
8214
|
-
mean_distance = 0;
|
|
8215
|
-
} else {
|
|
8216
|
-
mean_distance = (normalized_severity_eq1 + normalized_severity_eq2 + normalized_severity_eq3eq6 + normalized_severity_eq4 + normalized_severity_eq5) / n_existing_lower;
|
|
8217
|
-
}
|
|
8218
|
-
value -= mean_distance;
|
|
8219
|
-
if (value < 0)
|
|
8220
|
-
value = 0;
|
|
8221
|
-
if (value > 10)
|
|
8222
|
-
value = 10;
|
|
8223
|
-
return Math.round(value * 10) / 10;
|
|
8224
|
-
}
|
|
8225
|
-
function cvss4Severity(score) {
|
|
8226
|
-
if (score <= 0)
|
|
8227
|
-
return "None";
|
|
8228
|
-
if (score < 4)
|
|
8229
|
-
return "Low";
|
|
8230
|
-
if (score < 7)
|
|
8231
|
-
return "Medium";
|
|
8232
|
-
if (score < 9)
|
|
8233
|
-
return "High";
|
|
8234
|
-
return "Critical";
|
|
8235
|
-
}
|
|
8236
|
-
var CVSS4_METRIC_ORDER = [
|
|
8237
|
-
"AV",
|
|
8238
|
-
"AC",
|
|
8239
|
-
"AT",
|
|
8240
|
-
"PR",
|
|
8241
|
-
"UI",
|
|
8242
|
-
"VC",
|
|
8243
|
-
"VI",
|
|
8244
|
-
"VA",
|
|
8245
|
-
"SC",
|
|
8246
|
-
"SI",
|
|
8247
|
-
"SA",
|
|
8248
|
-
"E",
|
|
8249
|
-
"CR",
|
|
8250
|
-
"IR",
|
|
8251
|
-
"AR",
|
|
8252
|
-
"MAV",
|
|
8253
|
-
"MAC",
|
|
8254
|
-
"MAT",
|
|
8255
|
-
"MPR",
|
|
8256
|
-
"MUI",
|
|
8257
|
-
"MVC",
|
|
8258
|
-
"MVI",
|
|
8259
|
-
"MVA",
|
|
8260
|
-
"MSC",
|
|
8261
|
-
"MSI",
|
|
8262
|
-
"MSA",
|
|
8263
|
-
"S",
|
|
8264
|
-
"AU",
|
|
8265
|
-
"R",
|
|
8266
|
-
"V",
|
|
8267
|
-
"RE",
|
|
8268
|
-
"U"
|
|
8269
|
-
];
|
|
8270
|
-
function parseCvss4Vector(vector) {
|
|
8271
|
-
const trimmed = vector.trim();
|
|
8272
|
-
if (!trimmed.startsWith("CVSS:4.0/")) {
|
|
8273
|
-
throw new Cvss4ParseError(`Not a CVSS 4.0 vector (must start with "CVSS:4.0/"): ${vector}`);
|
|
8274
|
-
}
|
|
8275
|
-
const body = trimmed.slice("CVSS:4.0/".length);
|
|
8276
|
-
const parts = body.split("/").filter((p) => p.length > 0);
|
|
8277
|
-
if (parts.length === 0) {
|
|
8278
|
-
throw new Cvss4ParseError(`CVSS 4.0 vector has no metrics: ${vector}`);
|
|
8279
|
-
}
|
|
8280
|
-
const sel = {};
|
|
8281
|
-
for (const part of parts) {
|
|
8282
|
-
const eq = part.indexOf(":");
|
|
8283
|
-
if (eq < 0)
|
|
8284
|
-
throw new Cvss4ParseError(`Malformed metric segment "${part}" in ${vector}`);
|
|
8285
|
-
const key = part.slice(0, eq);
|
|
8286
|
-
const val = part.slice(eq + 1);
|
|
8287
|
-
const allowed = CVSS4_ALLOWED[key];
|
|
8288
|
-
if (!allowed)
|
|
8289
|
-
throw new Cvss4ParseError(`Unknown CVSS 4.0 metric "${key}" in ${vector}`);
|
|
8290
|
-
if (!allowed.has(val)) {
|
|
8291
|
-
throw new Cvss4ParseError(`Illegal value "${val}" for metric "${key}" in ${vector}`);
|
|
8292
|
-
}
|
|
8293
|
-
if (key in sel)
|
|
8294
|
-
throw new Cvss4ParseError(`Duplicate metric "${key}" in ${vector}`);
|
|
8295
|
-
sel[key] = val;
|
|
8296
|
-
}
|
|
8297
|
-
for (const base of CVSS4_BASE_KEYS) {
|
|
8298
|
-
if (!(base in sel)) {
|
|
8299
|
-
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;
|
|
8300
7480
|
}
|
|
8301
7481
|
}
|
|
8302
|
-
return
|
|
8303
|
-
}
|
|
8304
|
-
function formatCvss4Vector(sel) {
|
|
8305
|
-
const segs = [];
|
|
8306
|
-
for (const key of CVSS4_METRIC_ORDER) {
|
|
8307
|
-
const v = sel[key];
|
|
8308
|
-
if (v !== void 0 && v !== "X")
|
|
8309
|
-
segs.push(`${key}:${v}`);
|
|
8310
|
-
}
|
|
8311
|
-
return `CVSS:4.0/${segs.join("/")}`;
|
|
7482
|
+
return false;
|
|
8312
7483
|
}
|
|
8313
|
-
function
|
|
8314
|
-
|
|
8315
|
-
|
|
7484
|
+
function scopeRequiredResult(step, target, start) {
|
|
7485
|
+
if (target.scopeAllowlist && target.scopeAllowlist.length > 0)
|
|
7486
|
+
return void 0;
|
|
8316
7487
|
return {
|
|
8317
|
-
|
|
8318
|
-
|
|
8319
|
-
|
|
8320
|
-
|
|
7488
|
+
stepId: step.id,
|
|
7489
|
+
kind: "errored",
|
|
7490
|
+
durationMs: Date.now() - start,
|
|
7491
|
+
error: "PoC reverify requires a non-empty scope allowlist"
|
|
8321
7492
|
};
|
|
8322
7493
|
}
|
|
8323
|
-
function
|
|
8324
|
-
|
|
8325
|
-
|
|
8326
|
-
|
|
8327
|
-
|
|
8328
|
-
|
|
8329
|
-
|
|
8330
|
-
|
|
8331
|
-
|
|
8332
|
-
|
|
8333
|
-
case "local-priv":
|
|
8334
|
-
return { AV: "L", AT: "N", PR: "H", UI: "N" };
|
|
8335
|
-
case "needs-hardware":
|
|
8336
|
-
return { AV: "P", AT: "N", PR: "N", UI: "N" };
|
|
8337
|
-
case "needs-host-migration":
|
|
8338
|
-
return { AV: "L", AT: "N", PR: "N", UI: "A" };
|
|
8339
|
-
}
|
|
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;
|
|
8340
7504
|
}
|
|
8341
|
-
|
|
8342
|
-
|
|
8343
|
-
const
|
|
8344
|
-
|
|
8345
|
-
|
|
8346
|
-
|
|
8347
|
-
const UI = assessed?.UI ?? "N";
|
|
8348
|
-
const subsequent = impact.scope === "C";
|
|
8349
|
-
const sel = {
|
|
8350
|
-
AV,
|
|
8351
|
-
AC: "L",
|
|
8352
|
-
AT,
|
|
8353
|
-
PR: pr31,
|
|
8354
|
-
UI,
|
|
8355
|
-
VC: impact.C,
|
|
8356
|
-
VI: impact.I,
|
|
8357
|
-
VA: impact.A,
|
|
8358
|
-
SC: subsequent ? impact.C : "N",
|
|
8359
|
-
SI: subsequent ? impact.I : "N",
|
|
8360
|
-
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;
|
|
8361
7511
|
};
|
|
8362
|
-
|
|
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();
|
|
8363
7533
|
return {
|
|
8364
|
-
|
|
8365
|
-
|
|
8366
|
-
|
|
8367
|
-
|
|
7534
|
+
findingId: finding.id,
|
|
7535
|
+
startedAt,
|
|
7536
|
+
endedAt,
|
|
7537
|
+
steps,
|
|
7538
|
+
overallVerdict: aggregateVerdict(graph, steps)
|
|
8368
7539
|
};
|
|
8369
7540
|
}
|
|
8370
|
-
function
|
|
8371
|
-
const
|
|
8372
|
-
|
|
8373
|
-
|
|
8374
|
-
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
|
|
8379
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
8380
|
-
import { resolve, join } from "node:path";
|
|
8381
|
-
function extractFileRefs(finding) {
|
|
8382
|
-
const haystack = [
|
|
8383
|
-
finding.description,
|
|
8384
|
-
finding.evidence?.analysis,
|
|
8385
|
-
finding.evidence?.request,
|
|
8386
|
-
finding.evidence?.response
|
|
8387
|
-
].filter((s) => typeof s === "string" && s.length > 0).join("\n\n");
|
|
8388
|
-
const seen = /* @__PURE__ */ new Map();
|
|
8389
|
-
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;
|
|
8390
|
-
let match;
|
|
8391
|
-
while ((match = regex.exec(haystack)) !== null) {
|
|
8392
|
-
const file = match[1];
|
|
8393
|
-
const line = match[2] ? Number(match[2]) : void 0;
|
|
8394
|
-
if (file.startsWith("http:") || file.startsWith("https:"))
|
|
8395
|
-
continue;
|
|
8396
|
-
const key = `${file}:${line ?? ""}`;
|
|
8397
|
-
if (!seen.has(key))
|
|
8398
|
-
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
|
+
};
|
|
8399
7550
|
}
|
|
8400
|
-
return Array.from(seen.values());
|
|
8401
|
-
}
|
|
8402
|
-
function gitCmd(repoPath, args) {
|
|
8403
7551
|
try {
|
|
8404
|
-
|
|
8405
|
-
|
|
8406
|
-
|
|
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
|
+
};
|
|
8407
7582
|
}
|
|
8408
7583
|
}
|
|
8409
|
-
function
|
|
8410
|
-
const
|
|
8411
|
-
|
|
8412
|
-
|
|
8413
|
-
|
|
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
|
+
}
|
|
8414
7605
|
}
|
|
8415
|
-
const
|
|
8416
|
-
|
|
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)) {
|
|
8417
7618
|
return {
|
|
8418
|
-
|
|
8419
|
-
|
|
8420
|
-
|
|
8421
|
-
|
|
8422
|
-
refsStillPresent: [],
|
|
8423
|
-
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(", ")})`
|
|
8424
7623
|
};
|
|
8425
7624
|
}
|
|
8426
|
-
|
|
8427
|
-
|
|
8428
|
-
|
|
8429
|
-
|
|
8430
|
-
const abs = join(repoPath, ref.file);
|
|
8431
|
-
if (!existsSync(abs)) {
|
|
8432
|
-
refsMissing.push(ref);
|
|
8433
|
-
notes.push(`${ref.file} \u2014 file does not exist at ${currentRef}.`);
|
|
8434
|
-
continue;
|
|
8435
|
-
}
|
|
8436
|
-
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;
|
|
8437
7629
|
try {
|
|
8438
|
-
|
|
8439
|
-
if (ref.line > content.length) {
|
|
8440
|
-
refsMissing.push(ref);
|
|
8441
|
-
notes.push(`${ref.file}:${ref.line} \u2014 line is out of range (file has ${content.length} lines at ${currentRef}).`);
|
|
8442
|
-
continue;
|
|
8443
|
-
}
|
|
7630
|
+
host = new URL(u).host;
|
|
8444
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
|
+
};
|
|
8445
7641
|
}
|
|
8446
7642
|
}
|
|
8447
|
-
refsStillPresent.push(ref);
|
|
8448
|
-
}
|
|
8449
|
-
let status;
|
|
8450
|
-
if (refsStillPresent.length === 0) {
|
|
8451
|
-
status = refsMissing.some((r) => !existsSync(join(repoPath, r.file))) ? "file-removed" : "fixed";
|
|
8452
|
-
} else if (refsMissing.length === 0) {
|
|
8453
|
-
status = "still-vulnerable";
|
|
8454
|
-
} else {
|
|
8455
|
-
status = "partial-fix";
|
|
8456
|
-
}
|
|
8457
|
-
if (status === "still-vulnerable") {
|
|
8458
|
-
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.`);
|
|
8459
7643
|
}
|
|
8460
|
-
|
|
8461
|
-
|
|
8462
|
-
|
|
8463
|
-
|
|
8464
|
-
|
|
8465
|
-
refsStillPresent,
|
|
8466
|
-
refsMissing
|
|
8467
|
-
};
|
|
8468
|
-
}
|
|
8469
|
-
function refsMatch(a, b) {
|
|
8470
|
-
return a.file === b.file && a.line === b.line;
|
|
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);
|
|
8471
7649
|
}
|
|
8472
|
-
function
|
|
8473
|
-
const
|
|
8474
|
-
|
|
8475
|
-
|
|
8476
|
-
|
|
8477
|
-
|
|
8478
|
-
|
|
8479
|
-
|
|
8480
|
-
|
|
8481
|
-
|
|
8482
|
-
|
|
8483
|
-
|
|
8484
|
-
lines.push(`Refs checked (${result.refsChecked.length}):`);
|
|
8485
|
-
for (const ref of result.refsChecked) {
|
|
8486
|
-
const present = result.refsStillPresent.some((r) => refsMatch(r, ref));
|
|
8487
|
-
const marker = present ? "\u2713" : "\u2717";
|
|
8488
|
-
lines.push(`- ${marker} \`${ref.file}${ref.line ? `:${ref.line}` : ""}\``);
|
|
8489
|
-
}
|
|
8490
|
-
}
|
|
8491
|
-
if (result.notes.length > 0) {
|
|
8492
|
-
lines.push("");
|
|
8493
|
-
for (const note of result.notes)
|
|
8494
|
-
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
|
+
};
|
|
8495
7662
|
}
|
|
8496
|
-
|
|
8497
|
-
}
|
|
8498
|
-
|
|
8499
|
-
// packages/core/dist/disclose/version-range.js
|
|
8500
|
-
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
8501
|
-
import { resolve as resolve2 } from "node:path";
|
|
8502
|
-
function gitCmd2(repoPath, args) {
|
|
7663
|
+
let host;
|
|
8503
7664
|
try {
|
|
8504
|
-
|
|
8505
|
-
cwd: repoPath,
|
|
8506
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
8507
|
-
encoding: "utf8",
|
|
8508
|
-
maxBuffer: 4 * 1024 * 1024
|
|
8509
|
-
}).trim();
|
|
7665
|
+
host = new URL(url).host;
|
|
8510
7666
|
} catch {
|
|
8511
|
-
return null;
|
|
8512
|
-
}
|
|
8513
|
-
}
|
|
8514
|
-
function listTags(repoPath, limit, glob) {
|
|
8515
|
-
const baseArgs = ["tag"];
|
|
8516
|
-
if (glob)
|
|
8517
|
-
baseArgs.push("-l", glob);
|
|
8518
|
-
const byVersion = gitCmd2(repoPath, [...baseArgs, "--sort=-v:refname"]);
|
|
8519
|
-
if (byVersion && byVersion.length > 0) {
|
|
8520
|
-
return byVersion.split("\n").filter(Boolean).slice(0, limit);
|
|
8521
|
-
}
|
|
8522
|
-
const byDate = gitCmd2(repoPath, [...baseArgs, "--sort=-creatordate"]);
|
|
8523
|
-
if (!byDate)
|
|
8524
|
-
return [];
|
|
8525
|
-
return byDate.split("\n").filter(Boolean).slice(0, limit);
|
|
8526
|
-
}
|
|
8527
|
-
function fileExistsAtRef(repoPath, ref, filePath) {
|
|
8528
|
-
const out = gitCmd2(repoPath, ["cat-file", "-e", `${ref}:${filePath}`]);
|
|
8529
|
-
return out !== null;
|
|
8530
|
-
}
|
|
8531
|
-
function lineExistsAtRef(repoPath, ref, filePath, line) {
|
|
8532
|
-
const content = gitCmd2(repoPath, ["show", `${ref}:${filePath}`]);
|
|
8533
|
-
if (content === null)
|
|
8534
|
-
return false;
|
|
8535
|
-
const lineCount = content.split("\n").length;
|
|
8536
|
-
return line <= lineCount;
|
|
8537
|
-
}
|
|
8538
|
-
function findingPresentAtRef(repoPath, ref, refs) {
|
|
8539
|
-
if (refs.length === 0)
|
|
8540
|
-
return false;
|
|
8541
|
-
for (const r of refs) {
|
|
8542
|
-
if (!fileExistsAtRef(repoPath, ref, r.file))
|
|
8543
|
-
return false;
|
|
8544
|
-
if (r.line !== void 0 && !lineExistsAtRef(repoPath, ref, r.file, r.line))
|
|
8545
|
-
return false;
|
|
8546
|
-
}
|
|
8547
|
-
return true;
|
|
8548
|
-
}
|
|
8549
|
-
function detectVersionRange(finding, options) {
|
|
8550
|
-
const repoPath = resolve2(options.repoPath);
|
|
8551
|
-
const tagLimit = options.tagLimit ?? 30;
|
|
8552
|
-
const refs = extractFileRefs(finding);
|
|
8553
|
-
const notes = [];
|
|
8554
|
-
if (refs.length === 0) {
|
|
8555
7667
|
return {
|
|
8556
|
-
|
|
8557
|
-
|
|
8558
|
-
|
|
8559
|
-
|
|
7668
|
+
stepId: step.id,
|
|
7669
|
+
kind: "errored",
|
|
7670
|
+
durationMs: Date.now() - start,
|
|
7671
|
+
error: `http step url is not a valid URL: ${url}`
|
|
8560
7672
|
};
|
|
8561
7673
|
}
|
|
8562
|
-
|
|
8563
|
-
const presentOnHead = findingPresentAtRef(repoPath, "HEAD", refs);
|
|
8564
|
-
if (tags.length === 0) {
|
|
8565
|
-
notes.push(`No tags found in ${repoPath}${options.tagGlob ? ` matching '${options.tagGlob}'` : ""}.`);
|
|
7674
|
+
if (!hostMatchesAllowlist(host, target.scopeAllowlist)) {
|
|
8566
7675
|
return {
|
|
8567
|
-
|
|
8568
|
-
|
|
8569
|
-
|
|
8570
|
-
|
|
7676
|
+
stepId: step.id,
|
|
7677
|
+
kind: "errored",
|
|
7678
|
+
durationMs: Date.now() - start,
|
|
7679
|
+
error: `out-of-scope host: ${host} (allowlist: ${target.scopeAllowlist.join(", ")})`
|
|
8571
7680
|
};
|
|
8572
7681
|
}
|
|
8573
|
-
const
|
|
8574
|
-
|
|
8575
|
-
|
|
8576
|
-
|
|
8577
|
-
const
|
|
8578
|
-
const
|
|
8579
|
-
let
|
|
8580
|
-
|
|
8581
|
-
|
|
8582
|
-
|
|
8583
|
-
|
|
8584
|
-
|
|
8585
|
-
|
|
8586
|
-
|
|
8587
|
-
|
|
8588
|
-
|
|
8589
|
-
|
|
8590
|
-
|
|
8591
|
-
|
|
8592
|
-
|
|
8593
|
-
|
|
8594
|
-
|
|
8595
|
-
|
|
8596
|
-
|
|
8597
|
-
|
|
8598
|
-
|
|
8599
|
-
|
|
8600
|
-
|
|
8601
|
-
|
|
8602
|
-
|
|
8603
|
-
|
|
8604
|
-
|
|
8605
|
-
|
|
8606
|
-
|
|
8607
|
-
|
|
8608
|
-
|
|
8609
|
-
|
|
8610
|
-
|
|
8611
|
-
|
|
8612
|
-
|
|
8613
|
-
|
|
8614
|
-
|
|
8615
|
-
|
|
8616
|
-
|
|
8617
|
-
|
|
8618
|
-
|
|
8619
|
-
|
|
8620
|
-
|
|
8621
|
-
|
|
8622
|
-
|
|
8623
|
-
|
|
8624
|
-
|
|
8625
|
-
|
|
8626
|
-
|
|
8627
|
-
|
|
8628
|
-
|
|
8629
|
-
|
|
8630
|
-
|
|
8631
|
-
|
|
8632
|
-
|
|
8633
|
-
|
|
8634
|
-
};
|
|
8635
|
-
var SENSITIVE_HEADER_NAMES = /* @__PURE__ */ new Set([
|
|
8636
|
-
"authorization",
|
|
8637
|
-
"proxy-authorization",
|
|
8638
|
-
"cookie",
|
|
8639
|
-
"set-cookie",
|
|
8640
|
-
"x-auth-token",
|
|
8641
|
-
"x-api-key",
|
|
8642
|
-
"x-csrf-token",
|
|
8643
|
-
"x-xsrf-token"
|
|
8644
|
-
]);
|
|
8645
|
-
var AWS_KEY_RE = /\bAKIA[0-9A-Z]{16}\b/g;
|
|
8646
|
-
var JWT_RE = /\b[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+={0,2}\b/g;
|
|
8647
|
-
var INLINE_BEARER_RE = /\b(Bearer)\s+([^\s"'`]+)/gi;
|
|
8648
|
-
var INLINE_CURL_HEADER_RE = /(-H|--header)(\s+|=)(["']?)([A-Za-z][A-Za-z0-9-]*)\s*:\s*([^"'\n]*)\3/gi;
|
|
8649
|
-
function redactSensitiveHeaders(text) {
|
|
8650
|
-
if (!text)
|
|
8651
|
-
return text;
|
|
8652
|
-
let out = redactAuthHeaders(text);
|
|
8653
|
-
out = out.replace(AWS_KEY_RE, "<REDACTED-AWS-KEY>");
|
|
8654
|
-
out = out.replace(JWT_RE, (match) => {
|
|
8655
|
-
if (match.length < 80)
|
|
8656
|
-
return match;
|
|
8657
|
-
return "<REDACTED-JWT>";
|
|
8658
|
-
});
|
|
8659
|
-
return out;
|
|
8660
|
-
}
|
|
8661
|
-
function redactAuthHeaders(text) {
|
|
8662
|
-
if (!text)
|
|
8663
|
-
return text;
|
|
8664
|
-
const lines = text.split("\n");
|
|
8665
|
-
const redactedLines = lines.map((line) => {
|
|
8666
|
-
const m = /^(\s*)([A-Za-z][A-Za-z0-9-]*)\s*:\s*(.*)$/.exec(line);
|
|
8667
|
-
if (m && SENSITIVE_HEADER_NAMES.has(m[2].toLowerCase())) {
|
|
8668
|
-
return `${m[1]}${m[2]}: <REDACTED-${m[2]}>`;
|
|
8669
|
-
}
|
|
8670
|
-
return line;
|
|
8671
|
-
});
|
|
8672
|
-
let out = redactedLines.join("\n");
|
|
8673
|
-
out = out.replace(INLINE_CURL_HEADER_RE, (match, flag, sep, quote, name, _value) => {
|
|
8674
|
-
if (!SENSITIVE_HEADER_NAMES.has(name.toLowerCase()))
|
|
8675
|
-
return match;
|
|
8676
|
-
return `${flag}${sep}${quote}${name}: <REDACTED-${name}>${quote}`;
|
|
8677
|
-
});
|
|
8678
|
-
return out.replace(INLINE_BEARER_RE, "$1 <REDACTED-Bearer>");
|
|
8679
|
-
}
|
|
8680
|
-
function reachabilityLabel(tier) {
|
|
8681
|
-
switch (tier) {
|
|
8682
|
-
case "remote-unauth":
|
|
8683
|
-
return "remote, unauthenticated \u2014 reachable over the network with no credentials";
|
|
8684
|
-
case "remote-auth":
|
|
8685
|
-
return "remote, authenticated \u2014 requires an account or contributor access";
|
|
8686
|
-
case "proximity-rf":
|
|
8687
|
-
return "RF/physical proximity \u2014 attacker must be within radio range (NFC/BLE/Wi-Fi)";
|
|
8688
|
-
case "local-unpriv":
|
|
8689
|
-
return "local, unprivileged \u2014 requires an unprivileged account on the host";
|
|
8690
|
-
case "local-priv":
|
|
8691
|
-
return "local, privileged \u2014 requires an already-privileged local account";
|
|
8692
|
-
case "needs-hardware":
|
|
8693
|
-
return "requires specific or attacker-supplied hardware";
|
|
8694
|
-
case "needs-host-migration":
|
|
8695
|
-
return "requires the victim to mount/import an attacker-supplied artifact";
|
|
8696
|
-
}
|
|
8697
|
-
}
|
|
8698
|
-
function weaponizabilityLabel(w) {
|
|
8699
|
-
switch (w) {
|
|
8700
|
-
case "rce":
|
|
8701
|
-
return "remote code execution";
|
|
8702
|
-
case "lpe-to-root":
|
|
8703
|
-
return "local privilege escalation to root/SYSTEM";
|
|
8704
|
-
case "integrity-tampering":
|
|
8705
|
-
return "workflow integrity manipulation";
|
|
8706
|
-
case "info-leak":
|
|
8707
|
-
return "information disclosure";
|
|
8708
|
-
case "dos-crash":
|
|
8709
|
-
return "denial of service (crash)";
|
|
8710
|
-
}
|
|
8711
|
-
}
|
|
8712
|
-
function severityHeading(severity) {
|
|
8713
|
-
const upper = severity.toUpperCase();
|
|
8714
|
-
return upper === "CRITICAL" || upper === "HIGH" || upper === "MEDIUM" || upper === "LOW" ? upper : severity;
|
|
8715
|
-
}
|
|
8716
|
-
function slugifyTitle(title, max = 80) {
|
|
8717
|
-
return title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, max);
|
|
8718
|
-
}
|
|
8719
|
-
function indentEvidenceBlock(raw, lang = "") {
|
|
8720
|
-
const trimmed = raw.trim();
|
|
8721
|
-
if (!trimmed)
|
|
8722
|
-
return "";
|
|
8723
|
-
return "```" + lang + "\n" + trimmed + "\n```";
|
|
8724
|
-
}
|
|
8725
|
-
function renderPocSteps(finding) {
|
|
8726
|
-
if (!finding.pocSteps || finding.pocSteps.length === 0)
|
|
8727
|
-
return [];
|
|
8728
|
-
const lines = ["**Step graph:**", ""];
|
|
8729
|
-
for (const [index, step] of finding.pocSteps.entries()) {
|
|
8730
|
-
lines.push(`${index + 1}. **${step.kind}** \u2014 ${step.summary} _(id: \`${step.id}\`)_`);
|
|
8731
|
-
if (step.action.type === "shell") {
|
|
8732
|
-
lines.push("", indentEvidenceBlock(step.action.cmd, "bash"));
|
|
8733
|
-
} else if (step.action.type === "http") {
|
|
8734
|
-
const method = step.action.method.toUpperCase();
|
|
8735
|
-
lines.push("", indentEvidenceBlock(`${method} ${step.action.url}${step.action.body ? `
|
|
8736
|
-
|
|
8737
|
-
${step.action.body}` : ""}`, "http"));
|
|
8738
|
-
} else if (step.action.type === "docker") {
|
|
8739
|
-
lines.push("", indentEvidenceBlock(`docker run ${step.action.image} ${step.action.args.join(" ")}`.trim(), "bash"));
|
|
8740
|
-
} else {
|
|
8741
|
-
lines.push("", step.action.text);
|
|
8742
|
-
}
|
|
8743
|
-
if (step.expect) {
|
|
8744
|
-
lines.push("", `Expected result: \`${step.expect.type}\``);
|
|
8745
|
-
}
|
|
8746
|
-
lines.push("");
|
|
8747
|
-
}
|
|
8748
|
-
return lines;
|
|
8749
|
-
}
|
|
8750
|
-
function renderAdvisoryMarkdown(finding, ctx = {}) {
|
|
8751
|
-
const cwes = suggestCwesForCategory(finding.category);
|
|
8752
|
-
const cvss = suggestCvss(finding);
|
|
8753
|
-
const severity = severityHeading(finding.severity);
|
|
8754
|
-
const rank = { critical: "1", high: "2", medium: "3", low: "4", info: "5" };
|
|
8755
|
-
const filenameSlug = slugifyTitle(finding.title);
|
|
8756
|
-
const filename = `${rank[finding.severity] ?? "9"}-${finding.severity}-${filenameSlug}.md`;
|
|
8757
|
-
let affectedLine;
|
|
8758
|
-
if (ctx.versionRange) {
|
|
8759
|
-
affectedLine = formatVersionRangeLine(ctx.versionRange);
|
|
8760
|
-
} else if (ctx.target) {
|
|
8761
|
-
affectedLine = `\`${ctx.target}\`${ctx.targetRef ? ` at \`${ctx.targetRef}\`` : ""}${ctx.commitHash ? ` (commit \`${ctx.commitHash.slice(0, 12)}\`)` : ""}`;
|
|
8762
|
-
} else {
|
|
8763
|
-
affectedLine = "_Pass `--repo <path>` to `@0/cli disclose` to auto-detect the affected version range from git tags._";
|
|
8764
|
-
}
|
|
8765
|
-
const cvssSource = cvss.source === "finding" ? "populated on the finding by 0" : cvss.source === "impact-assessment" ? "exploitability metrics derived from 0'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";
|
|
8766
|
-
const remediation = finding.remediation;
|
|
8767
|
-
const suggestedFixParts = [];
|
|
8768
|
-
if (remediation?.summary)
|
|
8769
|
-
suggestedFixParts.push(remediation.summary);
|
|
8770
|
-
if (remediation?.steps?.length) {
|
|
8771
|
-
suggestedFixParts.push(remediation.steps.map((step, i) => `${i + 1}. ${step}`).join("\n"));
|
|
8772
|
-
}
|
|
8773
|
-
if (remediation?.codeExample?.after) {
|
|
8774
|
-
const lang = remediation.codeExample.language || "";
|
|
8775
|
-
suggestedFixParts.push(remediation.codeExample.before ? `**Before:**
|
|
8776
|
-
|
|
8777
|
-
\`\`\`${lang}
|
|
8778
|
-
${remediation.codeExample.before}
|
|
8779
|
-
\`\`\`
|
|
8780
|
-
|
|
8781
|
-
**After:**
|
|
8782
|
-
|
|
8783
|
-
\`\`\`${lang}
|
|
8784
|
-
${remediation.codeExample.after}
|
|
8785
|
-
\`\`\`` : `\`\`\`${lang}
|
|
8786
|
-
${remediation.codeExample.after}
|
|
8787
|
-
\`\`\``);
|
|
8788
|
-
} else if (ctx.siblingFix) {
|
|
8789
|
-
const ref = `${ctx.siblingFix.fileRef.file}${ctx.siblingFix.fileRef.line ? `:${ctx.siblingFix.fileRef.line}` : ""}`;
|
|
8790
|
-
suggestedFixParts.push(`**Correct pattern already present in the repo at \`${ref}\`** *(extracted by 0):*
|
|
8791
|
-
|
|
8792
|
-
\`\`\`${ctx.siblingFix.language}
|
|
8793
|
-
${ctx.siblingFix.snippet}
|
|
8794
|
-
\`\`\``);
|
|
8795
|
-
}
|
|
8796
|
-
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._";
|
|
8797
|
-
const evidenceAnalysis = finding.evidence?.analysis?.trim() ?? "";
|
|
8798
|
-
const out = [];
|
|
8799
|
-
out.push("# Title", "");
|
|
8800
|
-
out.push(finding.title, "");
|
|
8801
|
-
out.push("# Severity", "");
|
|
8802
|
-
out.push(`**${severity}** \u2014 ${cvss.vector} (~${cvss.score.toFixed(1)})`, "");
|
|
8803
|
-
out.push(`_CVSS source: ${cvssSource}._`, "");
|
|
8804
|
-
const impactAssessment = finding.impactAssessment;
|
|
8805
|
-
if (impactAssessment) {
|
|
8806
|
-
out.push("# Impact", "");
|
|
8807
|
-
out.push(`**Attacker gains:** ${weaponizabilityLabel(impactAssessment.weaponizability)}`, "");
|
|
8808
|
-
out.push(`**Attack prerequisites:** ${reachabilityLabel(impactAssessment.reachability_tier)}`, "");
|
|
8809
|
-
if (impactAssessment.blast_radius) {
|
|
8810
|
-
out.push(`**Blast radius:** ${impactAssessment.blast_radius}`, "");
|
|
8811
|
-
}
|
|
8812
|
-
if (impactAssessment.rationale) {
|
|
8813
|
-
out.push(`_${impactAssessment.rationale}_`, "");
|
|
8814
|
-
}
|
|
8815
|
-
}
|
|
8816
|
-
out.push(formatCweSection(cwes), "");
|
|
8817
|
-
out.push("# Affected versions", "");
|
|
8818
|
-
out.push(affectedLine, "");
|
|
8819
|
-
if (ctx.osecVersion || ctx.scanId) {
|
|
8820
|
-
const bits = [];
|
|
8821
|
-
if (ctx.osecVersion)
|
|
8822
|
-
bits.push(`0 \`${ctx.osecVersion}\``);
|
|
8823
|
-
if (ctx.scanId)
|
|
8824
|
-
bits.push(`scan \`${ctx.scanId.slice(0, 8)}\``);
|
|
8825
|
-
const canaryPositive = ctx.patchStatus?.status === "still-vulnerable";
|
|
8826
|
-
const behaviouralPositive = ctx.pocExecution?.overallVerdict === "exploit_still_works";
|
|
8827
|
-
if (canaryPositive && behaviouralPositive) {
|
|
8828
|
-
out.push(`> Code-verified by ${bits.join(", ")}.`, "");
|
|
8829
|
-
} else {
|
|
8830
|
-
out.push(`_Generated by ${bits.join(", ")}._`, "");
|
|
8831
|
-
}
|
|
8832
|
-
}
|
|
8833
|
-
out.push("## Summary", "");
|
|
8834
|
-
out.push(finding.description.trim(), "");
|
|
8835
|
-
if (evidenceAnalysis && evidenceAnalysis !== finding.description.trim()) {
|
|
8836
|
-
out.push("## Analysis", "");
|
|
8837
|
-
out.push(evidenceAnalysis, "");
|
|
8838
|
-
}
|
|
8839
|
-
const pocStepsBlock = renderPocSteps(finding);
|
|
8840
|
-
const hasRequest = !!finding.evidence?.request?.trim();
|
|
8841
|
-
const hasResponse = !!finding.evidence?.response?.trim();
|
|
8842
|
-
const hasScreenshots = !!ctx.screenshots && ctx.screenshots.length > 0;
|
|
8843
|
-
if (pocStepsBlock.length === 0 && !hasRequest && !hasResponse && !hasScreenshots) {
|
|
8844
|
-
throw new EmptyPocError(finding.id);
|
|
8845
|
-
}
|
|
8846
|
-
out.push("## PoC", "");
|
|
8847
|
-
if (pocStepsBlock.length > 0) {
|
|
8848
|
-
const redactedSteps = redactSensitiveHeaders(pocStepsBlock.join("\n")).split("\n");
|
|
8849
|
-
out.push(...redactedSteps);
|
|
8850
|
-
}
|
|
8851
|
-
if (hasScreenshots) {
|
|
8852
|
-
for (const shot of ctx.screenshots) {
|
|
8853
|
-
const width = shot.width ? ` width="${shot.width}"` : "";
|
|
8854
|
-
out.push(`<img${width} alt="${shot.alt}" src="${shot.relativePath}" />`, "");
|
|
8855
|
-
if (shot.caption) {
|
|
8856
|
-
out.push(`> ${shot.caption}`, "");
|
|
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
|
+
};
|
|
8857
7744
|
}
|
|
7745
|
+
try {
|
|
7746
|
+
finalResponse.body?.cancel();
|
|
7747
|
+
} catch {
|
|
7748
|
+
}
|
|
7749
|
+
currentUrl = nextUrlStr;
|
|
8858
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);
|
|
8859
7762
|
}
|
|
8860
|
-
|
|
8861
|
-
|
|
8862
|
-
|
|
8863
|
-
}
|
|
8864
|
-
if (hasResponse) {
|
|
8865
|
-
out.push("**Response:**", "");
|
|
8866
|
-
out.push(indentEvidenceBlock(redactSensitiveHeaders(finding.evidence.response), "http"), "");
|
|
8867
|
-
}
|
|
8868
|
-
out.push("## Suggested fix", "");
|
|
8869
|
-
out.push(suggestedFix, "");
|
|
8870
|
-
out.push("## Patch status", "");
|
|
8871
|
-
if (ctx.patchStatus) {
|
|
8872
|
-
out.push(formatPatchStatusSection(ctx.patchStatus), "");
|
|
8873
|
-
} else {
|
|
8874
|
-
out.push("_Pass `--repo <path>` to `@0/cli disclose` to auto-verify this against the target's current HEAD or a specific tag._", "");
|
|
8875
|
-
}
|
|
8876
|
-
if (ctx.pocExecution) {
|
|
8877
|
-
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.**";
|
|
8878
|
-
out.push(verdict, "");
|
|
8879
|
-
out.push(`> Verdict: \`${ctx.pocExecution.overallVerdict}\` (${ctx.pocExecution.steps.length} step${ctx.pocExecution.steps.length === 1 ? "" : "s"} executed).`, "");
|
|
8880
|
-
}
|
|
8881
|
-
out.push("## Credits", "");
|
|
8882
|
-
out.push("Discovered by **0.security**, the 0.security AI-assisted security engine ([0.security](https://0.security)).", "", "Reporter: _(your github handle)_", "");
|
|
7763
|
+
const verdict = evaluateExpect(step.expect, {
|
|
7764
|
+
status: finalResponse.status,
|
|
7765
|
+
body
|
|
7766
|
+
});
|
|
8883
7767
|
return {
|
|
8884
|
-
|
|
8885
|
-
|
|
8886
|
-
|
|
8887
|
-
|
|
8888
|
-
|
|
8889
|
-
|
|
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 } : {}
|
|
8890
7774
|
};
|
|
8891
7775
|
}
|
|
8892
|
-
function
|
|
8893
|
-
|
|
8894
|
-
|
|
8895
|
-
|
|
8896
|
-
|
|
7776
|
+
function resolveUrl(stepUrl, baseUrl) {
|
|
7777
|
+
try {
|
|
7778
|
+
new URL(stepUrl);
|
|
7779
|
+
return stepUrl;
|
|
7780
|
+
} catch {
|
|
8897
7781
|
}
|
|
8898
|
-
|
|
8899
|
-
|
|
8900
|
-
|
|
8901
|
-
|
|
8902
|
-
|
|
8903
|
-
return
|
|
7782
|
+
if (!baseUrl)
|
|
7783
|
+
return null;
|
|
7784
|
+
try {
|
|
7785
|
+
return new URL(stepUrl, baseUrl).toString();
|
|
7786
|
+
} catch {
|
|
7787
|
+
return null;
|
|
8904
7788
|
}
|
|
8905
|
-
const parts = [];
|
|
8906
|
-
parts.push(`An attacker gains **${weaponizabilityLabel(a.weaponizability)}**. Attack prerequisites: ${reachabilityLabel(a.reachability_tier)}.`);
|
|
8907
|
-
if (a.blast_radius)
|
|
8908
|
-
parts.push(`**Blast radius:** ${a.blast_radius}`);
|
|
8909
|
-
if (a.rationale)
|
|
8910
|
-
parts.push(a.rationale);
|
|
8911
|
-
return parts.join("\n\n");
|
|
8912
|
-
}
|
|
8913
|
-
function buildAttackScenario(finding) {
|
|
8914
|
-
const a = finding.impactAssessment;
|
|
8915
|
-
if (!a)
|
|
8916
|
-
return "";
|
|
8917
|
-
return `1. Attacker position: ${reachabilityLabel(a.reachability_tier)}.
|
|
8918
|
-
2. Trigger the ${finding.category.replace(/-/g, " ")} condition described above.
|
|
8919
|
-
3. Result: ${weaponizabilityLabel(a.weaponizability)}${a.blast_radius ? ` \u2014 ${a.blast_radius}` : ""}.`;
|
|
8920
|
-
}
|
|
8921
|
-
function buildStepsToReproduce(finding) {
|
|
8922
|
-
const block = renderPocSteps(finding);
|
|
8923
|
-
if (block.length === 0)
|
|
8924
|
-
return "";
|
|
8925
|
-
return redactSensitiveHeaders(block.join("\n"));
|
|
8926
7789
|
}
|
|
8927
|
-
function
|
|
8928
|
-
const
|
|
8929
|
-
|
|
8930
|
-
|
|
8931
|
-
|
|
8932
|
-
|
|
8933
|
-
|
|
8934
|
-
out.push(`> ${shot.caption}`, "");
|
|
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;
|
|
8935
7797
|
}
|
|
7798
|
+
merged[k] = v;
|
|
8936
7799
|
}
|
|
8937
|
-
if (
|
|
8938
|
-
|
|
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;
|
|
7809
|
+
}
|
|
8939
7810
|
}
|
|
8940
|
-
if (
|
|
8941
|
-
|
|
7811
|
+
if (persona.cookies && !("cookie" in lowerKeys(merged))) {
|
|
7812
|
+
merged["Cookie"] = persona.cookies;
|
|
8942
7813
|
}
|
|
8943
|
-
return
|
|
7814
|
+
return merged;
|
|
8944
7815
|
}
|
|
8945
|
-
function
|
|
8946
|
-
const
|
|
8947
|
-
const
|
|
8948
|
-
|
|
8949
|
-
|
|
8950
|
-
if (remediation?.steps?.length) {
|
|
8951
|
-
parts.push(remediation.steps.map((step, i) => `${i + 1}. ${step}`).join("\n"));
|
|
8952
|
-
}
|
|
8953
|
-
if (remediation?.codeExample?.after) {
|
|
8954
|
-
const lang = remediation.codeExample.language || "";
|
|
8955
|
-
parts.push(remediation.codeExample.before ? `**Before:**
|
|
8956
|
-
|
|
8957
|
-
\`\`\`${lang}
|
|
8958
|
-
${remediation.codeExample.before}
|
|
8959
|
-
\`\`\`
|
|
8960
|
-
|
|
8961
|
-
**After:**
|
|
8962
|
-
|
|
8963
|
-
\`\`\`${lang}
|
|
8964
|
-
${remediation.codeExample.after}
|
|
8965
|
-
\`\`\`` : `\`\`\`${lang}
|
|
8966
|
-
${remediation.codeExample.after}
|
|
8967
|
-
\`\`\``);
|
|
8968
|
-
} else if (ctx.siblingFix) {
|
|
8969
|
-
const ref = `${ctx.siblingFix.fileRef.file}${ctx.siblingFix.fileRef.line ? `:${ctx.siblingFix.fileRef.line}` : ""}`;
|
|
8970
|
-
parts.push(`**Correct pattern already present in the repo at \`${ref}\`** *(extracted by 0):*
|
|
8971
|
-
|
|
8972
|
-
\`\`\`${ctx.siblingFix.language}
|
|
8973
|
-
${ctx.siblingFix.snippet}
|
|
8974
|
-
\`\`\``);
|
|
8975
|
-
}
|
|
8976
|
-
return parts.length > 0 ? parts.join("\n\n") : "_Recommended fix: apply input validation / correct handling per the referenced CWE guidance._";
|
|
7816
|
+
function lowerKeys(obj) {
|
|
7817
|
+
const out = {};
|
|
7818
|
+
for (const [k, v] of Object.entries(obj))
|
|
7819
|
+
out[k.toLowerCase()] = v;
|
|
7820
|
+
return out;
|
|
8977
7821
|
}
|
|
8978
|
-
function
|
|
8979
|
-
|
|
8980
|
-
|
|
8981
|
-
|
|
8982
|
-
|
|
8983
|
-
|
|
8984
|
-
|
|
8985
|
-
|
|
8986
|
-
|
|
8987
|
-
|
|
7822
|
+
async function readBodyCapped(response) {
|
|
7823
|
+
if (!response.body)
|
|
7824
|
+
return "";
|
|
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;
|
|
8988
7848
|
}
|
|
8989
|
-
function
|
|
8990
|
-
|
|
8991
|
-
|
|
8992
|
-
|
|
8993
|
-
|
|
8994
|
-
|
|
8995
|
-
|
|
8996
|
-
|
|
8997
|
-
|
|
8998
|
-
|
|
8999
|
-
|
|
9000
|
-
|
|
9001
|
-
|
|
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
|
+
});
|
|
9002
7923
|
}
|
|
9003
|
-
function
|
|
9004
|
-
|
|
9005
|
-
|
|
9006
|
-
|
|
9007
|
-
|
|
9008
|
-
|
|
9009
|
-
|
|
9010
|
-
|
|
9011
|
-
|
|
9012
|
-
|
|
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
|
+
};
|
|
9013
7935
|
}
|
|
9014
|
-
|
|
9015
|
-
|
|
9016
|
-
|
|
9017
|
-
|
|
9018
|
-
|
|
9019
|
-
|
|
9020
|
-
|
|
9021
|
-
|
|
9022
|
-
|
|
9023
|
-
throw new EmptyPocError(finding.id);
|
|
9024
|
-
return {
|
|
9025
|
-
cvss,
|
|
9026
|
-
cwes,
|
|
9027
|
-
severity,
|
|
9028
|
-
title: finding.title,
|
|
9029
|
-
summary: finding.description.trim(),
|
|
9030
|
-
impact: buildImpactNarrative(finding),
|
|
9031
|
-
attackScenario: buildAttackScenario(finding),
|
|
9032
|
-
steps,
|
|
9033
|
-
poc,
|
|
9034
|
-
affected: buildAffectedLine(finding, ctx),
|
|
9035
|
-
remediation: buildRemediation(finding, ctx),
|
|
9036
|
-
references: buildReferences(finding, cwes),
|
|
9037
|
-
severityCvss31: renderCvssSection({ vector: cvss.vector, score: cvss.score, severity }),
|
|
9038
|
-
severityCvss40: renderCvssSection({
|
|
9039
|
-
vector: cvss4.vector,
|
|
9040
|
-
score: cvss4.score,
|
|
9041
|
-
severity: cvss4.severity
|
|
9042
|
-
})
|
|
9043
|
-
};
|
|
9044
|
-
}
|
|
9045
|
-
function assembleReport(platform, parts, sections) {
|
|
9046
|
-
const out = [`# ${parts.title}`, ""];
|
|
9047
|
-
for (const s of sections) {
|
|
9048
|
-
out.push(`## ${s.heading}`, "", s.body, "");
|
|
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
|
+
};
|
|
9049
7945
|
}
|
|
9050
|
-
|
|
9051
|
-
|
|
9052
|
-
|
|
9053
|
-
|
|
9054
|
-
|
|
9055
|
-
|
|
9056
|
-
|
|
9057
|
-
|
|
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
|
|
9058
7956
|
};
|
|
7957
|
+
if (spawned.exitCode !== null)
|
|
7958
|
+
result.observedExit = spawned.exitCode;
|
|
7959
|
+
if (verdict.error)
|
|
7960
|
+
result.error = verdict.error;
|
|
7961
|
+
return result;
|
|
9059
7962
|
}
|
|
9060
|
-
function
|
|
9061
|
-
|
|
9062
|
-
}
|
|
9063
|
-
|
|
9064
|
-
|
|
9065
|
-
|
|
9066
|
-
|
|
9067
|
-
|
|
9068
|
-
|
|
9069
|
-
|
|
9070
|
-
|
|
9071
|
-
|
|
9072
|
-
|
|
9073
|
-
"
|
|
9074
|
-
|
|
9075
|
-
|
|
9076
|
-
|
|
9077
|
-
|
|
9078
|
-
|
|
9079
|
-
|
|
9080
|
-
|
|
9081
|
-
|
|
9082
|
-
|
|
9083
|
-
|
|
9084
|
-
|
|
9085
|
-
|
|
9086
|
-
|
|
9087
|
-
{
|
|
9088
|
-
|
|
9089
|
-
|
|
9090
|
-
|
|
9091
|
-
|
|
9092
|
-
|
|
9093
|
-
|
|
9094
|
-
|
|
9095
|
-
|
|
9096
|
-
|
|
9097
|
-
|
|
9098
|
-
|
|
9099
|
-
|
|
9100
|
-
|
|
9101
|
-
|
|
9102
|
-
|
|
9103
|
-
|
|
9104
|
-
|
|
9105
|
-
|
|
9106
|
-
|
|
9107
|
-
|
|
9108
|
-
|
|
9109
|
-
|
|
9110
|
-
|
|
9111
|
-
|
|
9112
|
-
|
|
9113
|
-
|
|
9114
|
-
|
|
9115
|
-
|
|
9116
|
-
|
|
9117
|
-
|
|
9118
|
-
|
|
9119
|
-
{ heading: "Proof of Concept", body: parts.poc || "_See Steps to Reproduce._" },
|
|
9120
|
-
{ heading: "Remediation", body: parts.remediation },
|
|
9121
|
-
{ heading: "References", body: parts.references }
|
|
9122
|
-
];
|
|
9123
|
-
return assembleReport("bugcrowd", parts, sections);
|
|
9124
|
-
}
|
|
9125
|
-
};
|
|
9126
|
-
var INTIGRITI_TEMPLATE = {
|
|
9127
|
-
id: "intigriti",
|
|
9128
|
-
label: "Intigriti",
|
|
9129
|
-
description: "Intigriti order: Summary \u2192 Domain/Endpoint \u2192 Vulnerability Type (CWE) \u2192 Impact \u2192 Steps \u2192 PoC \u2192 Severity (CVSS) \u2192 Recommended Fix.",
|
|
9130
|
-
requiredSections: [
|
|
9131
|
-
"Summary",
|
|
9132
|
-
"Domain / Endpoint",
|
|
9133
|
-
"Vulnerability Type",
|
|
9134
|
-
"Impact",
|
|
9135
|
-
"Steps to Reproduce",
|
|
9136
|
-
"Proof of Concept",
|
|
9137
|
-
"Severity",
|
|
9138
|
-
"Recommended Fix"
|
|
9139
|
-
],
|
|
9140
|
-
render(finding, ctx = {}) {
|
|
9141
|
-
const parts = buildCommonParts(finding, ctx);
|
|
9142
|
-
const primaryCwe = parts.cwes[0];
|
|
9143
|
-
const sections = [
|
|
9144
|
-
{ heading: "Summary", body: parts.summary },
|
|
9145
|
-
{ heading: "Domain / Endpoint", body: parts.affected },
|
|
9146
|
-
{
|
|
9147
|
-
heading: "Vulnerability Type",
|
|
9148
|
-
body: primaryCwe ? `${primaryCwe.id}: ${primaryCwe.name} (category: \`${finding.category}\`)` : `Category: \`${finding.category}\``
|
|
9149
|
-
},
|
|
9150
|
-
{ heading: "Impact", body: parts.impact },
|
|
9151
|
-
{ heading: "Steps to Reproduce", body: stepsBodyOrPoc(parts) },
|
|
9152
|
-
{ heading: "Proof of Concept", body: parts.poc || "_See Steps to Reproduce._" },
|
|
9153
|
-
{ heading: "Severity", body: parts.severityCvss31 },
|
|
9154
|
-
{ heading: "Recommended Fix", body: parts.remediation },
|
|
9155
|
-
{ heading: "References", body: parts.references }
|
|
9156
|
-
];
|
|
9157
|
-
return assembleReport("intigriti", parts, sections);
|
|
9158
|
-
}
|
|
9159
|
-
};
|
|
9160
|
-
var IMMUNEFI_TEMPLATE = {
|
|
9161
|
-
id: "immunefi",
|
|
9162
|
-
label: "Immunefi (web3)",
|
|
9163
|
-
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.",
|
|
9164
|
-
requiredSections: [
|
|
9165
|
-
"Bug Description",
|
|
9166
|
-
"Impact",
|
|
9167
|
-
"Severity",
|
|
9168
|
-
"Attack Scenario",
|
|
9169
|
-
"Proof of Concept",
|
|
9170
|
-
"Affected Assets",
|
|
9171
|
-
"Recommendation"
|
|
9172
|
-
],
|
|
9173
|
-
render(finding, ctx = {}) {
|
|
9174
|
-
const parts = buildCommonParts(finding, ctx);
|
|
9175
|
-
const sections = [
|
|
9176
|
-
{ heading: "Bug Description", body: parts.summary },
|
|
9177
|
-
{ heading: "Impact", body: parts.impact },
|
|
9178
|
-
{
|
|
9179
|
-
heading: "Severity",
|
|
9180
|
-
body: `**${immunefiSeverity(finding.severity)}**
|
|
9181
|
-
|
|
9182
|
-
${parts.severityCvss40}
|
|
9183
|
-
|
|
9184
|
-
${parts.severityCvss31}`
|
|
9185
|
-
},
|
|
9186
|
-
{
|
|
9187
|
-
heading: "Attack Scenario",
|
|
9188
|
-
body: parts.attackScenario || stepsBodyOrPoc(parts)
|
|
9189
|
-
},
|
|
9190
|
-
{
|
|
9191
|
-
heading: "Proof of Concept",
|
|
9192
|
-
body: [parts.steps, parts.poc].filter(Boolean).join("\n\n") || "_Attach a runnable PoC / test before submission._"
|
|
9193
|
-
},
|
|
9194
|
-
{ heading: "Affected Assets", body: parts.affected },
|
|
9195
|
-
{ heading: "Recommendation", body: parts.remediation },
|
|
9196
|
-
{ heading: "References", body: parts.references }
|
|
9197
|
-
];
|
|
9198
|
-
return assembleReport("immunefi", parts, sections);
|
|
9199
|
-
}
|
|
9200
|
-
};
|
|
9201
|
-
var GENERIC_TEMPLATE = {
|
|
9202
|
-
id: "generic",
|
|
9203
|
-
label: "Generic / Default",
|
|
9204
|
-
description: "Platform-neutral, impact-first structure: Summary \u2192 Impact \u2192 Affected \u2192 Steps \u2192 PoC \u2192 Severity (CVSS) \u2192 Remediation \u2192 References.",
|
|
9205
|
-
requiredSections: [
|
|
9206
|
-
"Summary",
|
|
9207
|
-
"Impact",
|
|
9208
|
-
"Affected Assets",
|
|
9209
|
-
"Steps to Reproduce",
|
|
9210
|
-
"Proof of Concept",
|
|
9211
|
-
"Severity",
|
|
9212
|
-
"Remediation",
|
|
9213
|
-
"References"
|
|
9214
|
-
],
|
|
9215
|
-
render(finding, ctx = {}) {
|
|
9216
|
-
const parts = buildCommonParts(finding, ctx);
|
|
9217
|
-
const sections = [
|
|
9218
|
-
{ heading: "Summary", body: parts.summary },
|
|
9219
|
-
{ heading: "Impact", body: parts.impact },
|
|
9220
|
-
{ heading: "Affected Assets", body: parts.affected },
|
|
9221
|
-
{ heading: "Steps to Reproduce", body: stepsBodyOrPoc(parts) },
|
|
9222
|
-
{ heading: "Proof of Concept", body: parts.poc || "_See Steps to Reproduce._" },
|
|
9223
|
-
{ heading: "Severity", body: `${parts.severityCvss31}
|
|
9224
|
-
|
|
9225
|
-
_${cvssSourceLabel(parts.cvss)}_` },
|
|
9226
|
-
{ heading: "Remediation", body: parts.remediation },
|
|
9227
|
-
{ heading: "References", body: parts.references }
|
|
9228
|
-
];
|
|
9229
|
-
return assembleReport("generic", parts, sections);
|
|
9230
|
-
}
|
|
9231
|
-
};
|
|
9232
|
-
function cvssSourceLabel(cvss) {
|
|
9233
|
-
return cvss.source === "finding" ? "CVSS source: populated on the finding by 0." : cvss.source === "impact-assessment" ? "CVSS source: exploitability derived from 0's reachability assessment; impact from category \u2014 verify against your deployment." : "CVSS source: heuristic from category + severity \u2014 verify before submission.";
|
|
9234
|
-
}
|
|
9235
|
-
var TEMPLATE_REGISTRY = {
|
|
9236
|
-
hackerone: HACKERONE_TEMPLATE,
|
|
9237
|
-
bugcrowd: BUGCROWD_TEMPLATE,
|
|
9238
|
-
intigriti: INTIGRITI_TEMPLATE,
|
|
9239
|
-
immunefi: IMMUNEFI_TEMPLATE,
|
|
9240
|
-
generic: GENERIC_TEMPLATE
|
|
9241
|
-
};
|
|
9242
|
-
var REPORT_PLATFORMS = Object.values(TEMPLATE_REGISTRY).map((t) => ({
|
|
9243
|
-
id: t.id,
|
|
9244
|
-
label: t.label,
|
|
9245
|
-
description: t.description
|
|
9246
|
-
}));
|
|
9247
|
-
function reportTemplate(platform) {
|
|
9248
|
-
if (platform && platform in TEMPLATE_REGISTRY) {
|
|
9249
|
-
return TEMPLATE_REGISTRY[platform];
|
|
9250
|
-
}
|
|
9251
|
-
return GENERIC_TEMPLATE;
|
|
9252
|
-
}
|
|
9253
|
-
function renderPlatformReport(finding, platform, ctx = {}) {
|
|
9254
|
-
return reportTemplate(platform).render(finding, ctx);
|
|
9255
|
-
}
|
|
9256
|
-
|
|
9257
|
-
// packages/core/dist/disclose/known-marker.js
|
|
9258
|
-
var SOURCE_MARKER_RE = /\b(TODO|FIXME|XXX|HACK)\b(?:[(:]\s*(.*?)\s*[):])?|(\bknown[ -](?:limitation|issue)s?\b|\bdocumented[ -]limitation\b)/gi;
|
|
9259
|
-
function hasKnownMarkerText(source) {
|
|
9260
|
-
SOURCE_MARKER_RE.lastIndex = 0;
|
|
9261
|
-
const matched = SOURCE_MARKER_RE.test(source);
|
|
9262
|
-
SOURCE_MARKER_RE.lastIndex = 0;
|
|
9263
|
-
return matched;
|
|
9264
|
-
}
|
|
9265
|
-
function detectKnownMarkers(source, filePath) {
|
|
9266
|
-
const lines = source.split("\n");
|
|
9267
|
-
const markers = [];
|
|
9268
|
-
for (let i = 0; i < lines.length; i++) {
|
|
9269
|
-
const line = lines[i];
|
|
9270
|
-
SOURCE_MARKER_RE.lastIndex = 0;
|
|
9271
|
-
let match;
|
|
9272
|
-
while ((match = SOURCE_MARKER_RE.exec(line)) !== null) {
|
|
9273
|
-
const tag = match[1];
|
|
9274
|
-
const phrase = match[3];
|
|
9275
|
-
const markerText = tag ?? phrase ?? match[0];
|
|
9276
|
-
const contextLines = [];
|
|
9277
|
-
if (i > 0)
|
|
9278
|
-
contextLines.push(lines[i - 1]);
|
|
9279
|
-
contextLines.push(line);
|
|
9280
|
-
if (i < lines.length - 1)
|
|
9281
|
-
contextLines.push(lines[i + 1]);
|
|
9282
|
-
markers.push({
|
|
9283
|
-
marker: markerText.toLowerCase(),
|
|
9284
|
-
line: line.length > 200 ? line.slice(0, 100) + "..." + line.slice(line.length - 97) : line,
|
|
9285
|
-
lineNumber: i + 1,
|
|
9286
|
-
sourcePath: filePath,
|
|
9287
|
-
context: contextLines.join("\n")
|
|
9288
|
-
});
|
|
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
|
+
};
|
|
9289
8022
|
}
|
|
9290
8023
|
}
|
|
9291
|
-
return {
|
|
9292
|
-
hasKnownMarker: markers.length > 0,
|
|
9293
|
-
markers
|
|
9294
|
-
};
|
|
9295
8024
|
}
|
|
9296
|
-
function
|
|
9297
|
-
|
|
9298
|
-
|
|
9299
|
-
|
|
9300
|
-
|
|
9301
|
-
|
|
9302
|
-
|
|
9303
|
-
|
|
9304
|
-
|
|
9305
|
-
|
|
9306
|
-
|
|
9307
|
-
|
|
9308
|
-
|
|
9309
|
-
|
|
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";
|
|
8097
|
+
}
|
|
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);
|
|
9310
8107
|
}
|
|
9311
|
-
return {
|
|
9312
|
-
hasKnownMarker: allMarkers.length > 0,
|
|
9313
|
-
markers: allMarkers
|
|
9314
|
-
};
|
|
9315
8108
|
}
|
|
9316
8109
|
|
|
9317
8110
|
export {
|
|
9318
8111
|
require_dist,
|
|
9319
|
-
suggestCwesForCategory,
|
|
9320
|
-
formatCweSection,
|
|
9321
|
-
suggestCvss,
|
|
9322
|
-
Cvss4ParseError,
|
|
9323
|
-
computeCvss4BaseScore,
|
|
9324
|
-
cvss4Severity,
|
|
9325
|
-
parseCvss4Vector,
|
|
9326
|
-
formatCvss4Vector,
|
|
9327
|
-
scoreCvss4Vector,
|
|
9328
|
-
suggestCvss4,
|
|
9329
|
-
renderCvssSection,
|
|
9330
|
-
extractFileRefs,
|
|
9331
|
-
verifyAgainstRef,
|
|
9332
|
-
formatPatchStatusSection,
|
|
9333
|
-
detectVersionRange,
|
|
9334
|
-
formatVersionRangeLine,
|
|
9335
|
-
EmptyPocError,
|
|
9336
|
-
redactSensitiveHeaders,
|
|
9337
|
-
redactAuthHeaders,
|
|
9338
|
-
renderAdvisoryMarkdown,
|
|
9339
|
-
REPORT_PLATFORMS,
|
|
9340
|
-
reportTemplate,
|
|
9341
|
-
renderPlatformReport,
|
|
9342
8112
|
hasKnownMarkerText,
|
|
9343
8113
|
detectKnownMarkers,
|
|
9344
|
-
analyzeFindingForKnownMarkers
|
|
8114
|
+
analyzeFindingForKnownMarkers,
|
|
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
|
|
9345
8125
|
};
|