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
|
@@ -4,10 +4,12 @@ const require = __0CreateRequire(import.meta.url);
|
|
|
4
4
|
import {
|
|
5
5
|
analyzeFindingForKnownMarkers,
|
|
6
6
|
detectKnownMarkers,
|
|
7
|
-
extractFileRefs,
|
|
8
|
-
redactSensitiveHeaders,
|
|
9
7
|
require_dist
|
|
10
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-IXT64DV5.js";
|
|
9
|
+
import {
|
|
10
|
+
extractFileRefs,
|
|
11
|
+
redactSensitiveHeaders
|
|
12
|
+
} from "./chunk-UELXHK2Y.js";
|
|
11
13
|
import {
|
|
12
14
|
__toESM
|
|
13
15
|
} from "./chunk-VCSFCHAJ.js";
|
|
@@ -380,720 +382,6 @@ function extractSiblingFix(finding, options) {
|
|
|
380
382
|
};
|
|
381
383
|
}
|
|
382
384
|
|
|
383
|
-
// packages/core/dist/disclose/poc-runtime.js
|
|
384
|
-
import { spawn } from "node:child_process";
|
|
385
|
-
var MAX_CAPTURE_BYTES = 1024 * 1024;
|
|
386
|
-
var DEFAULT_STEP_TIMEOUT_MS = 3e4;
|
|
387
|
-
var PERSONA_HEADER = "X-0-Persona";
|
|
388
|
-
var TRUNCATION_MARKER = "\n\u2026[truncated at 1MiB]";
|
|
389
|
-
var DEFAULT_RPS_PER_HOST = 2;
|
|
390
|
-
var MAX_REDIRECT_HOPS = 5;
|
|
391
|
-
var hostBuckets = /* @__PURE__ */ new Map();
|
|
392
|
-
function getOrInitBucket(host, rps) {
|
|
393
|
-
let bucket = hostBuckets.get(host);
|
|
394
|
-
if (!bucket) {
|
|
395
|
-
bucket = {
|
|
396
|
-
tokens: rps,
|
|
397
|
-
// full bucket on first use
|
|
398
|
-
refillRatePerMs: rps / 1e3,
|
|
399
|
-
capacity: rps,
|
|
400
|
-
lastRefill: Date.now(),
|
|
401
|
-
retryUntil: 0
|
|
402
|
-
};
|
|
403
|
-
hostBuckets.set(host, bucket);
|
|
404
|
-
}
|
|
405
|
-
return bucket;
|
|
406
|
-
}
|
|
407
|
-
function refill(bucket) {
|
|
408
|
-
const now = Date.now();
|
|
409
|
-
const elapsed = now - bucket.lastRefill;
|
|
410
|
-
if (elapsed > 0) {
|
|
411
|
-
bucket.tokens = Math.min(bucket.capacity, bucket.tokens + elapsed * bucket.refillRatePerMs);
|
|
412
|
-
bucket.lastRefill = now;
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
async function acquireHostToken(host, rps) {
|
|
416
|
-
const bucket = getOrInitBucket(host, rps);
|
|
417
|
-
while (Date.now() < bucket.retryUntil) {
|
|
418
|
-
const waitMs = bucket.retryUntil - Date.now();
|
|
419
|
-
await sleep(Math.min(waitMs, 1e3));
|
|
420
|
-
}
|
|
421
|
-
while (true) {
|
|
422
|
-
refill(bucket);
|
|
423
|
-
if (bucket.tokens >= 1) {
|
|
424
|
-
bucket.tokens -= 1;
|
|
425
|
-
return;
|
|
426
|
-
}
|
|
427
|
-
const tokensNeeded = 1 - bucket.tokens;
|
|
428
|
-
const waitMs = Math.max(1, Math.ceil(tokensNeeded / bucket.refillRatePerMs));
|
|
429
|
-
await sleep(waitMs);
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
function markHostRateLimited(host, retryAfterHeader) {
|
|
433
|
-
const bucket = hostBuckets.get(host);
|
|
434
|
-
if (!bucket)
|
|
435
|
-
return;
|
|
436
|
-
const parsed = retryAfterHeader ? parseInt(retryAfterHeader, 10) : NaN;
|
|
437
|
-
const retryAfterMs = Number.isFinite(parsed) && parsed > 0 ? parsed * 1e3 : 0;
|
|
438
|
-
bucket.retryUntil = Date.now() + Math.max(retryAfterMs, 6e4);
|
|
439
|
-
}
|
|
440
|
-
function sleep(ms) {
|
|
441
|
-
return new Promise((r) => setTimeout(r, ms));
|
|
442
|
-
}
|
|
443
|
-
function normalizeHostForMatch(value) {
|
|
444
|
-
const trimmed = value.trim().toLowerCase();
|
|
445
|
-
if (trimmed.startsWith("[")) {
|
|
446
|
-
const end = trimmed.indexOf("]");
|
|
447
|
-
return end === -1 ? trimmed : trimmed.slice(1, end);
|
|
448
|
-
}
|
|
449
|
-
if ((trimmed.match(/:/g) ?? []).length >= 2)
|
|
450
|
-
return trimmed;
|
|
451
|
-
return trimmed.replace(/:\d+$/, "");
|
|
452
|
-
}
|
|
453
|
-
function hostMatchesAllowlist(host, allowlist) {
|
|
454
|
-
if (!allowlist || allowlist.length === 0)
|
|
455
|
-
return true;
|
|
456
|
-
const target = normalizeHostForMatch(host);
|
|
457
|
-
for (const raw of allowlist) {
|
|
458
|
-
const pattern = normalizeHostForMatch(raw);
|
|
459
|
-
if (!pattern)
|
|
460
|
-
continue;
|
|
461
|
-
if (pattern.startsWith("*.")) {
|
|
462
|
-
const suffix = pattern.slice(1);
|
|
463
|
-
if (target.endsWith(suffix) && target.length > suffix.length)
|
|
464
|
-
return true;
|
|
465
|
-
} else if (target === pattern) {
|
|
466
|
-
return true;
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
return false;
|
|
470
|
-
}
|
|
471
|
-
function scopeRequiredResult(step, target, start) {
|
|
472
|
-
if (target.scopeAllowlist && target.scopeAllowlist.length > 0)
|
|
473
|
-
return void 0;
|
|
474
|
-
return {
|
|
475
|
-
stepId: step.id,
|
|
476
|
-
kind: "errored",
|
|
477
|
-
durationMs: Date.now() - start,
|
|
478
|
-
error: "PoC reverify requires a non-empty scope allowlist"
|
|
479
|
-
};
|
|
480
|
-
}
|
|
481
|
-
function extractUrlsFromShellCommand(cmd) {
|
|
482
|
-
const matches = cmd.match(/https?:\/\/[^\s'"]+/g);
|
|
483
|
-
return matches ?? [];
|
|
484
|
-
}
|
|
485
|
-
function dockerRegistryHost(image) {
|
|
486
|
-
const separator = image.indexOf("/");
|
|
487
|
-
if (separator === -1)
|
|
488
|
-
return void 0;
|
|
489
|
-
const firstSegment = image.slice(0, separator);
|
|
490
|
-
return firstSegment.includes(".") || firstSegment.includes(":") || firstSegment === "localhost" ? firstSegment : void 0;
|
|
491
|
-
}
|
|
492
|
-
var deps = { spawn, fetch: globalThis.fetch };
|
|
493
|
-
function setRuntimeDeps(overrides) {
|
|
494
|
-
const previous = deps;
|
|
495
|
-
deps = { ...previous, ...overrides };
|
|
496
|
-
return () => {
|
|
497
|
-
deps = previous;
|
|
498
|
-
};
|
|
499
|
-
}
|
|
500
|
-
async function executePocSteps(finding, target) {
|
|
501
|
-
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
502
|
-
const steps = [];
|
|
503
|
-
const graph = finding.pocSteps ?? [];
|
|
504
|
-
for (const step of graph) {
|
|
505
|
-
const result = await executeStep(step, target);
|
|
506
|
-
steps.push(result);
|
|
507
|
-
if (result.kind === "errored" && step.kind !== "verify") {
|
|
508
|
-
for (let i = graph.indexOf(step) + 1; i < graph.length; i++) {
|
|
509
|
-
steps.push({
|
|
510
|
-
stepId: graph[i].id,
|
|
511
|
-
kind: "skipped",
|
|
512
|
-
durationMs: 0,
|
|
513
|
-
error: "skipped: an earlier step errored"
|
|
514
|
-
});
|
|
515
|
-
}
|
|
516
|
-
break;
|
|
517
|
-
}
|
|
518
|
-
}
|
|
519
|
-
const endedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
520
|
-
return {
|
|
521
|
-
findingId: finding.id,
|
|
522
|
-
startedAt,
|
|
523
|
-
endedAt,
|
|
524
|
-
steps,
|
|
525
|
-
overallVerdict: aggregateVerdict(graph, steps)
|
|
526
|
-
};
|
|
527
|
-
}
|
|
528
|
-
async function executeStep(step, target) {
|
|
529
|
-
const start = Date.now();
|
|
530
|
-
if (target.allowProcessActions === false && (step.action.type === "shell" || step.action.type === "docker")) {
|
|
531
|
-
return {
|
|
532
|
-
stepId: step.id,
|
|
533
|
-
kind: "errored",
|
|
534
|
-
durationMs: Date.now() - start,
|
|
535
|
-
error: `PoC ${step.action.type} actions require an isolated execution environment`
|
|
536
|
-
};
|
|
537
|
-
}
|
|
538
|
-
try {
|
|
539
|
-
switch (step.action.type) {
|
|
540
|
-
case "shell":
|
|
541
|
-
return await runShellStep(step, step.action, target, start);
|
|
542
|
-
case "http":
|
|
543
|
-
return await runHttpStep(step, step.action, target, start);
|
|
544
|
-
case "docker":
|
|
545
|
-
return await runDockerStep(step, step.action, target, start);
|
|
546
|
-
case "note":
|
|
547
|
-
return {
|
|
548
|
-
stepId: step.id,
|
|
549
|
-
kind: "skipped",
|
|
550
|
-
durationMs: Date.now() - start
|
|
551
|
-
};
|
|
552
|
-
default: {
|
|
553
|
-
const _exhaustive = step.action;
|
|
554
|
-
return {
|
|
555
|
-
stepId: step.id,
|
|
556
|
-
kind: "errored",
|
|
557
|
-
durationMs: Date.now() - start,
|
|
558
|
-
error: `unknown action type: ${JSON.stringify(_exhaustive)}`
|
|
559
|
-
};
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
} catch (err) {
|
|
563
|
-
return {
|
|
564
|
-
stepId: step.id,
|
|
565
|
-
kind: "errored",
|
|
566
|
-
durationMs: Date.now() - start,
|
|
567
|
-
error: errMessage(err)
|
|
568
|
-
};
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
|
-
async function runShellStep(step, action, target, start) {
|
|
572
|
-
const scopeError = scopeRequiredResult(step, target, start);
|
|
573
|
-
if (scopeError)
|
|
574
|
-
return scopeError;
|
|
575
|
-
if (target.scopeAllowlist && target.scopeAllowlist.length > 0) {
|
|
576
|
-
for (const u of extractUrlsFromShellCommand(action.cmd)) {
|
|
577
|
-
let host;
|
|
578
|
-
try {
|
|
579
|
-
host = new URL(u).host;
|
|
580
|
-
} catch {
|
|
581
|
-
continue;
|
|
582
|
-
}
|
|
583
|
-
if (!hostMatchesAllowlist(host, target.scopeAllowlist)) {
|
|
584
|
-
return {
|
|
585
|
-
stepId: step.id,
|
|
586
|
-
kind: "errored",
|
|
587
|
-
durationMs: Date.now() - start,
|
|
588
|
-
error: `out-of-scope url in shell cmd: ${u} (allowlist: ${target.scopeAllowlist.join(", ")})`
|
|
589
|
-
};
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
const env = { ...process.env, ...target.env ?? {} };
|
|
594
|
-
const cwd = action.cwd ?? target.cwd;
|
|
595
|
-
const timeoutMs = target.timeoutMs ?? DEFAULT_STEP_TIMEOUT_MS;
|
|
596
|
-
const spawned = await spawnAndCapture("/bin/sh", ["-c", action.cmd], { env, cwd, timeoutMs });
|
|
597
|
-
return finaliseProcessStep(step, spawned, start);
|
|
598
|
-
}
|
|
599
|
-
async function runDockerStep(step, action, target, start) {
|
|
600
|
-
const scopeError = scopeRequiredResult(step, target, start);
|
|
601
|
-
if (scopeError)
|
|
602
|
-
return scopeError;
|
|
603
|
-
const registryHost = dockerRegistryHost(action.image);
|
|
604
|
-
if (registryHost && !hostMatchesAllowlist(registryHost, target.scopeAllowlist)) {
|
|
605
|
-
return {
|
|
606
|
-
stepId: step.id,
|
|
607
|
-
kind: "errored",
|
|
608
|
-
durationMs: Date.now() - start,
|
|
609
|
-
error: `out-of-scope docker registry: ${registryHost} (allowlist: ${target.scopeAllowlist.join(", ")})`
|
|
610
|
-
};
|
|
611
|
-
}
|
|
612
|
-
if (target.scopeAllowlist && target.scopeAllowlist.length > 0) {
|
|
613
|
-
const dockerTokens = [action.image, ...action.args].join(" ");
|
|
614
|
-
for (const u of extractUrlsFromShellCommand(dockerTokens)) {
|
|
615
|
-
let host;
|
|
616
|
-
try {
|
|
617
|
-
host = new URL(u).host;
|
|
618
|
-
} catch {
|
|
619
|
-
continue;
|
|
620
|
-
}
|
|
621
|
-
if (!hostMatchesAllowlist(host, target.scopeAllowlist)) {
|
|
622
|
-
return {
|
|
623
|
-
stepId: step.id,
|
|
624
|
-
kind: "errored",
|
|
625
|
-
durationMs: Date.now() - start,
|
|
626
|
-
error: `out-of-scope url in docker action: ${u} (allowlist: ${target.scopeAllowlist.join(", ")})`
|
|
627
|
-
};
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
}
|
|
631
|
-
const env = { ...process.env, ...target.env ?? {} };
|
|
632
|
-
const cwd = target.cwd;
|
|
633
|
-
const timeoutMs = target.timeoutMs ?? DEFAULT_STEP_TIMEOUT_MS;
|
|
634
|
-
const spawned = await spawnAndCapture("docker", ["run", "--rm", ...action.args, action.image], { env, cwd, timeoutMs });
|
|
635
|
-
return finaliseProcessStep(step, spawned, start);
|
|
636
|
-
}
|
|
637
|
-
async function runHttpStep(step, action, target, start) {
|
|
638
|
-
const scopeError = scopeRequiredResult(step, target, start);
|
|
639
|
-
if (scopeError)
|
|
640
|
-
return scopeError;
|
|
641
|
-
const url = resolveUrl(action.url, target.baseUrl);
|
|
642
|
-
if (!url) {
|
|
643
|
-
return {
|
|
644
|
-
stepId: step.id,
|
|
645
|
-
kind: "errored",
|
|
646
|
-
durationMs: Date.now() - start,
|
|
647
|
-
error: `http step has a relative url (${action.url}) but no target.baseUrl was provided`
|
|
648
|
-
};
|
|
649
|
-
}
|
|
650
|
-
let host;
|
|
651
|
-
try {
|
|
652
|
-
host = new URL(url).host;
|
|
653
|
-
} catch {
|
|
654
|
-
return {
|
|
655
|
-
stepId: step.id,
|
|
656
|
-
kind: "errored",
|
|
657
|
-
durationMs: Date.now() - start,
|
|
658
|
-
error: `http step url is not a valid URL: ${url}`
|
|
659
|
-
};
|
|
660
|
-
}
|
|
661
|
-
if (!hostMatchesAllowlist(host, target.scopeAllowlist)) {
|
|
662
|
-
return {
|
|
663
|
-
stepId: step.id,
|
|
664
|
-
kind: "errored",
|
|
665
|
-
durationMs: Date.now() - start,
|
|
666
|
-
error: `out-of-scope host: ${host} (allowlist: ${target.scopeAllowlist.join(", ")})`
|
|
667
|
-
};
|
|
668
|
-
}
|
|
669
|
-
const rps = target.rpsPerHost ?? DEFAULT_RPS_PER_HOST;
|
|
670
|
-
await acquireHostToken(host, rps);
|
|
671
|
-
const headers = mergePersonaHeaders(action.headers ?? {}, target);
|
|
672
|
-
const timeoutMs = target.timeoutMs ?? DEFAULT_STEP_TIMEOUT_MS;
|
|
673
|
-
const ac = new AbortController();
|
|
674
|
-
const timer = setTimeout(() => ac.abort(), timeoutMs);
|
|
675
|
-
let finalResponse;
|
|
676
|
-
let body = "";
|
|
677
|
-
let currentUrl = url;
|
|
678
|
-
let redirectCount = 0;
|
|
679
|
-
try {
|
|
680
|
-
while (true) {
|
|
681
|
-
finalResponse = await deps.fetch(currentUrl, {
|
|
682
|
-
method: action.method,
|
|
683
|
-
headers,
|
|
684
|
-
body: action.body,
|
|
685
|
-
signal: ac.signal,
|
|
686
|
-
redirect: "manual"
|
|
687
|
-
});
|
|
688
|
-
const status = finalResponse.status;
|
|
689
|
-
const isRedirect = [301, 302, 303, 307, 308].includes(status);
|
|
690
|
-
if (!isRedirect) {
|
|
691
|
-
body = await readBodyCapped(finalResponse);
|
|
692
|
-
if (status === 429) {
|
|
693
|
-
const retryAfter = finalResponse.headers.get("retry-after");
|
|
694
|
-
markHostRateLimited(host, retryAfter);
|
|
695
|
-
}
|
|
696
|
-
break;
|
|
697
|
-
}
|
|
698
|
-
redirectCount++;
|
|
699
|
-
if (redirectCount > MAX_REDIRECT_HOPS) {
|
|
700
|
-
try {
|
|
701
|
-
finalResponse.body?.cancel();
|
|
702
|
-
} catch {
|
|
703
|
-
}
|
|
704
|
-
clearTimeout(timer);
|
|
705
|
-
return {
|
|
706
|
-
stepId: step.id,
|
|
707
|
-
kind: "errored",
|
|
708
|
-
durationMs: Date.now() - start,
|
|
709
|
-
error: `too many redirects (exceeded ${MAX_REDIRECT_HOPS} hops)`
|
|
710
|
-
};
|
|
711
|
-
}
|
|
712
|
-
const location = finalResponse.headers.get("location");
|
|
713
|
-
if (!location) {
|
|
714
|
-
body = await readBodyCapped(finalResponse);
|
|
715
|
-
break;
|
|
716
|
-
}
|
|
717
|
-
const nextUrlStr = new URL(location, currentUrl).toString();
|
|
718
|
-
const nextHost = new URL(nextUrlStr).host;
|
|
719
|
-
if (!hostMatchesAllowlist(nextHost, target.scopeAllowlist)) {
|
|
720
|
-
try {
|
|
721
|
-
finalResponse.body?.cancel();
|
|
722
|
-
} catch {
|
|
723
|
-
}
|
|
724
|
-
clearTimeout(timer);
|
|
725
|
-
return {
|
|
726
|
-
stepId: step.id,
|
|
727
|
-
kind: "errored",
|
|
728
|
-
durationMs: Date.now() - start,
|
|
729
|
-
error: `redirect to out-of-scope host: ${nextHost} (allowlist: ${target.scopeAllowlist.join(", ")})`
|
|
730
|
-
};
|
|
731
|
-
}
|
|
732
|
-
try {
|
|
733
|
-
finalResponse.body?.cancel();
|
|
734
|
-
} catch {
|
|
735
|
-
}
|
|
736
|
-
currentUrl = nextUrlStr;
|
|
737
|
-
}
|
|
738
|
-
} catch (err) {
|
|
739
|
-
clearTimeout(timer);
|
|
740
|
-
const aborted = ac.signal.aborted;
|
|
741
|
-
return {
|
|
742
|
-
stepId: step.id,
|
|
743
|
-
kind: "errored",
|
|
744
|
-
durationMs: Date.now() - start,
|
|
745
|
-
error: aborted ? `timeout after ${timeoutMs}ms` : errMessage(err)
|
|
746
|
-
};
|
|
747
|
-
} finally {
|
|
748
|
-
clearTimeout(timer);
|
|
749
|
-
}
|
|
750
|
-
const verdict = evaluateExpect(step.expect, {
|
|
751
|
-
status: finalResponse.status,
|
|
752
|
-
body
|
|
753
|
-
});
|
|
754
|
-
return {
|
|
755
|
-
stepId: step.id,
|
|
756
|
-
kind: verdict.kind,
|
|
757
|
-
observedStatus: finalResponse.status,
|
|
758
|
-
observedResponseBody: body,
|
|
759
|
-
durationMs: Date.now() - start,
|
|
760
|
-
...verdict.error ? { error: verdict.error } : {}
|
|
761
|
-
};
|
|
762
|
-
}
|
|
763
|
-
function resolveUrl(stepUrl, baseUrl) {
|
|
764
|
-
try {
|
|
765
|
-
new URL(stepUrl);
|
|
766
|
-
return stepUrl;
|
|
767
|
-
} catch {
|
|
768
|
-
}
|
|
769
|
-
if (!baseUrl)
|
|
770
|
-
return null;
|
|
771
|
-
try {
|
|
772
|
-
return new URL(stepUrl, baseUrl).toString();
|
|
773
|
-
} catch {
|
|
774
|
-
return null;
|
|
775
|
-
}
|
|
776
|
-
}
|
|
777
|
-
function mergePersonaHeaders(stepHeaders, target) {
|
|
778
|
-
const merged = {};
|
|
779
|
-
let personaName;
|
|
780
|
-
for (const [k, v] of Object.entries(stepHeaders)) {
|
|
781
|
-
if (k.toLowerCase() === PERSONA_HEADER.toLowerCase()) {
|
|
782
|
-
personaName = v;
|
|
783
|
-
continue;
|
|
784
|
-
}
|
|
785
|
-
merged[k] = v;
|
|
786
|
-
}
|
|
787
|
-
if (!personaName)
|
|
788
|
-
return merged;
|
|
789
|
-
const persona = target.personas?.[personaName];
|
|
790
|
-
if (!persona)
|
|
791
|
-
return merged;
|
|
792
|
-
if (persona.headers) {
|
|
793
|
-
for (const [k, v] of Object.entries(persona.headers)) {
|
|
794
|
-
if (!(k in merged))
|
|
795
|
-
merged[k] = v;
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
if (persona.cookies && !("cookie" in lowerKeys(merged))) {
|
|
799
|
-
merged["Cookie"] = persona.cookies;
|
|
800
|
-
}
|
|
801
|
-
return merged;
|
|
802
|
-
}
|
|
803
|
-
function lowerKeys(obj) {
|
|
804
|
-
const out = {};
|
|
805
|
-
for (const [k, v] of Object.entries(obj))
|
|
806
|
-
out[k.toLowerCase()] = v;
|
|
807
|
-
return out;
|
|
808
|
-
}
|
|
809
|
-
async function readBodyCapped(response) {
|
|
810
|
-
if (!response.body)
|
|
811
|
-
return "";
|
|
812
|
-
const reader = response.body.getReader();
|
|
813
|
-
const decoder = new TextDecoder("utf-8", { fatal: false });
|
|
814
|
-
let captured = "";
|
|
815
|
-
let truncated = false;
|
|
816
|
-
while (true) {
|
|
817
|
-
const { value, done } = await reader.read();
|
|
818
|
-
if (done)
|
|
819
|
-
break;
|
|
820
|
-
if (value) {
|
|
821
|
-
const chunk = decoder.decode(value, { stream: true });
|
|
822
|
-
if (captured.length + chunk.length > MAX_CAPTURE_BYTES) {
|
|
823
|
-
captured += chunk.slice(0, MAX_CAPTURE_BYTES - captured.length);
|
|
824
|
-
truncated = true;
|
|
825
|
-
try {
|
|
826
|
-
await reader.cancel();
|
|
827
|
-
} catch {
|
|
828
|
-
}
|
|
829
|
-
break;
|
|
830
|
-
}
|
|
831
|
-
captured += chunk;
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
return truncated ? captured + TRUNCATION_MARKER : captured;
|
|
835
|
-
}
|
|
836
|
-
function spawnAndCapture(cmd, args, opts) {
|
|
837
|
-
return new Promise((resolveP) => {
|
|
838
|
-
let child;
|
|
839
|
-
try {
|
|
840
|
-
child = deps.spawn(cmd, args, {
|
|
841
|
-
env: opts.env,
|
|
842
|
-
cwd: opts.cwd,
|
|
843
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
844
|
-
});
|
|
845
|
-
} catch (err) {
|
|
846
|
-
resolveP({
|
|
847
|
-
exitCode: null,
|
|
848
|
-
stdout: "",
|
|
849
|
-
stderr: "",
|
|
850
|
-
timedOut: false,
|
|
851
|
-
error: errMessage(err)
|
|
852
|
-
});
|
|
853
|
-
return;
|
|
854
|
-
}
|
|
855
|
-
let stdout = "";
|
|
856
|
-
let stderr = "";
|
|
857
|
-
let stdoutTruncated = false;
|
|
858
|
-
let stderrTruncated = false;
|
|
859
|
-
let timedOut = false;
|
|
860
|
-
let settled = false;
|
|
861
|
-
const timer = setTimeout(() => {
|
|
862
|
-
timedOut = true;
|
|
863
|
-
try {
|
|
864
|
-
child.kill("SIGKILL");
|
|
865
|
-
} catch {
|
|
866
|
-
}
|
|
867
|
-
}, opts.timeoutMs);
|
|
868
|
-
child.stdout?.on("data", (chunk) => {
|
|
869
|
-
const s = typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
870
|
-
if (stdout.length + s.length > MAX_CAPTURE_BYTES) {
|
|
871
|
-
if (!stdoutTruncated) {
|
|
872
|
-
stdout += s.slice(0, MAX_CAPTURE_BYTES - stdout.length);
|
|
873
|
-
stdoutTruncated = true;
|
|
874
|
-
}
|
|
875
|
-
return;
|
|
876
|
-
}
|
|
877
|
-
stdout += s;
|
|
878
|
-
});
|
|
879
|
-
child.stderr?.on("data", (chunk) => {
|
|
880
|
-
const s = typeof chunk === "string" ? chunk : chunk.toString("utf8");
|
|
881
|
-
if (stderr.length + s.length > MAX_CAPTURE_BYTES) {
|
|
882
|
-
if (!stderrTruncated) {
|
|
883
|
-
stderr += s.slice(0, MAX_CAPTURE_BYTES - stderr.length);
|
|
884
|
-
stderrTruncated = true;
|
|
885
|
-
}
|
|
886
|
-
return;
|
|
887
|
-
}
|
|
888
|
-
stderr += s;
|
|
889
|
-
});
|
|
890
|
-
const settle = (exit, errorMsg) => {
|
|
891
|
-
if (settled)
|
|
892
|
-
return;
|
|
893
|
-
settled = true;
|
|
894
|
-
clearTimeout(timer);
|
|
895
|
-
resolveP({
|
|
896
|
-
exitCode: exit,
|
|
897
|
-
stdout: stdoutTruncated ? stdout + TRUNCATION_MARKER : stdout,
|
|
898
|
-
stderr: stderrTruncated ? stderr + TRUNCATION_MARKER : stderr,
|
|
899
|
-
timedOut,
|
|
900
|
-
error: errorMsg
|
|
901
|
-
});
|
|
902
|
-
};
|
|
903
|
-
child.on("error", (err) => {
|
|
904
|
-
settle(null, errMessage(err));
|
|
905
|
-
});
|
|
906
|
-
child.on("close", (code) => {
|
|
907
|
-
settle(code);
|
|
908
|
-
});
|
|
909
|
-
});
|
|
910
|
-
}
|
|
911
|
-
function finaliseProcessStep(step, spawned, start) {
|
|
912
|
-
const durationMs = Date.now() - start;
|
|
913
|
-
if (spawned.timedOut) {
|
|
914
|
-
return {
|
|
915
|
-
stepId: step.id,
|
|
916
|
-
kind: "errored",
|
|
917
|
-
observedStdout: spawned.stdout,
|
|
918
|
-
observedStderr: spawned.stderr,
|
|
919
|
-
durationMs,
|
|
920
|
-
error: `timeout after ${durationMs}ms`
|
|
921
|
-
};
|
|
922
|
-
}
|
|
923
|
-
if (spawned.error && spawned.exitCode === null) {
|
|
924
|
-
return {
|
|
925
|
-
stepId: step.id,
|
|
926
|
-
kind: "errored",
|
|
927
|
-
observedStdout: spawned.stdout,
|
|
928
|
-
observedStderr: spawned.stderr,
|
|
929
|
-
durationMs,
|
|
930
|
-
error: spawned.error
|
|
931
|
-
};
|
|
932
|
-
}
|
|
933
|
-
const verdict = evaluateExpect(step.expect, {
|
|
934
|
-
exitCode: spawned.exitCode,
|
|
935
|
-
stdout: spawned.stdout
|
|
936
|
-
});
|
|
937
|
-
const result = {
|
|
938
|
-
stepId: step.id,
|
|
939
|
-
kind: verdict.kind,
|
|
940
|
-
observedStdout: spawned.stdout,
|
|
941
|
-
observedStderr: spawned.stderr,
|
|
942
|
-
durationMs
|
|
943
|
-
};
|
|
944
|
-
if (spawned.exitCode !== null)
|
|
945
|
-
result.observedExit = spawned.exitCode;
|
|
946
|
-
if (verdict.error)
|
|
947
|
-
result.error = verdict.error;
|
|
948
|
-
return result;
|
|
949
|
-
}
|
|
950
|
-
function evaluateExpect(expect, obs) {
|
|
951
|
-
if (!expect) {
|
|
952
|
-
return { kind: "passed" };
|
|
953
|
-
}
|
|
954
|
-
switch (expect.type) {
|
|
955
|
-
case "exit-zero": {
|
|
956
|
-
if (obs.exitCode === 0)
|
|
957
|
-
return { kind: "passed" };
|
|
958
|
-
return {
|
|
959
|
-
kind: "failed",
|
|
960
|
-
error: `expected exit-zero, got exitCode=${String(obs.exitCode ?? "unknown")}`
|
|
961
|
-
};
|
|
962
|
-
}
|
|
963
|
-
case "http-status": {
|
|
964
|
-
const wanted = Array.isArray(expect.status) ? expect.status : [expect.status];
|
|
965
|
-
if (typeof obs.status === "number" && wanted.includes(obs.status)) {
|
|
966
|
-
return { kind: "passed" };
|
|
967
|
-
}
|
|
968
|
-
return {
|
|
969
|
-
kind: "failed",
|
|
970
|
-
error: `expected http-status in [${wanted.join(",")}], got ${String(obs.status ?? "no-response")}`
|
|
971
|
-
};
|
|
972
|
-
}
|
|
973
|
-
case "body-contains": {
|
|
974
|
-
const haystack = obs.body ?? obs.stdout ?? "";
|
|
975
|
-
if (haystack.includes(expect.text))
|
|
976
|
-
return { kind: "passed" };
|
|
977
|
-
return {
|
|
978
|
-
kind: "failed",
|
|
979
|
-
error: `expected body-contains '${expect.text}', not found in observed output`
|
|
980
|
-
};
|
|
981
|
-
}
|
|
982
|
-
case "body-matches": {
|
|
983
|
-
const haystack = obs.body ?? obs.stdout ?? "";
|
|
984
|
-
let re;
|
|
985
|
-
try {
|
|
986
|
-
re = new RegExp(expect.pattern);
|
|
987
|
-
} catch (err) {
|
|
988
|
-
return { kind: "errored", error: `invalid regex: ${errMessage(err)}` };
|
|
989
|
-
}
|
|
990
|
-
if (re.test(haystack))
|
|
991
|
-
return { kind: "passed" };
|
|
992
|
-
return {
|
|
993
|
-
kind: "failed",
|
|
994
|
-
error: `expected body-matches /${expect.pattern}/, no match in observed output`
|
|
995
|
-
};
|
|
996
|
-
}
|
|
997
|
-
case "file-exists": {
|
|
998
|
-
return {
|
|
999
|
-
kind: "errored",
|
|
1000
|
-
error: "file-exists predicate cannot be evaluated against a network target; rewrite as a shell action with `[ -e <path> ]`"
|
|
1001
|
-
};
|
|
1002
|
-
}
|
|
1003
|
-
default: {
|
|
1004
|
-
const _exhaustive = expect;
|
|
1005
|
-
return {
|
|
1006
|
-
kind: "errored",
|
|
1007
|
-
error: `unknown expect type: ${JSON.stringify(_exhaustive)}`
|
|
1008
|
-
};
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1011
|
-
}
|
|
1012
|
-
function aggregateVerdict(graph, steps) {
|
|
1013
|
-
if (graph.length === 0) {
|
|
1014
|
-
return "could_not_run";
|
|
1015
|
-
}
|
|
1016
|
-
const byId = new Map(steps.map((s) => [s.stepId, s]));
|
|
1017
|
-
let reachedExploitOrVerify = false;
|
|
1018
|
-
for (const step of graph) {
|
|
1019
|
-
const result = byId.get(step.id);
|
|
1020
|
-
if (!result)
|
|
1021
|
-
continue;
|
|
1022
|
-
if (step.kind === "exploit" || step.kind === "verify") {
|
|
1023
|
-
reachedExploitOrVerify = true;
|
|
1024
|
-
}
|
|
1025
|
-
if (result.kind === "errored" && (step.kind === "setup" || step.kind === "auth" || step.kind === "prerequisite")) {
|
|
1026
|
-
return "could_not_run";
|
|
1027
|
-
}
|
|
1028
|
-
}
|
|
1029
|
-
const verifySteps = graph.filter((s) => s.kind === "verify");
|
|
1030
|
-
if (verifySteps.length > 0) {
|
|
1031
|
-
let anyFailed = false;
|
|
1032
|
-
let anyErrored = false;
|
|
1033
|
-
let allPassed = true;
|
|
1034
|
-
for (const v of verifySteps) {
|
|
1035
|
-
const result = byId.get(v.id);
|
|
1036
|
-
if (!result || result.kind === "skipped") {
|
|
1037
|
-
allPassed = false;
|
|
1038
|
-
anyErrored = true;
|
|
1039
|
-
continue;
|
|
1040
|
-
}
|
|
1041
|
-
if (result.kind === "failed") {
|
|
1042
|
-
anyFailed = true;
|
|
1043
|
-
allPassed = false;
|
|
1044
|
-
} else if (result.kind === "errored") {
|
|
1045
|
-
anyErrored = true;
|
|
1046
|
-
allPassed = false;
|
|
1047
|
-
}
|
|
1048
|
-
}
|
|
1049
|
-
if (allPassed)
|
|
1050
|
-
return "exploit_still_works";
|
|
1051
|
-
if (anyFailed)
|
|
1052
|
-
return "exploit_broken";
|
|
1053
|
-
if (anyErrored)
|
|
1054
|
-
return "could_not_run";
|
|
1055
|
-
}
|
|
1056
|
-
const exploitSteps = graph.filter((s) => s.kind === "exploit");
|
|
1057
|
-
if (exploitSteps.length > 0) {
|
|
1058
|
-
let anyFailed = false;
|
|
1059
|
-
let anyErrored = false;
|
|
1060
|
-
let allPassed = true;
|
|
1061
|
-
for (const e of exploitSteps) {
|
|
1062
|
-
const result = byId.get(e.id);
|
|
1063
|
-
if (!result || result.kind === "skipped") {
|
|
1064
|
-
allPassed = false;
|
|
1065
|
-
anyErrored = true;
|
|
1066
|
-
continue;
|
|
1067
|
-
}
|
|
1068
|
-
if (result.kind === "failed") {
|
|
1069
|
-
anyFailed = true;
|
|
1070
|
-
allPassed = false;
|
|
1071
|
-
} else if (result.kind === "errored") {
|
|
1072
|
-
anyErrored = true;
|
|
1073
|
-
allPassed = false;
|
|
1074
|
-
}
|
|
1075
|
-
}
|
|
1076
|
-
if (allPassed)
|
|
1077
|
-
return "exploit_still_works";
|
|
1078
|
-
if (anyFailed)
|
|
1079
|
-
return "exploit_broken";
|
|
1080
|
-
if (anyErrored)
|
|
1081
|
-
return "could_not_run";
|
|
1082
|
-
}
|
|
1083
|
-
return reachedExploitOrVerify ? "exploit_still_works" : "could_not_run";
|
|
1084
|
-
}
|
|
1085
|
-
function errMessage(err) {
|
|
1086
|
-
if (err instanceof Error)
|
|
1087
|
-
return err.message;
|
|
1088
|
-
if (typeof err === "string")
|
|
1089
|
-
return err;
|
|
1090
|
-
try {
|
|
1091
|
-
return JSON.stringify(err);
|
|
1092
|
-
} catch {
|
|
1093
|
-
return String(err);
|
|
1094
|
-
}
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
385
|
// packages/core/dist/disclose/bundle.js
|
|
1098
386
|
function decideFilingState(inputs) {
|
|
1099
387
|
const { patchStatus, behaviouralReport, dropFixed, keepUnrun, emptyPoc } = inputs;
|
|
@@ -1972,10 +1260,6 @@ export {
|
|
|
1972
1260
|
composeStepSession,
|
|
1973
1261
|
renderExploitScreenshot,
|
|
1974
1262
|
extractSiblingFix,
|
|
1975
|
-
MAX_CAPTURE_BYTES,
|
|
1976
|
-
DEFAULT_STEP_TIMEOUT_MS,
|
|
1977
|
-
setRuntimeDeps,
|
|
1978
|
-
executePocSteps,
|
|
1979
1263
|
decideFilingState,
|
|
1980
1264
|
dropSlug,
|
|
1981
1265
|
droppedFilename,
|