@pensar/apex 2.0.1 → 2.0.2-canary.09dbe74f

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/build/{agent-x7n47c84.js → agent-067x1n67.js} +9 -9
  2. package/build/{agent-6nhperp2.js → agent-3n8msbqb.js} +10 -8
  3. package/build/agent-m3bsrs09.js +19 -0
  4. package/build/{apps-2ac4vt09.js → apps-7fhwknrj.js} +20 -15
  5. package/build/{auth-bmt98hz0.js → auth-a1z7ew5p.js} +15 -15
  6. package/build/authentication-69q16waz.js +19 -0
  7. package/build/blackboxAgent-80y8j499.js +19 -0
  8. package/build/{blackboxPentest-xngbtdxb.js → blackboxPentest-aay3kx94.js} +13 -13
  9. package/build/{cli-hk03x6fq.js → cli-117ypqqj.js} +2 -1
  10. package/build/{cli-fa7nrded.js → cli-2hw7jen3.js} +5 -5
  11. package/build/{cli-zpdmnz8c.js → cli-2p56h4nq.js} +881 -373
  12. package/build/{cli-mfzkhttr.js → cli-5e5gq617.js} +22 -20
  13. package/build/{cli-ddtmgbqv.js → cli-8q9kr0x9.js} +2 -2
  14. package/build/{cli-z1dapp7v.js → cli-a3pzv462.js} +71 -33
  15. package/build/{cli-eptabm2j.js → cli-eg35gebv.js} +1 -1
  16. package/build/{cli-0yptvbbm.js → cli-hh404jw6.js} +10 -9
  17. package/build/{cli-1f5zzrxj.js → cli-k8zpadm5.js} +1 -1
  18. package/build/{cli-f93g10xk.js → cli-mcn1ar96.js} +2 -2
  19. package/build/{cli-pyzw545d.js → cli-ncecs1a9.js} +76 -11
  20. package/build/{cli-w2st266h.js → cli-pppvjz87.js} +33 -4
  21. package/build/{cli-fxtbkw2f.js → cli-pyz8tnrp.js} +6 -6
  22. package/build/{cli-8xknm7d9.js → cli-q24twygk.js} +1 -1
  23. package/build/{cli-8g5cwvbm.js → cli-r9yh5mka.js} +2 -2
  24. package/build/{cli-cc13ydyx.js → cli-sgrt7t9v.js} +9 -9
  25. package/build/{cli-88bhxzr1.js → cli-tt7ps59g.js} +4 -4
  26. package/build/cli.js +52 -47
  27. package/build/{config-j0gfjhrm.js → config-8rnbn2d0.js} +4 -4
  28. package/build/{doctor-zn8ms7gs.js → doctor-jddjv64a.js} +8 -8
  29. package/build/{fixes-d8ytvyzn.js → fixes-rfrer4t8.js} +15 -15
  30. package/build/{index-hjvqqkem.js → index-0nz7y997.js} +4 -4
  31. package/build/{index-2t2cg8x0.js → index-mk5mxrjd.js} +8 -8
  32. package/build/{index-k6ttkac6.js → index-nw5vbcg9.js} +13 -12
  33. package/build/{index-528cyewc.js → index-pr80jx2t.js} +116 -70
  34. package/build/{index-a1sy2zak.js → index-rg2czyx7.js} +2 -2
  35. package/build/{index-3cbcjqw1.js → index-speg9ebc.js} +9 -9
  36. package/build/{index-9d2es97h.js → index-syz3srk7.js} +3 -3
  37. package/build/{issues-17kdjtdg.js → issues-484xb633.js} +15 -15
  38. package/build/{logs-r4rjar4m.js → logs-kmw11amx.js} +15 -15
  39. package/build/{offesecAgent-azd8ahkm.js → offesecAgent-ykx4cmb1.js} +8 -8
  40. package/build/{parse-15kqmy2v.js → parse-7djk9jyf.js} +1 -1
  41. package/build/pentest-4v06edvf.js +28 -0
  42. package/build/{pentests-npjb5q1h.js → pentests-jpc8hjdm.js} +15 -15
  43. package/build/{targetedPentest-m24wvscc.js → targetedPentest-zkezvsdt.js} +9 -9
  44. package/build/targets-p4d186xd.js +113 -0
  45. package/build/threatModel-k41x41eg.js +26 -0
  46. package/build/{uninstall-7pm6zcah.js → uninstall-s75nx85e.js} +9 -9
  47. package/build/{upload-wg0vxmk0.js → upload-57y9k8gs.js} +6 -6
  48. package/build/{utils-gd1y4t26.js → utils-dwkm0fb2.js} +5 -5
  49. package/package.json +9 -8
  50. package/build/agent-4g69jwmq.js +0 -19
  51. package/build/authentication-c0aj9zaz.js +0 -19
  52. package/build/blackboxAgent-sgph70e4.js +0 -19
  53. package/build/pentest-2vsjf0j8.js +0 -28
  54. package/build/threatModel-7akmfzzm.js +0 -26
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  detectOSAndEnhancePrompt
3
- } from "./cli-cc13ydyx.js";
3
+ } from "./cli-sgrt7t9v.js";
4
4
  import {
5
5
  parseTargetUrl
6
6
  } from "./cli-c8131c4q.js";
@@ -26,14 +26,14 @@ import {
26
26
  scopedLogger,
27
27
  streamResponse,
28
28
  write
29
- } from "./cli-z1dapp7v.js";
29
+ } from "./cli-a3pzv462.js";
30
30
  import {
31
31
  ensureValidToken,
32
32
  getPensarApiUrl,
33
33
  init_auth,
34
34
  init_constants,
35
35
  signGatewayRequest
36
- } from "./cli-8g5cwvbm.js";
36
+ } from "./cli-r9yh5mka.js";
37
37
  import {
38
38
  _enum,
39
39
  _null,
@@ -64,7 +64,7 @@ import {
64
64
  import {
65
65
  config,
66
66
  init_config
67
- } from "./cli-eptabm2j.js";
67
+ } from "./cli-eg35gebv.js";
68
68
  import {
69
69
  __commonJS,
70
70
  __require,
@@ -42486,8 +42486,8 @@ var require_core3 = __commonJS((exports) => {
42486
42486
  function many1(p) {
42487
42487
  return ab(p, many(p), (head, tail) => [head, ...tail]);
42488
42488
  }
42489
- function ab(pa, pb, join13) {
42490
- return (data, i) => mapOuter(pa(data, i), (ma) => mapInner(pb(data, ma.position), (vb, j) => join13(ma.value, vb, data, i, j)));
42489
+ function ab(pa, pb, join14) {
42490
+ return (data, i) => mapOuter(pa(data, i), (ma) => mapInner(pb(data, ma.position), (vb, j) => join14(ma.value, vb, data, i, j)));
42491
42491
  }
42492
42492
  function left(pa, pb) {
42493
42493
  return ab(pa, pb, (va) => va);
@@ -42495,8 +42495,8 @@ var require_core3 = __commonJS((exports) => {
42495
42495
  function right(pa, pb) {
42496
42496
  return ab(pa, pb, (va, vb) => vb);
42497
42497
  }
42498
- function abc(pa, pb, pc, join13) {
42499
- return (data, i) => mapOuter(pa(data, i), (ma) => mapOuter(pb(data, ma.position), (mb) => mapInner(pc(data, mb.position), (vc, j) => join13(ma.value, mb.value, vc, data, i, j))));
42498
+ function abc(pa, pb, pc, join14) {
42499
+ return (data, i) => mapOuter(pa(data, i), (ma) => mapOuter(pb(data, ma.position), (mb) => mapInner(pc(data, mb.position), (vc, j) => join14(ma.value, mb.value, vc, data, i, j))));
42500
42500
  }
42501
42501
  function middle(pa, pb, pc) {
42502
42502
  return abc(pa, pb, pc, (ra, rb) => rb);
@@ -71179,7 +71179,7 @@ var require_thread_stream = __commonJS((exports, module) => {
71179
71179
  var { version } = require_package5();
71180
71180
  var { EventEmitter: EventEmitter2 } = __require("events");
71181
71181
  var { Worker } = __require("worker_threads");
71182
- var { join: join13 } = __require("path");
71182
+ var { join: join14 } = __require("path");
71183
71183
  var { pathToFileURL } = __require("url");
71184
71184
  var { wait } = require_wait();
71185
71185
  var {
@@ -71215,7 +71215,7 @@ var require_thread_stream = __commonJS((exports, module) => {
71215
71215
  function createWorker(stream, opts) {
71216
71216
  const { filename, workerData } = opts;
71217
71217
  const bundlerOverrides = "__bundlerPathsOverrides" in globalThis ? globalThis.__bundlerPathsOverrides : {};
71218
- const toExecute = bundlerOverrides["thread-stream-worker"] || join13(__dirname, "lib", "worker.js");
71218
+ const toExecute = bundlerOverrides["thread-stream-worker"] || join14(__dirname, "lib", "worker.js");
71219
71219
  const worker = new Worker(toExecute, {
71220
71220
  ...opts.workerOpts,
71221
71221
  trackUnmanagedFds: false,
@@ -71601,10 +71601,10 @@ var require_thread_stream = __commonJS((exports, module) => {
71601
71601
  // node_modules/pino/lib/transport.js
71602
71602
  var require_transport = __commonJS((exports, module) => {
71603
71603
  var __dirname = "/home/runner/work/apex/apex/node_modules/pino/lib";
71604
- var { createRequire: createRequire2 } = __require("module");
71604
+ var { createRequire: createRequire3 } = __require("module");
71605
71605
  var { existsSync: existsSync9 } = __require("node:fs");
71606
71606
  var getCallers = require_caller();
71607
- var { join: join13, isAbsolute: isAbsolute2, sep } = __require("node:path");
71607
+ var { join: join14, isAbsolute: isAbsolute2, sep } = __require("node:path");
71608
71608
  var { fileURLToPath } = __require("node:url");
71609
71609
  var sleep = require_atomic_sleep();
71610
71610
  var onExit = require_on_exit_leak_free();
@@ -71757,7 +71757,7 @@ var require_transport = __commonJS((exports, module) => {
71757
71757
  throw new Error("only one of target or targets can be specified");
71758
71758
  }
71759
71759
  if (targets) {
71760
- target = bundlerOverrides["pino-worker"] || join13(__dirname, "worker.js");
71760
+ target = bundlerOverrides["pino-worker"] || join14(__dirname, "worker.js");
71761
71761
  options.targets = targets.filter((dest) => dest.target).map((dest) => {
71762
71762
  return {
71763
71763
  ...dest,
@@ -71774,7 +71774,7 @@ var require_transport = __commonJS((exports, module) => {
71774
71774
  });
71775
71775
  });
71776
71776
  } else if (pipeline2) {
71777
- target = bundlerOverrides["pino-worker"] || join13(__dirname, "worker.js");
71777
+ target = bundlerOverrides["pino-worker"] || join14(__dirname, "worker.js");
71778
71778
  options.pipelines = [pipeline2.map((dest) => {
71779
71779
  return {
71780
71780
  ...dest,
@@ -71797,13 +71797,13 @@ var require_transport = __commonJS((exports, module) => {
71797
71797
  return origin;
71798
71798
  }
71799
71799
  if (origin === "pino/file") {
71800
- return join13(__dirname, "..", "file.js");
71800
+ return join14(__dirname, "..", "file.js");
71801
71801
  }
71802
71802
  let fixTarget2;
71803
71803
  for (const filePath of callers) {
71804
71804
  try {
71805
71805
  const context = filePath === "node:repl" ? process.cwd() + sep : filePath;
71806
- fixTarget2 = createRequire2(context).resolve(origin);
71806
+ fixTarget2 = createRequire3(context).resolve(origin);
71807
71807
  break;
71808
71808
  } catch (err) {
71809
71809
  continue;
@@ -72726,7 +72726,7 @@ var require_safe_stable_stringify = __commonJS((exports, module) => {
72726
72726
  return circularValue;
72727
72727
  }
72728
72728
  let res = "";
72729
- let join13 = ",";
72729
+ let join14 = ",";
72730
72730
  const originalIndentation = indentation;
72731
72731
  if (Array.isArray(value)) {
72732
72732
  if (value.length === 0) {
@@ -72740,7 +72740,7 @@ var require_safe_stable_stringify = __commonJS((exports, module) => {
72740
72740
  indentation += spacer;
72741
72741
  res += `
72742
72742
  ${indentation}`;
72743
- join13 = `,
72743
+ join14 = `,
72744
72744
  ${indentation}`;
72745
72745
  }
72746
72746
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -72748,13 +72748,13 @@ ${indentation}`;
72748
72748
  for (;i < maximumValuesToStringify - 1; i++) {
72749
72749
  const tmp2 = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
72750
72750
  res += tmp2 !== undefined ? tmp2 : "null";
72751
- res += join13;
72751
+ res += join14;
72752
72752
  }
72753
72753
  const tmp = stringifyFnReplacer(String(i), value, stack, replacer, spacer, indentation);
72754
72754
  res += tmp !== undefined ? tmp : "null";
72755
72755
  if (value.length - 1 > maximumBreadth) {
72756
72756
  const removedKeys = value.length - maximumBreadth - 1;
72757
- res += `${join13}"... ${getItemCount(removedKeys)} not stringified"`;
72757
+ res += `${join14}"... ${getItemCount(removedKeys)} not stringified"`;
72758
72758
  }
72759
72759
  if (spacer !== "") {
72760
72760
  res += `
@@ -72775,7 +72775,7 @@ ${originalIndentation}`;
72775
72775
  let separator = "";
72776
72776
  if (spacer !== "") {
72777
72777
  indentation += spacer;
72778
- join13 = `,
72778
+ join14 = `,
72779
72779
  ${indentation}`;
72780
72780
  whitespace = " ";
72781
72781
  }
@@ -72789,13 +72789,13 @@ ${indentation}`;
72789
72789
  const tmp = stringifyFnReplacer(key2, value, stack, replacer, spacer, indentation);
72790
72790
  if (tmp !== undefined) {
72791
72791
  res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
72792
- separator = join13;
72792
+ separator = join14;
72793
72793
  }
72794
72794
  }
72795
72795
  if (keyLength > maximumBreadth) {
72796
72796
  const removedKeys = keyLength - maximumBreadth;
72797
72797
  res += `${separator}"...":${whitespace}"${getItemCount(removedKeys)} not stringified"`;
72798
- separator = join13;
72798
+ separator = join14;
72799
72799
  }
72800
72800
  if (spacer !== "" && separator.length > 1) {
72801
72801
  res = `
@@ -72835,7 +72835,7 @@ ${originalIndentation}`;
72835
72835
  }
72836
72836
  const originalIndentation = indentation;
72837
72837
  let res = "";
72838
- let join13 = ",";
72838
+ let join14 = ",";
72839
72839
  if (Array.isArray(value)) {
72840
72840
  if (value.length === 0) {
72841
72841
  return "[]";
@@ -72848,7 +72848,7 @@ ${originalIndentation}`;
72848
72848
  indentation += spacer;
72849
72849
  res += `
72850
72850
  ${indentation}`;
72851
- join13 = `,
72851
+ join14 = `,
72852
72852
  ${indentation}`;
72853
72853
  }
72854
72854
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
@@ -72856,13 +72856,13 @@ ${indentation}`;
72856
72856
  for (;i < maximumValuesToStringify - 1; i++) {
72857
72857
  const tmp2 = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
72858
72858
  res += tmp2 !== undefined ? tmp2 : "null";
72859
- res += join13;
72859
+ res += join14;
72860
72860
  }
72861
72861
  const tmp = stringifyArrayReplacer(String(i), value[i], stack, replacer, spacer, indentation);
72862
72862
  res += tmp !== undefined ? tmp : "null";
72863
72863
  if (value.length - 1 > maximumBreadth) {
72864
72864
  const removedKeys = value.length - maximumBreadth - 1;
72865
- res += `${join13}"... ${getItemCount(removedKeys)} not stringified"`;
72865
+ res += `${join14}"... ${getItemCount(removedKeys)} not stringified"`;
72866
72866
  }
72867
72867
  if (spacer !== "") {
72868
72868
  res += `
@@ -72875,7 +72875,7 @@ ${originalIndentation}`;
72875
72875
  let whitespace = "";
72876
72876
  if (spacer !== "") {
72877
72877
  indentation += spacer;
72878
- join13 = `,
72878
+ join14 = `,
72879
72879
  ${indentation}`;
72880
72880
  whitespace = " ";
72881
72881
  }
@@ -72884,7 +72884,7 @@ ${indentation}`;
72884
72884
  const tmp = stringifyArrayReplacer(key2, value[key2], stack, replacer, spacer, indentation);
72885
72885
  if (tmp !== undefined) {
72886
72886
  res += `${separator}${strEscape(key2)}:${whitespace}${tmp}`;
72887
- separator = join13;
72887
+ separator = join14;
72888
72888
  }
72889
72889
  }
72890
72890
  if (spacer !== "" && separator.length > 1) {
@@ -72941,20 +72941,20 @@ ${originalIndentation}`;
72941
72941
  indentation += spacer;
72942
72942
  let res2 = `
72943
72943
  ${indentation}`;
72944
- const join14 = `,
72944
+ const join15 = `,
72945
72945
  ${indentation}`;
72946
72946
  const maximumValuesToStringify = Math.min(value.length, maximumBreadth);
72947
72947
  let i = 0;
72948
72948
  for (;i < maximumValuesToStringify - 1; i++) {
72949
72949
  const tmp2 = stringifyIndent(String(i), value[i], stack, spacer, indentation);
72950
72950
  res2 += tmp2 !== undefined ? tmp2 : "null";
72951
- res2 += join14;
72951
+ res2 += join15;
72952
72952
  }
72953
72953
  const tmp = stringifyIndent(String(i), value[i], stack, spacer, indentation);
72954
72954
  res2 += tmp !== undefined ? tmp : "null";
72955
72955
  if (value.length - 1 > maximumBreadth) {
72956
72956
  const removedKeys = value.length - maximumBreadth - 1;
72957
- res2 += `${join14}"... ${getItemCount(removedKeys)} not stringified"`;
72957
+ res2 += `${join15}"... ${getItemCount(removedKeys)} not stringified"`;
72958
72958
  }
72959
72959
  res2 += `
72960
72960
  ${originalIndentation}`;
@@ -72970,16 +72970,16 @@ ${originalIndentation}`;
72970
72970
  return '"[Object]"';
72971
72971
  }
72972
72972
  indentation += spacer;
72973
- const join13 = `,
72973
+ const join14 = `,
72974
72974
  ${indentation}`;
72975
72975
  let res = "";
72976
72976
  let separator = "";
72977
72977
  let maximumPropertiesToStringify = Math.min(keyLength, maximumBreadth);
72978
72978
  if (isTypedArrayWithEntries(value)) {
72979
- res += stringifyTypedArray(value, join13, maximumBreadth);
72979
+ res += stringifyTypedArray(value, join14, maximumBreadth);
72980
72980
  keys = keys.slice(value.length);
72981
72981
  maximumPropertiesToStringify -= value.length;
72982
- separator = join13;
72982
+ separator = join14;
72983
72983
  }
72984
72984
  if (deterministic) {
72985
72985
  keys = sort(keys, comparator);
@@ -72990,13 +72990,13 @@ ${indentation}`;
72990
72990
  const tmp = stringifyIndent(key2, value[key2], stack, spacer, indentation);
72991
72991
  if (tmp !== undefined) {
72992
72992
  res += `${separator}${strEscape(key2)}: ${tmp}`;
72993
- separator = join13;
72993
+ separator = join14;
72994
72994
  }
72995
72995
  }
72996
72996
  if (keyLength > maximumBreadth) {
72997
72997
  const removedKeys = keyLength - maximumBreadth;
72998
72998
  res += `${separator}"...": "${getItemCount(removedKeys)} not stringified"`;
72999
- separator = join13;
72999
+ separator = join14;
73000
73000
  }
73001
73001
  if (separator !== "") {
73002
73002
  res = `
@@ -105309,7 +105309,7 @@ Invalid`)
105309
105309
  });
105310
105310
 
105311
105311
  // src/core/eventBus.ts
105312
- import { EventEmitter } from "events";
105312
+ import { EventEmitter } from "node:events";
105313
105313
  var CHILD_BUS_FORWARD_POLICY = {
105314
105314
  "text-delta": "forward",
105315
105315
  "tool-call-start": "forward",
@@ -106392,8 +106392,8 @@ function assertCommandInScope(command, ctx) {
106392
106392
  // src/core/agents/offSecAgent/tools/authenticateSession.ts
106393
106393
  init_dist();
106394
106394
  init_zod();
106395
- import { writeFileSync } from "fs";
106396
- import { join as join2 } from "path";
106395
+ import { writeFileSync } from "node:fs";
106396
+ import { join as join2 } from "node:path";
106397
106397
 
106398
106398
  // src/core/http/targetHeaders.ts
106399
106399
  function getRegistrableDomain2(hostname) {
@@ -106834,6 +106834,11 @@ or provide username/password directly.`,
106834
106834
  });
106835
106835
  }
106836
106836
 
106837
+ // src/core/agents/offSecAgent/tools/playwrightMcp.ts
106838
+ import { existsSync as existsSync2, mkdirSync, writeFileSync as writeFileSync2 } from "node:fs";
106839
+ import { createRequire as createRequire2 } from "node:module";
106840
+ import { dirname as dirname2, join as join4 } from "node:path";
106841
+
106837
106842
  // node_modules/zod/v4/mini/parse.js
106838
106843
  init_core();
106839
106844
 
@@ -109377,9 +109382,44 @@ function isElectron() {
109377
109382
  // src/core/agents/offSecAgent/tools/playwrightMcp.ts
109378
109383
  init_dist();
109379
109384
  init_zod();
109380
- import { existsSync as existsSync2, mkdirSync, writeFileSync as writeFileSync2 } from "fs";
109381
- import { createRequire } from "module";
109382
- import { dirname, join as join3 } from "path";
109385
+
109386
+ // src/core/agents/offSecAgent/tools/camoufox.ts
109387
+ import { execFile } from "node:child_process";
109388
+ import { createRequire } from "node:module";
109389
+ import { dirname, join as join3 } from "node:path";
109390
+ import { promisify } from "node:util";
109391
+ var execFileAsync = promisify(execFile);
109392
+ var CAMOUFOX_OPTIONS = {
109393
+ humanize: true,
109394
+ block_webrtc: true
109395
+ };
109396
+ async function resolveCamoufoxLaunchOptions(headless) {
109397
+ const { launchOptions: camoufoxLaunchOptions } = await import("camoufox-js");
109398
+ return await camoufoxLaunchOptions({
109399
+ ...CAMOUFOX_OPTIONS,
109400
+ headless
109401
+ });
109402
+ }
109403
+ var ensurePromise = null;
109404
+ function ensureCamoufox(log) {
109405
+ if (!ensurePromise) {
109406
+ ensurePromise = (async () => {
109407
+ log?.("Provisioning Camoufox browser (first run downloads ~150MB; cached after)…");
109408
+ const require_ = createRequire(import.meta.url);
109409
+ const pkgPath = require_.resolve("camoufox-js/package.json");
109410
+ const fetchBin = join3(dirname(pkgPath), "dist", "__main__.js");
109411
+ await execFileAsync("node", [fetchBin, "fetch"], {
109412
+ timeout: 300000
109413
+ });
109414
+ })().catch((err) => {
109415
+ ensurePromise = null;
109416
+ throw err;
109417
+ });
109418
+ }
109419
+ return ensurePromise;
109420
+ }
109421
+
109422
+ // src/core/agents/offSecAgent/tools/playwrightMcp.ts
109383
109423
  var BrowserNavigateInput = exports_external.object({
109384
109424
  url: exports_external.string().describe("Full URL to navigate to"),
109385
109425
  toolCallDescription: exports_external.string().describe("Why you are navigating to this URL")
@@ -109495,6 +109535,7 @@ class PlaywrightMcpSession {
109495
109535
  viewportSize;
109496
109536
  extraHttpHeaders;
109497
109537
  mcpConfigPath = null;
109538
+ cachedCamouOptions = null;
109498
109539
  constructor(options = {}) {
109499
109540
  const { headless, userAgent, viewportSize, extraHttpHeaders } = options;
109500
109541
  this.headless = headless ?? defaultHeadless;
@@ -109504,14 +109545,26 @@ class PlaywrightMcpSession {
109504
109545
  this.extraHttpHeaders = headerSource && Object.keys(headerSource).length > 0 ? { ...headerSource } : undefined;
109505
109546
  }
109506
109547
  resetState() {
109548
+ this.cleanupConfigFile();
109507
109549
  this.mcpClient = null;
109508
109550
  this.mcpTransport = null;
109509
109551
  this.mcpProcess = null;
109510
109552
  this.connectionPromise = null;
109511
109553
  this.disconnecting = false;
109512
109554
  }
109513
- forceKillProcess() {
109514
- const proc = this.mcpProcess;
109555
+ cleanupConfigFile() {
109556
+ const configPath = this.mcpConfigPath;
109557
+ if (!configPath)
109558
+ return;
109559
+ this.mcpConfigPath = null;
109560
+ (async () => {
109561
+ try {
109562
+ const fsp = await import("fs/promises");
109563
+ await fsp.unlink(configPath);
109564
+ } catch {}
109565
+ })();
109566
+ }
109567
+ forceKillProcess(proc = this.mcpProcess) {
109515
109568
  if (!proc || proc.exitCode !== null)
109516
109569
  return;
109517
109570
  try {
@@ -109539,41 +109592,40 @@ class PlaywrightMcpSession {
109539
109592
  }
109540
109593
  this.connectionPromise = (async () => {
109541
109594
  try {
109542
- const require_ = createRequire(import.meta.url);
109595
+ const require_ = createRequire2(import.meta.url);
109543
109596
  const mcpPkgJsonPath = require_.resolve("@playwright/mcp/package.json");
109544
- const cliPath = join3(dirname(mcpPkgJsonPath), "cli.js");
109597
+ const cliPath = join4(dirname2(mcpPkgJsonPath), "cli.js");
109545
109598
  const args = [cliPath, "--isolated"];
109546
- if (this.headless) {
109547
- args.push("--headless");
109548
- }
109549
- if (this.userAgent) {
109550
- args.push("--user-agent", this.userAgent);
109551
- }
109552
- if (this.viewportSize) {
109553
- args.push(`--viewport-size=${this.viewportSize}`);
109554
- }
109555
- if (this.extraHttpHeaders) {
109556
- const os = await import("os");
109557
- const fsp = await import("fs/promises");
109558
- const cfg = {
109559
- browser: {
109560
- contextOptions: { extraHTTPHeaders: this.extraHttpHeaders }
109561
- }
109562
- };
109563
- this.mcpConfigPath = join3(os.tmpdir(), `pensar-mcp-${process.pid}-${Date.now()}.json`);
109564
- await fsp.writeFile(this.mcpConfigPath, JSON.stringify(cfg), {
109565
- encoding: "utf-8",
109566
- mode: 384
109567
- });
109568
- args.push("--config", this.mcpConfigPath);
109569
- }
109570
- if (process.getuid?.() === 0) {
109571
- args.push("--no-sandbox");
109572
- }
109599
+ await ensureCamoufox();
109600
+ if (!this.cachedCamouOptions) {
109601
+ this.cachedCamouOptions = await resolveCamoufoxLaunchOptions(this.headless);
109602
+ }
109603
+ const camou = this.cachedCamouOptions;
109604
+ const os = await import("node:os");
109605
+ const fsp = await import("node:fs/promises");
109606
+ const cfg = {
109607
+ browser: {
109608
+ browserName: "firefox",
109609
+ launchOptions: {
109610
+ executablePath: camou.executablePath,
109611
+ args: camou.args,
109612
+ firefoxUserPrefs: camou.firefoxUserPrefs,
109613
+ headless: camou.headless
109614
+ },
109615
+ ...this.extraHttpHeaders ? { contextOptions: { extraHTTPHeaders: this.extraHttpHeaders } } : {}
109616
+ }
109617
+ };
109618
+ this.mcpConfigPath = join4(os.tmpdir(), `pensar-mcp-${process.pid}-${Date.now()}.json`);
109619
+ await fsp.writeFile(this.mcpConfigPath, JSON.stringify(cfg), {
109620
+ encoding: "utf-8",
109621
+ mode: 384
109622
+ });
109623
+ args.push("--config", this.mcpConfigPath);
109573
109624
  const transport = new StdioClientTransport({
109574
109625
  command: "node",
109575
109626
  args,
109576
- stderr: "pipe"
109627
+ stderr: "pipe",
109628
+ env: Object.fromEntries(Object.entries(camou.env).map(([k, v]) => [k, String(v)]))
109577
109629
  });
109578
109630
  const client = new Client({
109579
109631
  name: "apex-browser-agent",
@@ -109607,29 +109659,28 @@ class PlaywrightMcpSession {
109607
109659
  this.disconnecting = true;
109608
109660
  const transport = this.mcpTransport;
109609
109661
  const client = this.mcpClient;
109662
+ const proc = this.mcpProcess;
109610
109663
  this.resetState();
109611
109664
  this.disconnecting = true;
109612
- if (client) {
109613
- try {
109614
- await client.close();
109615
- } catch {}
109616
- }
109617
- if (transport) {
109618
- try {
109619
- await transport.close();
109620
- } catch {}
109621
- }
109622
- this.forceKillProcess();
109623
- if (this.mcpConfigPath) {
109624
- const configPath = this.mcpConfigPath;
109625
- this.mcpConfigPath = null;
109665
+ this.forceKillProcess(proc);
109666
+ const CLOSE_TIMEOUT_MS = 5000;
109667
+ let closeTimer;
109668
+ await Promise.race([
109626
109669
  (async () => {
109627
109670
  try {
109628
- const fsp = await import("fs/promises");
109629
- await fsp.unlink(configPath);
109671
+ await client?.close();
109630
109672
  } catch {}
109631
- })();
109632
- }
109673
+ try {
109674
+ await transport?.close();
109675
+ } catch {}
109676
+ })(),
109677
+ new Promise((resolve) => {
109678
+ closeTimer = setTimeout(resolve, CLOSE_TIMEOUT_MS);
109679
+ })
109680
+ ]);
109681
+ if (closeTimer)
109682
+ clearTimeout(closeTimer);
109683
+ this.cleanupConfigFile();
109633
109684
  this.disconnecting = false;
109634
109685
  }
109635
109686
  isConnected() {
@@ -109953,8 +110004,8 @@ Target base URL: ${targetUrl}`,
109953
110004
  if (base64Data) {
109954
110005
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
109955
110006
  const screenshotFilename = `${filename}_${timestamp}.png`;
109956
- const screenshotPath = join3(evidenceDir, screenshotFilename);
109957
- const dir = dirname(screenshotPath);
110007
+ const screenshotPath = join4(evidenceDir, screenshotFilename);
110008
+ const dir = dirname2(screenshotPath);
109958
110009
  if (!existsSync2(dir)) {
109959
110010
  mkdirSync(dir, { recursive: true });
109960
110011
  }
@@ -110167,18 +110218,20 @@ The returned cookies can be formatted as a Cookie header for use with http_reque
110167
110218
  // src/core/agents/offSecAgent/tools/sandboxPlaywright.ts
110168
110219
  init_dist();
110169
110220
  init_zod();
110170
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "fs";
110171
- import { dirname as dirname2, join as join4 } from "path";
110221
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, writeFileSync as writeFileSync3 } from "node:fs";
110222
+ import { dirname as dirname3, join as join5 } from "node:path";
110172
110223
  var SANDBOX_PW_DIR = "/opt/sandbox-playwright";
110173
110224
  var SANDBOX_EVIDENCE_DIR = "/tmp/evidence";
110174
110225
  var SANDBOX_REFS_FILE = "/tmp/pw-refs.json";
110175
110226
  var SANDBOX_URL_FILE = "/tmp/pw-current-url";
110176
110227
  var SANDBOX_CONSOLE_FILE = "/tmp/pw-console-log.json";
110228
+ var SANDBOX_CAMOU_CACHE = "/tmp/pw-camou-opts.json";
110177
110229
  var RESULT_START = "__PW_RESULT__";
110178
110230
  var RESULT_END = "__PW_END__";
110179
110231
  var installationCache = new WeakMap;
110232
+ var browserSetupCache = new WeakMap;
110180
110233
  async function checkSandboxPlaywright(sandbox) {
110181
- const script = `try{require("playwright");console.log("OK")}catch(e){process.exit(1)}`;
110234
+ const script = `(async()=>{try{const{launchPath}=await import("camoufox-js/dist/pkgman.js");require("playwright-core");if(!require("fs").existsSync(launchPath()))process.exit(1);console.log("OK")}catch(e){process.exit(1)}})()`;
110182
110235
  const b64 = Buffer.from(script).toString("base64");
110183
110236
  await sandbox.execute(`mkdir -p ${SANDBOX_PW_DIR} && echo "${b64}" | base64 -d > ${SANDBOX_PW_DIR}/pw_check.js`, { timeout: 10 });
110184
110237
  const result = await sandbox.execute(`node ${SANDBOX_PW_DIR}/pw_check.js`, {
@@ -110189,35 +110242,33 @@ async function checkSandboxPlaywright(sandbox) {
110189
110242
  async function installSandboxPlaywright(sandbox) {
110190
110243
  await sandbox.execute(`mkdir -p ${SANDBOX_PW_DIR}`, { timeout: 10 });
110191
110244
  const isAlpine = (await sandbox.execute("which apk", { timeout: 5 })).success;
110245
+ if (isAlpine) {
110246
+ throw new Error("Camoufox requires a glibc-based sandbox image (Debian/Ubuntu); Alpine/musl is unsupported.");
110247
+ }
110192
110248
  const initResult = await sandbox.execute(`cd ${SANDBOX_PW_DIR} && npm init -y --silent 2>/dev/null`, { timeout: 30 });
110193
110249
  if (!initResult.success) {
110194
110250
  throw new Error(`Failed to init npm project in sandbox: ${initResult.stderr || initResult.stdout}`);
110195
110251
  }
110196
- const npmInstallCmd = isAlpine ? `cd ${SANDBOX_PW_DIR} && PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm install playwright 2>&1` : `cd ${SANDBOX_PW_DIR} && npm install playwright 2>&1`;
110197
- const installResult = await sandbox.execute(npmInstallCmd, { timeout: 300 });
110252
+ const installResult = await sandbox.execute(`cd ${SANDBOX_PW_DIR} && npm install camoufox-js@0.11.1 playwright-core@1.53.1 2>&1`, { timeout: 300 });
110198
110253
  if (!installResult.success) {
110199
- throw new Error(`Failed to install Playwright in sandbox: ${installResult.stderr || installResult.stdout}`);
110254
+ throw new Error(`Failed to install camoufox-js in sandbox: ${installResult.stderr || installResult.stdout}`);
110200
110255
  }
110201
- if (isAlpine) {
110202
- const apkResult = await sandbox.execute("apk add --no-cache chromium nss freetype harfbuzz ca-certificates ttf-freefont 2>&1", { timeout: 120 });
110203
- if (!apkResult.success) {
110204
- throw new Error(`Failed to install Chromium via apk: ${apkResult.stderr || apkResult.stdout}`);
110205
- }
110206
- } else {
110207
- await sandbox.execute(`(sudo rm -f /etc/apt/sources.list.d/yarn.list /etc/apt/sources.list.d/yarn.sources 2>/dev/null || rm -f /etc/apt/sources.list.d/yarn.list /etc/apt/sources.list.d/yarn.sources 2>/dev/null || true)`, { timeout: 10 });
110208
- let browserResult;
110209
- for (let attempt = 1;attempt <= 3; attempt++) {
110210
- browserResult = await sandbox.execute(`cd ${SANDBOX_PW_DIR} && npx playwright install chromium --with-deps 2>&1`, { timeout: 300 });
110211
- if (browserResult.success)
110212
- break;
110213
- if (attempt < 3) {
110214
- await new Promise((r) => setTimeout(r, 3000));
110215
- }
110216
- }
110217
- if (!browserResult.success) {
110218
- throw new Error(`Failed to install Chromium in sandbox: ${browserResult.stderr || browserResult.stdout}`);
110256
+ const depsResult = await sandbox.execute(`rm -f /etc/apt/sources.list.d/yarn.list /etc/apt/sources.list.d/yarn.sources 2>/dev/null; cd ${SANDBOX_PW_DIR} && npx playwright@1.53.1 install-deps firefox 2>&1`, { timeout: 300 });
110257
+ if (!depsResult.success) {
110258
+ throw new Error(`Failed to install Firefox system deps in sandbox: ${depsResult.stderr || depsResult.stdout}`);
110259
+ }
110260
+ let fetchResult;
110261
+ for (let attempt = 1;attempt <= 3; attempt++) {
110262
+ fetchResult = await sandbox.execute(`cd ${SANDBOX_PW_DIR} && node ./node_modules/camoufox-js/dist/__main__.js fetch 2>&1`, { timeout: 300 });
110263
+ if (fetchResult.success)
110264
+ break;
110265
+ if (attempt < 3) {
110266
+ await new Promise((r) => setTimeout(r, 3000));
110219
110267
  }
110220
110268
  }
110269
+ if (!fetchResult.success) {
110270
+ throw new Error(`Failed to fetch Camoufox in sandbox: ${fetchResult.stderr || fetchResult.stdout}`);
110271
+ }
110221
110272
  }
110222
110273
  async function ensureSandboxPlaywright(sandbox) {
110223
110274
  let cached = installationCache.get(sandbox);
@@ -110238,42 +110289,59 @@ async function ensureSandboxPlaywright(sandbox) {
110238
110289
  }
110239
110290
  }
110240
110291
  async function ensureSandboxBrowser(sandbox) {
110241
- await sandbox.execute(`mkdir -p ${SANDBOX_EVIDENCE_DIR} /tmp/pw-user-data`, {
110242
- timeout: 5
110243
- });
110292
+ await sandbox.execute(`rm -rf /tmp/pw-user-data ${SANDBOX_CAMOU_CACHE}; mkdir -p ${SANDBOX_EVIDENCE_DIR} /tmp/pw-user-data`, { timeout: 5 });
110244
110293
  }
110245
110294
  async function ensureSandboxReady(sandbox) {
110246
110295
  await ensureSandboxPlaywright(sandbox);
110247
- await ensureSandboxBrowser(sandbox);
110296
+ let cached = browserSetupCache.get(sandbox);
110297
+ if (!cached) {
110298
+ cached = ensureSandboxBrowser(sandbox);
110299
+ browserSetupCache.set(sandbox, cached);
110300
+ try {
110301
+ await cached;
110302
+ } catch (error) {
110303
+ browserSetupCache.delete(sandbox);
110304
+ throw error;
110305
+ }
110306
+ } else {
110307
+ await cached;
110308
+ }
110248
110309
  }
110249
110310
  async function runPlaywrightScript(sandbox, body, timeout = 60, extraHttpHeaders) {
110250
110311
  const headersJson = extraHttpHeaders && Object.keys(extraHttpHeaders).length > 0 ? JSON.stringify(extraHttpHeaders) : "null";
110251
110312
  const script = `
110252
- const { chromium } = require('playwright');
110313
+ const { firefox } = require('playwright-core');
110253
110314
  const fs = require('fs');
110254
110315
 
110255
110316
  (async () => {
110317
+ const { launchOptions } = await import('camoufox-js');
110256
110318
  function resolve(value) {
110257
110319
  process.stdout.write('${RESULT_START}' + JSON.stringify(value) + '${RESULT_END}');
110258
110320
  }
110259
110321
 
110260
- // Prefer system Chromium (Alpine apk install) over Playwright's bundled binary.
110261
- let executablePath;
110262
- for (const p of ['/usr/bin/chromium-browser', '/usr/bin/chromium']) {
110263
- try { fs.accessSync(p, fs.constants.X_OK); executablePath = p; break; } catch {}
110264
- }
110265
-
110266
110322
  // Resolved per script invocation so /headers mutations take effect
110267
110323
  // on the next browser tool call.
110268
110324
  const __extraHeaders = ${headersJson};
110269
110325
 
110326
+ // Use the sandbox's virtual display if one is present — Camoufox is far less
110327
+ // detectable headful. Falls back to plain headless, which is still fully
110328
+ // fingerprint-spoofed (just a weaker stealth posture, never vanilla Chromium).
110329
+ const __headless = process.env.DISPLAY ? false : true;
110330
+ // Resolve Camoufox options once per sandbox session and cache to disk so
110331
+ // every tool call presents the same fingerprint on the shared profile dir.
110332
+ let __camou;
110333
+ try {
110334
+ __camou = JSON.parse(fs.readFileSync('${SANDBOX_CAMOU_CACHE}', 'utf-8'));
110335
+ } catch {
110336
+ __camou = await launchOptions({ ...${JSON.stringify(CAMOUFOX_OPTIONS)}, headless: __headless });
110337
+ fs.writeFileSync('${SANDBOX_CAMOU_CACHE}', JSON.stringify(__camou));
110338
+ }
110339
+
110270
110340
  let context;
110271
110341
  const __consoleMessages = [];
110272
110342
  try {
110273
- context = await chromium.launchPersistentContext('/tmp/pw-user-data', {
110274
- headless: true,
110275
- ...(executablePath ? { executablePath } : {}),
110276
- args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage', '--disable-gpu'],
110343
+ context = await firefox.launchPersistentContext('/tmp/pw-user-data', {
110344
+ ...__camou,
110277
110345
  ...(__extraHeaders ? { extraHTTPHeaders: __extraHeaders } : {}),
110278
110346
  });
110279
110347
  const pages = context.pages();
@@ -110363,7 +110431,7 @@ var BrowserGetCookiesInput2 = exports_external.object({
110363
110431
  });
110364
110432
  function createSandboxBrowserTools(ctx) {
110365
110433
  const sandbox = ctx.sandbox;
110366
- const evidenceDir = join4(ctx.session.rootPath, "evidence");
110434
+ const evidenceDir = join5(ctx.session.rootPath, "evidence");
110367
110435
  const targetUrl = ctx.target ?? "";
110368
110436
  if (!existsSync3(evidenceDir)) {
110369
110437
  mkdirSync2(evidenceDir, { recursive: true });
@@ -110375,9 +110443,13 @@ function createSandboxBrowserTools(ctx) {
110375
110443
  }
110376
110444
  return setupPromise;
110377
110445
  }
110446
+ let scriptQueue = Promise.resolve();
110378
110447
  function runScript(body, timeout = 60) {
110379
110448
  const resolved = targetUrl ? resolveEffectiveHeaders(resolverSessionFromCtx(ctx), targetUrl) : ctx.session.config?.headers;
110380
- return runPlaywrightScript(sandbox, body, timeout, stripBrowserManagedHeaders(resolved));
110449
+ const headers = stripBrowserManagedHeaders(resolved);
110450
+ const next = scriptQueue.then(() => runPlaywrightScript(sandbox, body, timeout, headers));
110451
+ scriptQueue = next.then(() => {}, () => {});
110452
+ return next;
110381
110453
  }
110382
110454
  const browser_navigate = tool({
110383
110455
  description: `Navigate the browser to a URL to load and render a page.
@@ -110428,8 +110500,8 @@ Use this to document:
110428
110500
  resolve({ success: true, data: b64, sandboxPath: ${JSON.stringify(sandboxPath)} });
110429
110501
  `, 30);
110430
110502
  if (result.success && result.data) {
110431
- const localPath = join4(evidenceDir, screenshotFilename);
110432
- const dir = dirname2(localPath);
110503
+ const localPath = join5(evidenceDir, screenshotFilename);
110504
+ const dir = dirname3(localPath);
110433
110505
  if (!existsSync3(dir)) {
110434
110506
  mkdirSync2(dir, { recursive: true });
110435
110507
  }
@@ -110806,7 +110878,7 @@ The returned cookies can be formatted as a Cookie header for use with http_reque
110806
110878
  // src/core/agents/offSecAgent/tools/browserTools.ts
110807
110879
  init_dist();
110808
110880
  init_zod();
110809
- import { join as join5 } from "path";
110881
+ import { join as join6 } from "node:path";
110810
110882
  var BROWSER_TOOL_NAMES = [
110811
110883
  "browser_navigate",
110812
110884
  "browser_snapshot",
@@ -110818,7 +110890,7 @@ var BROWSER_TOOL_NAMES = [
110818
110890
  "browser_get_cookies"
110819
110891
  ];
110820
110892
  function createBrowserToolset(ctx) {
110821
- const tools = ctx.sandbox ? createSandboxBrowserTools(ctx) : createBrowserTools(ctx.target ?? "", join5(ctx.session.rootPath, "evidence"), "operator", undefined, ctx.abortSignal, undefined, undefined, undefined, ctx.browserSession);
110893
+ const tools = ctx.sandbox ? createSandboxBrowserTools(ctx) : createBrowserTools(ctx.target ?? "", join6(ctx.session.rootPath, "evidence"), "operator", undefined, ctx.abortSignal, undefined, undefined, undefined, ctx.browserSession);
110822
110894
  if (!ctx.credentialManager) {
110823
110895
  return tools;
110824
110896
  }
@@ -110878,7 +110950,7 @@ Credential mode: Instead of passing a raw secret as "value", you can pass ` + `"
110878
110950
  error: "Either value or credentialId + credentialField must be provided"
110879
110951
  };
110880
110952
  }
110881
- return originalFill.execute({ element, ref, value, toolCallDescription }, { toolCallId: "", messages: [], abortSignal: undefined });
110953
+ return originalFill.execute?.({ element, ref, value, toolCallDescription }, { toolCallId: "", messages: [], abortSignal: undefined });
110882
110954
  }
110883
110955
  });
110884
110956
  return {
@@ -110943,8 +111015,8 @@ init_dist();
110943
111015
  init_zod();
110944
111016
  init_structured();
110945
111017
  init_lazyLogger();
110946
- import { existsSync as existsSync4, mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
110947
- import { join as join6 } from "path";
111018
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "node:fs";
111019
+ import { join as join7 } from "node:path";
110948
111020
  var log = scopedLogger(() => createLogger("complete_authentication"));
110949
111021
  var AUTH_DIR = "auth";
110950
111022
  var AUTH_DATA_FILENAME = "auth-data.json";
@@ -110988,11 +111060,11 @@ This tool marks the end of the authentication flow.`,
110988
111060
  log.info(`Authentication complete: ${result.success ? "SUCCESS" : "FAILED"}`);
110989
111061
  let authDataPath;
110990
111062
  try {
110991
- const authDir = join6(ctx.session.rootPath, AUTH_DIR);
111063
+ const authDir = join7(ctx.session.rootPath, AUTH_DIR);
110992
111064
  if (!existsSync4(authDir)) {
110993
111065
  mkdirSync3(authDir, { recursive: true });
110994
111066
  }
110995
- authDataPath = join6(authDir, AUTH_DATA_FILENAME);
111067
+ authDataPath = join7(authDir, AUTH_DATA_FILENAME);
110996
111068
  const authData = {
110997
111069
  authenticated: result.success,
110998
111070
  strategy: result.strategy || "unknown",
@@ -111061,10 +111133,10 @@ async function extractJavascriptEndpoints(params) {
111061
111133
  const patternCopy = new RegExp(pattern.source, pattern.flags);
111062
111134
  for (let match = patternCopy.exec(scriptContent);match !== null; match = patternCopy.exec(scriptContent)) {
111063
111135
  const endpoint = match[1] || match[2];
111064
- if (endpoint && endpoint.startsWith("/")) {
111136
+ if (endpoint?.startsWith("/")) {
111065
111137
  endpoints.push({
111066
111138
  endpoint,
111067
- pattern: pattern.source.substring(0, 30) + "...",
111139
+ pattern: `${pattern.source.substring(0, 30)}...`,
111068
111140
  source: "inline-script"
111069
111141
  });
111070
111142
  }
@@ -111208,8 +111280,8 @@ function crawlAuthenticated(ctx) {
111208
111280
  // src/core/agents/offSecAgent/tools/createAttackSurfaceReport.ts
111209
111281
  init_dist();
111210
111282
  init_zod();
111211
- import { writeFileSync as writeFileSync5 } from "fs";
111212
- import { join as join7 } from "path";
111283
+ import { writeFileSync as writeFileSync5 } from "node:fs";
111284
+ import { join as join8 } from "node:path";
111213
111285
  function createAttackSurfaceReport(ctx) {
111214
111286
  return tool({
111215
111287
  description: `Provide attack surface analysis results to the orchestrator agent.
@@ -111235,7 +111307,7 @@ Call this at the END of your analysis with:
111235
111307
  toolCallDescription: exports_external.string().describe("A concise, human-readable description of what this tool call is doing")
111236
111308
  }),
111237
111309
  execute: async (results) => {
111238
- const resultsPath = join7(ctx.session.rootPath, "attack-surface-results.json");
111310
+ const resultsPath = join8(ctx.session.rootPath, "attack-surface-results.json");
111239
111311
  writeFileSync5(resultsPath, JSON.stringify(results, null, 2));
111240
111312
  return {
111241
111313
  success: true,
@@ -111252,9 +111324,9 @@ init_dist();
111252
111324
  init_zod();
111253
111325
  init_structured();
111254
111326
  init_lazyLogger();
111255
- import { existsSync as existsSync5 } from "fs";
111256
- import { mkdir, writeFile } from "fs/promises";
111257
- import { dirname as dirname3, isAbsolute, resolve } from "path";
111327
+ import { existsSync as existsSync5 } from "node:fs";
111328
+ import { mkdir, writeFile } from "node:fs/promises";
111329
+ import { dirname as dirname4, isAbsolute, resolve } from "node:path";
111258
111330
  var log3 = scopedLogger(() => createLogger("create_file"));
111259
111331
  var createFileInputSchema = exports_external.object({
111260
111332
  path: exports_external.string().describe("Absolute or relative path for the new file"),
@@ -111298,7 +111370,7 @@ async function executeLocalCreate(filePath, content, overwrite) {
111298
111370
  path: filePath
111299
111371
  };
111300
111372
  }
111301
- const dir = dirname3(filePath);
111373
+ const dir = dirname4(filePath);
111302
111374
  log3.debug(`local: mkdir ${dir}`);
111303
111375
  await mkdir(dir, { recursive: true });
111304
111376
  log3.debug(`local: mkdir done, writing ${content.length} bytes`);
@@ -111332,7 +111404,7 @@ async function executeSandboxCreate(ctx, filePath, content, overwrite) {
111332
111404
  };
111333
111405
  }
111334
111406
  }
111335
- const dirPath = dirname3(filePath);
111407
+ const dirPath = dirname4(filePath);
111336
111408
  await ctx.sandbox.execute(`mkdir -p "${dirPath}"`);
111337
111409
  const base64Content = Buffer.from(content).toString("base64");
111338
111410
  const writeResult = await ctx.sandbox.execute(`echo "${base64Content}" | base64 -d > "${filePath}"`);
@@ -111362,17 +111434,17 @@ init_dist();
111362
111434
  init_zod();
111363
111435
 
111364
111436
  // src/core/tasks/index.ts
111365
- import { mkdirSync as mkdirSync4, readdirSync as readdirSync2, readFileSync, writeFileSync as writeFileSync6 } from "fs";
111366
- import { join as join8 } from "path";
111437
+ import { mkdirSync as mkdirSync4, readdirSync as readdirSync2, readFileSync, writeFileSync as writeFileSync6 } from "node:fs";
111438
+ import { join as join9 } from "node:path";
111367
111439
  var HWM_FILENAME = "_hwm.json";
111368
111440
  function ensureDir(dir) {
111369
111441
  mkdirSync4(dir, { recursive: true });
111370
111442
  }
111371
111443
  function taskPath(tasksDir, id) {
111372
- return join8(tasksDir, `${id}.json`);
111444
+ return join9(tasksDir, `${id}.json`);
111373
111445
  }
111374
111446
  function hwmPath(tasksDir) {
111375
- return join8(tasksDir, HWM_FILENAME);
111447
+ return join9(tasksDir, HWM_FILENAME);
111376
111448
  }
111377
111449
  function readHighWaterMark(tasksDir) {
111378
111450
  try {
@@ -111445,7 +111517,7 @@ function listTasks(tasksDir, filter) {
111445
111517
  if (!file.endsWith(".json") || file === HWM_FILENAME)
111446
111518
  continue;
111447
111519
  try {
111448
- const raw = readFileSync(join8(tasksDir, file), "utf-8");
111520
+ const raw = readFileSync(join9(tasksDir, file), "utf-8");
111449
111521
  const task = JSON.parse(raw);
111450
111522
  if (filter?.status && task.status !== filter.status)
111451
111523
  continue;
@@ -111542,8 +111614,8 @@ Examples of good tasks:
111542
111614
  init_dist();
111543
111615
  init_zod();
111544
111616
  init_credentials();
111545
- import { writeFileSync as writeFileSync7 } from "fs";
111546
- import { join as join9 } from "path";
111617
+ import { writeFileSync as writeFileSync7 } from "node:fs";
111618
+ import { join as join10 } from "node:path";
111547
111619
  init_structured();
111548
111620
  init_lazyLogger();
111549
111621
  var log4 = scopedLogger(() => createLogger("delegate_auth"));
@@ -111709,7 +111781,7 @@ When to use delegate_to_auth_subagent vs authenticate_session:
111709
111781
  if (credentials) {
111710
111782
  ctx.session.credentialManager.addFromAuthCredentials(credentials);
111711
111783
  }
111712
- const { runAuthenticationAgent } = await import("./authentication-c0aj9zaz.js");
111784
+ const { runAuthenticationAgent } = await import("./authentication-69q16waz.js");
111713
111785
  const localBus = new AgentEventBus;
111714
111786
  AgentEventBus.attachChild(localBus, ctx.eventBus, subagentId);
111715
111787
  const result = await runAuthenticationAgent({
@@ -111728,7 +111800,7 @@ When to use delegate_to_auth_subagent vs authenticate_session:
111728
111800
  parentSubagentId: ctx.subagentId
111729
111801
  });
111730
111802
  if (result.success) {
111731
- const sessionInfoPath = join9(ctx.session.rootPath, "session-info.json");
111803
+ const sessionInfoPath = join10(ctx.session.rootPath, "session-info.json");
111732
111804
  const sessionInfo = {
111733
111805
  authenticated: true,
111734
111806
  username: username || "via_subagent",
@@ -111922,8 +111994,8 @@ function detectBarrier(bodyLower, statusCode) {
111922
111994
  // src/core/agents/offSecAgent/tools/documentApp.ts
111923
111995
  init_dist();
111924
111996
  init_zod();
111925
- import { existsSync as existsSync6, mkdirSync as mkdirSync5, writeFileSync as writeFileSync8 } from "fs";
111926
- import { join as join10 } from "path";
111997
+ import { existsSync as existsSync6, mkdirSync as mkdirSync5, writeFileSync as writeFileSync8 } from "node:fs";
111998
+ import { join as join11 } from "node:path";
111927
111999
  function sanitizeName(name) {
111928
112000
  return name.toLowerCase().replace(/[^a-z0-9-_.]/g, "_");
111929
112001
  }
@@ -111962,7 +112034,7 @@ function validateDomainUrl(value) {
111962
112034
  }
111963
112035
  }
111964
112036
  function documentApp(ctx) {
111965
- const baseAppsPath = join10(ctx.session.rootPath, "apps");
112037
+ const baseAppsPath = join11(ctx.session.rootPath, "apps");
111966
112038
  return tool({
111967
112039
  description: `Document a discovered application during attack surface analysis.
111968
112040
 
@@ -112015,7 +112087,7 @@ Each application creates a JSON file in the apps directory for tracking and anal
112015
112087
  const sanitizedName = sanitizeName(input.appName);
112016
112088
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
112017
112089
  const filename = `app_${sanitizedName}_${timestamp}.json`;
112018
- const filepath = join10(baseAppsPath, filename);
112090
+ const filepath = join11(baseAppsPath, filename);
112019
112091
  const appRecord = {
112020
112092
  ...input,
112021
112093
  discoveredAt: new Date().toISOString(),
@@ -112038,8 +112110,8 @@ Each application creates a JSON file in the apps directory for tracking and anal
112038
112110
  // src/core/agents/offSecAgent/tools/documentEndpoint.ts
112039
112111
  init_dist();
112040
112112
  init_zod();
112041
- import { existsSync as existsSync7, mkdirSync as mkdirSync6, writeFileSync as writeFileSync9 } from "fs";
112042
- import { join as join11 } from "path";
112113
+ import { existsSync as existsSync7, mkdirSync as mkdirSync6, writeFileSync as writeFileSync9 } from "node:fs";
112114
+ import { join as join12 } from "node:path";
112043
112115
 
112044
112116
  // src/core/agents/specialized/attackSurface/blackboxRiskScoring.ts
112045
112117
  var RISK_LEVEL_BASE_SCORE = {
@@ -112091,7 +112163,7 @@ function computeExposure(riskLevel, details) {
112091
112163
  }
112092
112164
  return Math.min(3, Math.max(0, base));
112093
112165
  }
112094
- function computeDataSensitivity(riskLevel, assetType, details) {
112166
+ function computeDataSensitivity(riskLevel, _assetType, details) {
112095
112167
  if (riskLevel === "CRITICAL")
112096
112168
  return 3;
112097
112169
  let score = riskLevel === "HIGH" ? 2 : riskLevel === "MEDIUM" ? 1 : 0;
@@ -112389,7 +112461,7 @@ async function generateThreatModelForEndpoint(ctx, input) {
112389
112461
  return threatModelLimiter(async () => {
112390
112462
  if (ctx.abortSignal?.aborted)
112391
112463
  return null;
112392
- const { CodeAgent } = await import("./agent-4g69jwmq.js");
112464
+ const { CodeAgent } = await import("./agent-m3bsrs09.js");
112393
112465
  const subagentId = `threat-model-${sanitize(input.appName)}-${sanitize(input.routePath)}`;
112394
112466
  ctx.eventBus?.emit("subagent-spawn", {
112395
112467
  subagentId,
@@ -112697,7 +112769,7 @@ var documentEndpointInputSchema = exports_external.object({
112697
112769
  toolCallDescription: exports_external.string().describe("A concise, human-readable description of what this tool call is doing")
112698
112770
  });
112699
112771
  function documentEndpoint(ctx) {
112700
- const baseAssetsPath = join11(ctx.session.rootPath, "assets");
112772
+ const baseAssetsPath = join12(ctx.session.rootPath, "assets");
112701
112773
  return tool({
112702
112774
  description: `Document a discovered endpoint during attack surface analysis.
112703
112775
 
@@ -112743,14 +112815,14 @@ Each endpoint creates a JSON file in the assets directory for tracking and analy
112743
112815
  message: `routePath "${input.routePath}" is a full URL. The domain is already stored on the parent application. ` + `Use a path or access pattern instead (e.g. "/api/users", "/{objectKey}?X-Amz-Signature={sig}", "arn:aws:s3:::bucket-name").`
112744
112816
  };
112745
112817
  }
112746
- const targetDir = join11(baseAssetsPath, sanitizeName2(input.appName));
112818
+ const targetDir = join12(baseAssetsPath, sanitizeName2(input.appName));
112747
112819
  if (!existsSync7(targetDir)) {
112748
112820
  mkdirSync6(targetDir, { recursive: true });
112749
112821
  }
112750
112822
  const sanitizedPath = sanitizeName2(input.routePath);
112751
112823
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
112752
112824
  const filename = `asset_${sanitizedPath}_${timestamp}.json`;
112753
- const filepath = join11(targetDir, filename);
112825
+ const filepath = join12(targetDir, filename);
112754
112826
  const heuristicRiskScore = computeBlackboxRiskScore(input.riskLevel, "endpoint", {
112755
112827
  url: input.routePath,
112756
112828
  method: input.method,
@@ -112819,7 +112891,7 @@ Each endpoint creates a JSON file in the assets directory for tracking and analy
112819
112891
  // src/core/agents/offSecAgent/tools/documentFinding.ts
112820
112892
  init_dist();
112821
112893
  init_zod();
112822
- import { spawn as spawn2 } from "child_process";
112894
+ import { spawn as spawn2 } from "node:child_process";
112823
112895
  import {
112824
112896
  appendFileSync,
112825
112897
  chmodSync,
@@ -112827,8 +112899,8 @@ import {
112827
112899
  mkdirSync as mkdirSync7,
112828
112900
  unlinkSync,
112829
112901
  writeFileSync as writeFileSync10
112830
- } from "fs";
112831
- import { join as join12 } from "path";
112902
+ } from "node:fs";
112903
+ import { join as join13 } from "node:path";
112832
112904
 
112833
112905
  // src/lib/cwe/types.ts
112834
112906
  init_zod();
@@ -113327,7 +113399,7 @@ function getMetricDistance(metrics, metric) {
113327
113399
  if (!levels)
113328
113400
  return 0;
113329
113401
  let value;
113330
- const modifiedMetric = "M" + metric;
113402
+ const modifiedMetric = `M${metric}`;
113331
113403
  const metricsRecord = metrics;
113332
113404
  if (metricsRecord[modifiedMetric] && metricsRecord[modifiedMetric] !== "X") {
113333
113405
  value = metricsRecord[modifiedMetric] ?? "";
@@ -113349,12 +113421,12 @@ function getNextLowerScore(macroVector, position) {
113349
113421
  return MACROVECTOR_LOOKUP[nextMacroVector] ?? null;
113350
113422
  }
113351
113423
  function interpolateScore(metrics, macroVector, baseScore) {
113352
- const eq1 = parseInt(macroVector[0]);
113353
- const eq2 = parseInt(macroVector[1]);
113354
- const eq3 = parseInt(macroVector[2]);
113355
- const eq4 = parseInt(macroVector[3]);
113356
- const eq5 = parseInt(macroVector[4]);
113357
- const eq6 = parseInt(macroVector[5]);
113424
+ const eq1 = parseInt(macroVector[0], 10);
113425
+ const eq2 = parseInt(macroVector[1], 10);
113426
+ const eq3 = parseInt(macroVector[2], 10);
113427
+ const eq4 = parseInt(macroVector[3], 10);
113428
+ const eq5 = parseInt(macroVector[4], 10);
113429
+ const eq6 = parseInt(macroVector[5], 10);
113358
113430
  let meanDistance = 0;
113359
113431
  let eqCount = 0;
113360
113432
  const eq1NextLower = getNextLowerScore(macroVector, 0);
@@ -114063,6 +114135,30 @@ var CVSS_SCORER_SYSTEM_PROMPT = `You are a CVSS 4.0 scoring specialist. Your tas
114063
114135
  - If production-like or confirmed unintentional: **E:A**
114064
114136
  - Severity: typically **HIGH-CRITICAL** for real bypasses, **MEDIUM** for intentional test credentials in sandbox
114065
114137
 
114138
+ ### Denial of Service / Resource Exhaustion (unbounded input, algorithmic complexity, amplification)
114139
+ - Typically: **AV:N, AC:L, AT:N, PR** varies (often **L** for authenticated endpoints), **UI:N**
114140
+ - **VC:N, VI:N** — DoS has no confidentiality/integrity impact unless separately demonstrated
114141
+ - **VA** must reflect what the evidence actually proves, not the worst case it implies:
114142
+ - **VA:L** when a single request degrades performance or ties up one worker temporarily (the typical demonstrated case). A slow response (e.g. several seconds) for one request is **VA:L**, not **VA:H**.
114143
+ - **VA:H** ONLY when the POC demonstrates a *sustained, service-wide* outage — e.g. proven worker-pool exhaustion at realistic concurrency, or the service staying unavailable to other users. Extrapolating "5-10 concurrent requests would exhaust the pool" is theoretical and does NOT justify **VA:H** unless the POC actually showed it.
114144
+ - **E:P** when only the resource-consumption gap was demonstrated; **E:A** only if an actual outage was produced and observed during testing.
114145
+ - Severity range: typically **LOW-MEDIUM**. Reserve **HIGH** for a demonstrated full outage with no easy mitigation.
114146
+
114147
+ ### OAuth Flow Weaknesses (missing PKCE, weak/predictable state, state integrity)
114148
+ - These findings describe a *missing or weak control* in an auth flow. The impact (account/session takeover) is only realizable when chained with a *separate* capability: an authorization-code interception path (open redirect, referrer leakage, network MITM) or a forgeable/guessable state.
114149
+ - **Do NOT credit full VC:H/VI:H on the vulnerable system unless the interception/forgery chain was actually demonstrated end to end.** If only the absence of PKCE (or a missing signature) was shown, the direct impact on the vulnerable system is limited → prefer **VC:L/VI:L or N** and **E:P**, with **AC:H** and/or **AT:P** to reflect the required preconditions.
114150
+ - If a state parameter already binds to the initiating user (e.g. a server-side userId check on return), missing PKCE/signing is largely a **defense-in-depth / best-practice** gap → **LOW** (or informational when state is also unguessable and validated).
114151
+ - Severity range: typically **LOW** for "missing PKCE / unsigned state" in isolation; elevate only when a working interception or CSRF-via-state-forgery chain is demonstrated.
114152
+
114153
+ ## Severity Calibration Principles
114154
+
114155
+ Apply these across every vulnerability class. They override the worst-case instinct.
114156
+
114157
+ - **Score what was demonstrated, not what could theoretically follow.** The CVSS reflects the impact the POC actually proved on the target, not the maximal impact the weakness might enable in a different configuration or when chained with an undiscovered bug.
114158
+ - **Chained / conditional exploitation:** when realizing impact depends on a *separate, undemonstrated* vulnerability or attacker-favorable precondition (interception position, a second bug, a guessed identifier), reflect that in the exploitability metrics (**AC:H**, **AT:P**, exploit maturity **E:P/U**) and do NOT assign full **VC:H/VI:H/VA:H** to the vulnerable system. A finding whose impact is entirely contingent on a missing precondition trends **LOW**.
114159
+ - **Security-boundary bypass without proven sensitive exposure:** when a test shows an access-control/authorization boundary was bypassed but the data actually returned is non-sensitive or same-tenant/expected-visible, score the *demonstrated* confidentiality impact (often **VC:L** or **VC:N**), not the boundary's theoretical worst case. Note explicitly in the reasoning what data was (and was not) exposed.
114160
+ - **Cross-tenant vs same-tenant matters:** confirmed cross-tenant/cross-user exposure of private data justifies **VC:H**; same-tenant data the identity could plausibly already see does not. If tenancy is unproven, say so and score conservatively.
114161
+
114066
114162
  ## Analysis Instructions
114067
114163
 
114068
114164
  1. Read the finding description and evidence carefully
@@ -114070,8 +114166,8 @@ var CVSS_SCORER_SYSTEM_PROMPT = `You are a CVSS 4.0 scoring specialist. Your tas
114070
114166
  3. Assess complexity based on whether special conditions were needed
114071
114167
  4. Determine privileges based on authentication requirements
114072
114168
  5. Evaluate user interaction based on exploit mechanics
114073
- 6. Assess impact on both the vulnerable system AND potential subsequent systems
114074
- 7. Since a POC exists and confirmed the vulnerability, E should typically be 'A'
114169
+ 6. Assess impact on both the vulnerable system AND potential subsequent systems — score what the evidence proves, not the worst case it implies (see Severity Calibration Principles)
114170
+ 7. Exploit Maturity (E): use **A (Attacked)** only when the POC demonstrated the actual security impact (data accessed, outage produced, session taken over). When the POC only proved the *gap* exists — a missing control, a slow response, a boundary bypass without confirmed sensitive exposure — use **P (POC)**. Do not default to **A** merely because a script ran and exited 0.
114075
114171
 
114076
114172
  Always provide brief reasoning explaining your key decisions.
114077
114173
 
@@ -114103,6 +114199,8 @@ In addition to CVSS metrics, assign one or more CWE identifiers to the finding.
114103
114199
  | Hardcoded Credentials | CWE-798 | CWE-259 (Hard-coded Password), CWE-321 (Hard-coded Crypto Key) |
114104
114200
  | Captcha Bypass | CWE-804 | CWE-837 (Improper Enforcement of Single Access) |
114105
114201
  | Missing Security Headers | CWE-1021 | CWE-693 (Protection Mechanism Failure), CWE-16 (Configuration) |
114202
+ | Denial of Service / Resource Exhaustion | CWE-400 | CWE-770 (Allocation Without Limits), CWE-1333 (Inefficient Regex) |
114203
+ | OAuth Flow Weakness (missing PKCE, weak state) | CWE-352 | CWE-345 (Insufficient Verification of Authenticity), CWE-1275 (Sensitive Cookie Weak Attributes) |
114106
114204
 
114107
114205
  ### CWE Assignment Rules
114108
114206
 
@@ -114142,7 +114240,7 @@ var MAX_IMPACT_CHARS = 2000;
114142
114240
  function truncateField(value, limit) {
114143
114241
  if (value.length <= limit)
114144
114242
  return value;
114145
- return value.substring(0, limit) + `
114243
+ return `${value.substring(0, limit)}
114146
114244
  ... [truncated]`;
114147
114245
  }
114148
114246
  function buildScoringPrompt(input) {
@@ -114228,8 +114326,8 @@ function extractContextSummary(messages) {
114228
114326
  return `No additional context available from testing conversation.
114229
114327
  `;
114230
114328
  }
114231
- return contextParts.join(`
114232
- `) + `
114329
+ return `${contextParts.join(`
114330
+ `)}
114233
114331
  `;
114234
114332
  }
114235
114333
 
@@ -114239,7 +114337,7 @@ init_lazyLogger();
114239
114337
  var log6 = scopedLogger(() => createLogger("FindingJudge"));
114240
114338
  async function judgeFinding(input, ctx) {
114241
114339
  try {
114242
- const { FindingJudgeAgent } = await import("./agent-6nhperp2.js");
114340
+ const { FindingJudgeAgent } = await import("./agent-3n8msbqb.js");
114243
114341
  const agent = new FindingJudgeAgent({
114244
114342
  finding: input,
114245
114343
  model: ctx.model,
@@ -114529,14 +114627,14 @@ CRITICAL RULES — READ BEFORE CALLING:
114529
114627
  description: `POC execution output for ${filename}`
114530
114628
  });
114531
114629
  const timestamp = new Date().toISOString();
114532
- const outputDir = isVulnerability ? session.findingsPath : join12(session.rootPath, "informational");
114630
+ const outputDir = isVulnerability ? session.findingsPath : join13(session.rootPath, "informational");
114533
114631
  if (!isVulnerability) {
114534
114632
  mkdirSync7(outputDir, { recursive: true });
114535
114633
  }
114536
114634
  let evidenceForPrompt = materializedEvidence;
114537
114635
  if (materializedEvidence.length > EVIDENCE_FILE_THRESHOLD) {
114538
114636
  const evidenceFilename = `${timestamp.split("T")[0]}-${slugify2(input.title, 40)}-evidence.txt`;
114539
- const evidenceFilePath = join12(outputDir, evidenceFilename);
114637
+ const evidenceFilePath = join13(outputDir, evidenceFilename);
114540
114638
  writeFileSync10(evidenceFilePath, materializedEvidence);
114541
114639
  evidenceForPrompt = materializedEvidence.substring(0, EVIDENCE_FILE_THRESHOLD) + `
114542
114640
  ... [truncated — full output saved to ${evidenceFilename}]`;
@@ -114678,8 +114776,8 @@ CRITICAL RULES — READ BEFORE CALLING:
114678
114776
  const findingId = `${timestamp.split("T")[0]}-${slugify2(finding.title, 50)}`;
114679
114777
  const jsonFilename = `${findingId}.json`;
114680
114778
  const mdFilename = `${findingId}.md`;
114681
- const jsonPath = join12(outputDir, jsonFilename);
114682
- const mdPath = join12(outputDir, mdFilename);
114779
+ const jsonPath = join13(outputDir, jsonFilename);
114780
+ const mdPath = join13(outputDir, mdFilename);
114683
114781
  try {
114684
114782
  writeFileSync10(jsonPath, JSON.stringify(findingWithMeta, null, 2));
114685
114783
  const cvssSection = cvssWarning ? `## CVSS 4.0 Assessment
@@ -114762,7 +114860,7 @@ ${finding.references}` : ""}
114762
114860
  `;
114763
114861
  writeFileSync10(mdPath, markdown);
114764
114862
  if (isVulnerability) {
114765
- const summaryPath = join12(session.rootPath, "findings-summary.md");
114863
+ const summaryPath = join13(session.rootPath, "findings-summary.md");
114766
114864
  const cweTag = cvssResult.cwes?.length ? ` (${cvssResult.cwes.map((c) => c.id).join(", ")})` : "";
114767
114865
  const cvssTag = cvssWarning ? "(estimated)" : `(CVSS ${cvssResult.score})`;
114768
114866
  const summaryEntry = `- [${finding.severity}] ${cvssTag}${cweTag} ${finding.title} - \`findings/${mdFilename}\`
@@ -114820,7 +114918,7 @@ async function executeLocalPoc(ctx, input) {
114820
114918
  mkdirSync7(pocsPath, { recursive: true });
114821
114919
  }
114822
114920
  const { filename, pocContent } = preparePoc(input);
114823
- const pocPath = join12(pocsPath, filename);
114921
+ const pocPath = join13(pocsPath, filename);
114824
114922
  writeFileSync10(pocPath, pocContent);
114825
114923
  chmodSync(pocPath, 493);
114826
114924
  const { stdout, stderr, exitCode } = await runScript(POC_RUNNERS[input.pocType], pocPath, 60000, ctx.abortSignal);
@@ -114838,7 +114936,7 @@ async function executeSandboxPoc(ctx, input) {
114838
114936
  if (!existsSync8(localPocsPath)) {
114839
114937
  mkdirSync7(localPocsPath, { recursive: true });
114840
114938
  }
114841
- const localPocPath = join12(localPocsPath, filename);
114939
+ const localPocPath = join13(localPocsPath, filename);
114842
114940
  writeFileSync10(localPocPath, pocContent);
114843
114941
  const sandboxPocPath = `/tmp/pocs/${filename}`;
114844
114942
  const base64Content = Buffer.from(pocContent).toString("base64");
@@ -114871,10 +114969,10 @@ POC file has been deleted.`,
114871
114969
  }
114872
114970
  function cleanupPocFiles(ctx, filename) {
114873
114971
  try {
114874
- unlinkSync(join12(ctx.session.pocsPath, filename));
114972
+ unlinkSync(join13(ctx.session.pocsPath, filename));
114875
114973
  } catch {}
114876
114974
  try {
114877
- unlinkSync(join12(ctx.session.pocsPath, `${filename}.output.json`));
114975
+ unlinkSync(join13(ctx.session.pocsPath, `${filename}.output.json`));
114878
114976
  } catch {}
114879
114977
  }
114880
114978
  function sanitizeFilename(str) {
@@ -114935,7 +115033,7 @@ ${commentChar} Created: ${new Date().toISOString()}
114935
115033
  }
114936
115034
  function writePocOutputSidecar(pocsPath, filename, stdout, stderr, exitCode, description) {
114937
115035
  try {
114938
- const outputPath = join12(pocsPath, `${filename}.output.json`);
115036
+ const outputPath = join13(pocsPath, `${filename}.output.json`);
114939
115037
  writeFileSync10(outputPath, JSON.stringify({
114940
115038
  stdout,
114941
115039
  stderr,
@@ -117765,7 +117863,7 @@ function hasImapAttachments(bodyStructure) {
117765
117863
  return false;
117766
117864
  }
117767
117865
  function truncate(s, max) {
117768
- return s.length > max ? s.slice(0, max) + `
117866
+ return s.length > max ? `${s.slice(0, max)}
117769
117867
 
117770
117868
  (truncated)` : s;
117771
117869
  }
@@ -118005,7 +118103,8 @@ Sets the read/seen flag on a message so it no longer appears as unread.`,
118005
118103
 
118006
118104
  // src/core/agents/offSecAgent/tools/email/sendEmail.ts
118007
118105
  init_dist();
118008
- import { readFile } from "fs/promises";
118106
+ import { readFile } from "node:fs/promises";
118107
+ import { basename } from "node:path";
118009
118108
 
118010
118109
  // node_modules/mime-types/index.js
118011
118110
  /*!
@@ -118126,7 +118225,6 @@ var $createTransport = function(transporter, defaults) {
118126
118225
 
118127
118226
  // src/core/agents/offSecAgent/tools/email/sendEmail.ts
118128
118227
  init_zod();
118129
- import { basename } from "path";
118130
118228
  var attachmentSchema = exports_external.object({
118131
118229
  path: exports_external.string().describe("Absolute path to the file on disk to attach. The file is read and included inline."),
118132
118230
  filename: exports_external.string().optional().describe("Override the attachment filename (defaults to the basename of the path)")
@@ -118249,13 +118347,181 @@ var SEND_EMAIL_TOOL_NAME = "send_email";
118249
118347
  // src/core/agents/offSecAgent/tools/executeCommand.ts
118250
118348
  init_dist();
118251
118349
  init_zod();
118252
- import { existsSync as existsSync9, mkdirSync as mkdirSync8, writeFileSync as writeFileSync11 } from "fs";
118253
- import { join as join13 } from "path";
118350
+ import { existsSync as existsSync9, mkdirSync as mkdirSync8, writeFileSync as writeFileSync11 } from "node:fs";
118351
+ import { join as join15 } from "node:path";
118352
+
118353
+ // src/core/prompt-injections/index.ts
118354
+ init_zod();
118355
+ import { createHash } from "node:crypto";
118356
+ import { readFileSync as readFileSync2, statSync as statSync2 } from "node:fs";
118357
+ import { dirname as dirname5, isAbsolute as isAbsolute2, join as join14, relative, resolve as resolve2, sep } from "node:path";
118358
+ function sha256(value) {
118359
+ return createHash("sha256").update(value).digest("hex");
118360
+ }
118361
+ var PromptInjectionCatalogEntrySchema = exports_external.object({
118362
+ id: exports_external.string().min(1),
118363
+ name: exports_external.string().min(1),
118364
+ category: exports_external.enum([
118365
+ "instruction-hijack",
118366
+ "data-exfiltration",
118367
+ "tool-misuse",
118368
+ "role-confusion",
118369
+ "encoding"
118370
+ ]),
118371
+ description: exports_external.string(),
118372
+ tags: exports_external.array(exports_external.string()).default([]),
118373
+ deliveryHints: exports_external.array(exports_external.string()).default([]),
118374
+ expectedObservation: exports_external.string().default(""),
118375
+ payloadPath: exports_external.string().min(1)
118376
+ });
118377
+ var PromptInjectionLibraryFileSchema = exports_external.union([
118378
+ exports_external.array(PromptInjectionCatalogEntrySchema),
118379
+ exports_external.object({
118380
+ payloads: exports_external.array(PromptInjectionCatalogEntrySchema)
118381
+ }),
118382
+ exports_external.object({
118383
+ injections: exports_external.array(PromptInjectionCatalogEntrySchema)
118384
+ })
118385
+ ]);
118386
+ function isPromptInjectionRef(value) {
118387
+ return typeof value === "object" && value !== null && value.kind === "prompt_injection_ref" && typeof value.id === "string";
118388
+ }
118389
+
118390
+ class StaticPromptInjectionLibrary {
118391
+ ordered;
118392
+ entries;
118393
+ hashes;
118394
+ constructor(entries) {
118395
+ this.ordered = entries;
118396
+ this.entries = new Map(entries.map((entry) => [entry.id, entry]));
118397
+ this.hashes = new Map(entries.map((entry) => [entry.id, sha256(entry.payload)]));
118398
+ }
118399
+ listCatalog() {
118400
+ return this.ordered.map(({ payload, payloadFilePath: _path, ...entry }) => ({
118401
+ ...entry,
118402
+ payloadHash: sha256(payload)
118403
+ }));
118404
+ }
118405
+ getPayload(id) {
118406
+ return this.entries.get(id)?.payload;
118407
+ }
118408
+ getPayloadFilePath(id) {
118409
+ return this.entries.get(id)?.payloadFilePath;
118410
+ }
118411
+ getPayloadHash(id) {
118412
+ return this.hashes.get(id);
118413
+ }
118414
+ has(id) {
118415
+ return this.entries.has(id);
118416
+ }
118417
+ }
118418
+ var EMPTY_PROMPT_INJECTION_LIBRARY = new StaticPromptInjectionLibrary([]);
118419
+ var SOURCE_CACHE = new Map;
118420
+ function resolvePromptInjectionLibrarySource(explicit) {
118421
+ return explicit || process.env.PENSAR_PROMPT_INJECTION_LIBRARY || process.env.APEX_PROMPT_INJECTION_LIBRARY;
118422
+ }
118423
+ function resolveCatalogPath(source) {
118424
+ if (source.startsWith("https://") || source.startsWith("http://")) {
118425
+ throw new Error("Prompt injection library source must be a local path, not a URL.");
118426
+ }
118427
+ const path = source.startsWith("file://") ? source.slice(7) : source;
118428
+ const resolved = isAbsolute2(path) ? path : resolve2(process.cwd(), path);
118429
+ const stat = statSync2(resolved);
118430
+ if (stat.isDirectory()) {
118431
+ return { catalogPath: join14(resolved, "catalog.json"), root: resolved };
118432
+ }
118433
+ return { catalogPath: resolved, root: dirname5(resolved) };
118434
+ }
118435
+ function resolvePayloadPath(root, payloadPath) {
118436
+ if (isAbsolute2(payloadPath)) {
118437
+ throw new Error("Prompt injection payloadPath must be relative.");
118438
+ }
118439
+ const resolved = resolve2(root, payloadPath);
118440
+ const relativePath = relative(root, resolved);
118441
+ if (relativePath === ".." || relativePath.startsWith(`..${sep}`)) {
118442
+ throw new Error("Prompt injection payloadPath must stay within the library.");
118443
+ }
118444
+ return resolved;
118445
+ }
118446
+ function parsePromptInjectionLibrary(raw, root) {
118447
+ const parsed = PromptInjectionLibraryFileSchema.parse(JSON.parse(raw));
118448
+ const catalogEntries = Array.isArray(parsed) ? parsed : ("payloads" in parsed) ? parsed.payloads : parsed.injections;
118449
+ const entries = catalogEntries.map((entry) => {
118450
+ const payloadFile = resolvePayloadPath(root, entry.payloadPath);
118451
+ const payload = readFileSync2(payloadFile, "utf-8");
118452
+ const { payloadPath: _payloadPath, ...safeEntry } = entry;
118453
+ return { ...safeEntry, payload, payloadFilePath: payloadFile };
118454
+ });
118455
+ return new StaticPromptInjectionLibrary(entries);
118456
+ }
118457
+ async function readSource(source) {
118458
+ if (source.startsWith("https://") || source.startsWith("http://")) {
118459
+ throw new Error("Prompt injection library source must be a local path, not a URL.");
118460
+ }
118461
+ const { catalogPath, root } = resolveCatalogPath(source);
118462
+ return parsePromptInjectionLibrary(readFileSync2(catalogPath, "utf-8"), root);
118463
+ }
118464
+ async function loadPromptInjectionLibrary(source) {
118465
+ let cached = SOURCE_CACHE.get(source);
118466
+ if (!cached) {
118467
+ cached = readSource(source).catch((err) => {
118468
+ SOURCE_CACHE.delete(source);
118469
+ throw err;
118470
+ });
118471
+ SOURCE_CACHE.set(source, cached);
118472
+ }
118473
+ return cached;
118474
+ }
118475
+ async function getPromptInjectionLibrary(opts) {
118476
+ if (opts?.library)
118477
+ return opts.library;
118478
+ const source = resolvePromptInjectionLibrarySource(opts?.source);
118479
+ if (!source)
118480
+ return EMPTY_PROMPT_INJECTION_LIBRARY;
118481
+ return loadPromptInjectionLibrary(source);
118482
+ }
118483
+ function resolvePromptInjectionRefs(value, library) {
118484
+ if (isPromptInjectionRef(value)) {
118485
+ const payload = library.getPayload(value.id);
118486
+ if (!payload)
118487
+ throw new Error(`Unknown prompt injection id: ${value.id}`);
118488
+ return payload;
118489
+ }
118490
+ if (Array.isArray(value)) {
118491
+ return value.map((item) => resolvePromptInjectionRefs(item, library));
118492
+ }
118493
+ if (typeof value === "object" && value !== null) {
118494
+ const resolved = {};
118495
+ for (const [key, nested] of Object.entries(value)) {
118496
+ resolved[key] = resolvePromptInjectionRefs(nested, library);
118497
+ }
118498
+ return resolved;
118499
+ }
118500
+ return value;
118501
+ }
118502
+ function redactPromptInjectionPayloads(value, library) {
118503
+ let redacted = value;
118504
+ for (const entry of library.listCatalog()) {
118505
+ const payload = library.getPayload(entry.id);
118506
+ if (!payload)
118507
+ continue;
118508
+ redacted = redacted.split(payload).join(`[PROMPT_INJECTION:${entry.id}]`);
118509
+ }
118510
+ return redacted;
118511
+ }
118512
+
118513
+ // src/core/agents/offSecAgent/tools/executeCommand.ts
118254
118514
  var MAX_INLINE = 50000;
118255
118515
  var MS_TIMEOUT_THRESHOLD = 1e4;
118516
+ var DEFAULT_PROMPT_INJECTION_FILE_ENV = "APEX_PROMPT_INJECTION_FILE";
118517
+ var promptInjectionPointerSchema = exports_external.object({
118518
+ id: exports_external.string().min(1).describe("Stable prompt-injection id returned by list_prompt_injections."),
118519
+ envVar: exports_external.string().regex(/^[A-Za-z_][A-Za-z0-9_]*$/).optional().describe(`Environment variable that will contain the payload file path at runtime. Defaults to ${DEFAULT_PROMPT_INJECTION_FILE_ENV}.`)
118520
+ });
118256
118521
  var executeCommandInputSchema = exports_external.object({
118257
118522
  toolCallDescription: exports_external.string().describe("A concise, human-readable description of what this tool call is doing (e.g., 'Scanning for open ports on target')"),
118258
118523
  command: exports_external.string().describe("The shell command to execute"),
118524
+ promptInjection: promptInjectionPointerSchema.optional().describe("Optional runtime prompt-injection file pointer. The tool resolves the id to a local payload file path and exposes that path through envVar. The raw payload text is never inserted into the command."),
118259
118525
  timeout: exports_external.number().optional().describe("Timeout in seconds. If omitted, the command runs until completion or abort."),
118260
118526
  allow_unprotected: exports_external.boolean().optional().describe("Acknowledge that this command will run WITHOUT the session's configured custom HTTP headers because the tool is unrecognized or the command is pipelined. Defaults to false (fail-closed). Use only when you understand the headers will not be applied.")
118261
118527
  });
@@ -118272,13 +118538,13 @@ function maybeSaveFullOutput(raw, ctx) {
118272
118538
  if (raw.length <= MAX_INLINE) {
118273
118539
  return { text: raw || "(no output)" };
118274
118540
  }
118275
- const outputDir = join13(ctx.session.logsPath, "cmd-output");
118541
+ const outputDir = join15(ctx.session.logsPath, "cmd-output");
118276
118542
  if (!existsSync9(outputDir)) {
118277
118543
  mkdirSync8(outputDir, { recursive: true });
118278
118544
  }
118279
118545
  const ts = new Date().toISOString().replace(/[:.]/g, "-");
118280
118546
  const filename = `output-${ts}.txt`;
118281
- const filePath = join13(outputDir, filename);
118547
+ const filePath = join15(outputDir, filename);
118282
118548
  try {
118283
118549
  writeFileSync11(filePath, raw);
118284
118550
  } catch {
@@ -118296,6 +118562,49 @@ function maybeSaveFullOutput(raw, ctx) {
118296
118562
  file: filePath
118297
118563
  };
118298
118564
  }
118565
+ function shellQuote2(value) {
118566
+ return `'${value.replace(/'/g, `'\\''`)}'`;
118567
+ }
118568
+ function wrapCommandWithEnv(command, envVars) {
118569
+ if (!envVars || Object.keys(envVars).length === 0)
118570
+ return command;
118571
+ const assignments = Object.entries(envVars).map(([name, value]) => {
118572
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) {
118573
+ throw new Error(`Invalid environment variable name: ${name}`);
118574
+ }
118575
+ return `${name}=${shellQuote2(value)}`;
118576
+ }).join(" ");
118577
+ return `env ${assignments} bash -lc ${shellQuote2(command)}`;
118578
+ }
118579
+ async function resolvePromptInjectionEnv(promptInjection, ctx) {
118580
+ if (!promptInjection)
118581
+ return {};
118582
+ const library = await getPromptInjectionLibrary({
118583
+ library: ctx.promptInjectionLibrary,
118584
+ source: ctx.promptInjectionLibrarySource
118585
+ });
118586
+ const payloadContent = library.getPayload(promptInjection.id);
118587
+ if (payloadContent === undefined) {
118588
+ return {
118589
+ library,
118590
+ error: `Unknown prompt injection id: ${promptInjection.id}`
118591
+ };
118592
+ }
118593
+ const payloadFilePath = library.getPayloadFilePath(promptInjection.id);
118594
+ if (!payloadFilePath) {
118595
+ return {
118596
+ library,
118597
+ error: `Unknown prompt injection id or no payload file path available: ` + promptInjection.id
118598
+ };
118599
+ }
118600
+ return {
118601
+ library,
118602
+ payloadContent,
118603
+ envVars: {
118604
+ [promptInjection.envVar ?? DEFAULT_PROMPT_INJECTION_FILE_ENV]: payloadFilePath
118605
+ }
118606
+ };
118607
+ }
118299
118608
  function executeCommand(ctx) {
118300
118609
  return tool({
118301
118610
  description: `Execute a shell command for penetration testing activities.
@@ -118356,10 +118665,18 @@ results to disk before any signal arrives.
118356
118665
  - nmap: prefer --host-timeout, --max-rtt-timeout, and -T4 / --min-rate
118357
118666
  to bound total runtime against slow networks.
118358
118667
 
118668
+ PROMPT-INJECTION PAYLOADS:
118669
+ - Do not put raw prompt-injection payload text in the command.
118670
+ - To run a local harness with a payload, set promptInjection.id to an id from
118671
+ list_prompt_injections and reference "$APEX_PROMPT_INJECTION_FILE" in the
118672
+ command. The tool resolves that variable to the local payload file path only
118673
+ at runtime.
118674
+
118359
118675
  IMPORTANT: Always analyze results and adjust your approach based on findings.`,
118360
118676
  inputSchema: executeCommandInputSchema,
118361
118677
  execute: async ({
118362
118678
  command,
118679
+ promptInjection,
118363
118680
  timeout,
118364
118681
  allow_unprotected
118365
118682
  }) => {
@@ -118398,7 +118715,35 @@ IMPORTANT: Always analyze results and adjust your approach based on findings.`,
118398
118715
  command
118399
118716
  };
118400
118717
  }
118401
- const effectiveCommand = inject.status === "injected" ? inject.command : command;
118718
+ const commandWithHeaders = inject.status === "injected" ? inject.command : command;
118719
+ let promptInjectionLibrary;
118720
+ let promptInjectionEnvVars;
118721
+ let promptInjectionPayloadContent;
118722
+ try {
118723
+ const resolved = await resolvePromptInjectionEnv(promptInjection, ctx);
118724
+ if (resolved.error) {
118725
+ return {
118726
+ success: false,
118727
+ error: resolved.error,
118728
+ stdout: "",
118729
+ stderr: resolved.error,
118730
+ command
118731
+ };
118732
+ }
118733
+ promptInjectionLibrary = resolved.library;
118734
+ promptInjectionEnvVars = resolved.envVars;
118735
+ promptInjectionPayloadContent = resolved.payloadContent;
118736
+ } catch (error) {
118737
+ const msg = error instanceof Error ? error.message : String(error);
118738
+ return {
118739
+ success: false,
118740
+ error: msg,
118741
+ stdout: "",
118742
+ stderr: msg,
118743
+ command
118744
+ };
118745
+ }
118746
+ const redact = (value) => promptInjectionLibrary ? redactPromptInjectionPayloads(value, promptInjectionLibrary) : value;
118402
118747
  if (ctx.sandbox) {
118403
118748
  try {
118404
118749
  const ssmOpts = {};
@@ -118406,13 +118751,38 @@ IMPORTANT: Always analyze results and adjust your approach based on findings.`,
118406
118751
  if (normalizedTimeout != null) {
118407
118752
  ssmOpts.timeout = normalizedTimeout;
118408
118753
  }
118409
- const result = await ctx.sandbox.execute(effectiveCommand, ssmOpts);
118410
- const { text: stdout, file: outputFile } = maybeSaveFullOutput(result.stdout, ctx);
118754
+ if (promptInjectionPayloadContent && promptInjection) {
118755
+ const envVarName = promptInjection.envVar ?? DEFAULT_PROMPT_INJECTION_FILE_ENV;
118756
+ const sandboxTempFile = `/tmp/apex_payload_${Date.now()}.txt`;
118757
+ const escapedPayload = promptInjectionPayloadContent.replace(/\\/g, "\\\\").replace(/'/g, "'\\''");
118758
+ const writeCommand = `printf '%s' '${escapedPayload}' > ${sandboxTempFile}`;
118759
+ const writeResult = await ctx.sandbox.execute(writeCommand, {
118760
+ timeout: normalizedTimeout ?? 30
118761
+ });
118762
+ if (!writeResult.success) {
118763
+ const errorMsg = `Failed to write prompt injection payload to sandbox: ${writeResult.stderr || "unknown error"}`;
118764
+ return {
118765
+ success: false,
118766
+ error: errorMsg,
118767
+ stdout: writeResult.stdout,
118768
+ stderr: writeResult.stderr || errorMsg,
118769
+ command
118770
+ };
118771
+ }
118772
+ ssmOpts.envVars = {
118773
+ [envVarName]: sandboxTempFile
118774
+ };
118775
+ } else if (promptInjectionEnvVars) {
118776
+ ssmOpts.envVars = promptInjectionEnvVars;
118777
+ }
118778
+ const result = await ctx.sandbox.execute(commandWithHeaders, ssmOpts);
118779
+ const { text: stdout, file: outputFile } = maybeSaveFullOutput(redact(result.stdout), ctx);
118780
+ const stderr = redact(result.stderr || "");
118411
118781
  return {
118412
118782
  success: result.success,
118413
- error: !result.success ? result.stderr || "Command failed" : "",
118783
+ error: !result.success ? stderr || "Command failed" : "",
118414
118784
  stdout,
118415
- stderr: result.stderr || "",
118785
+ stderr,
118416
118786
  command,
118417
118787
  outputFile
118418
118788
  };
@@ -118430,14 +118800,15 @@ IMPORTANT: Always analyze results and adjust your approach based on findings.`,
118430
118800
  if (ctx.persistentShell) {
118431
118801
  try {
118432
118802
  const normalizedTimeout = normalizeExecuteCommandTimeout(timeout);
118433
- const onData = ctx.eventBus ? (data) => ctx.eventBus.emit("command-output", { data }) : undefined;
118434
- const result = await ctx.persistentShell.execute(effectiveCommand, normalizedTimeout, onData, ctx.abortSignal);
118435
- const { text: stdout, file: outputFile } = maybeSaveFullOutput(result.stdout, ctx);
118803
+ const onData = ctx.eventBus ? (data) => ctx.eventBus?.emit("command-output", { data: redact(data) }) : undefined;
118804
+ const result = await ctx.persistentShell.execute(wrapCommandWithEnv(commandWithHeaders, promptInjectionEnvVars), normalizedTimeout, onData, ctx.abortSignal);
118805
+ const { text: stdout, file: outputFile } = maybeSaveFullOutput(redact(result.stdout), ctx);
118806
+ const stderr = redact(result.stderr);
118436
118807
  return {
118437
118808
  success: result.exitCode === 0,
118438
118809
  error: result.exitCode === 124 ? "Command timed out" : result.exitCode !== 0 ? `Exit code: ${result.exitCode}` : "",
118439
118810
  stdout,
118440
- stderr: result.stderr,
118811
+ stderr,
118441
118812
  command,
118442
118813
  outputFile
118443
118814
  };
@@ -118654,7 +119025,7 @@ BEST PRACTICES:
118654
119025
  // src/core/agents/offSecAgent/tools/grep.ts
118655
119026
  init_dist();
118656
119027
  init_zod();
118657
- import { spawn as spawn3 } from "child_process";
119028
+ import { spawn as spawn3 } from "node:child_process";
118658
119029
  var grepInputSchema = exports_external.object({
118659
119030
  pattern: exports_external.string().describe("The pattern to search for"),
118660
119031
  directory: exports_external.string().optional().describe("Directory or file path to search in (defaults to current working directory)"),
@@ -118698,7 +119069,7 @@ search with flags or a more specific directory if results are truncated.`,
118698
119069
  const defaultFlags = hasRecursive ? [] : ["-r"];
118699
119070
  const args = [...defaultFlags, ...userFlags, "--", pattern, dir];
118700
119071
  const command = `grep ${args.join(" ")}`;
118701
- return new Promise((resolve2) => {
119072
+ return new Promise((resolve3) => {
118702
119073
  const child = spawn3("grep", args, {
118703
119074
  cwd,
118704
119075
  stdio: ["ignore", "pipe", "pipe"]
@@ -118712,7 +119083,7 @@ search with flags or a more specific directory if results are truncated.`,
118712
119083
  ctx.abortSignal.addEventListener("abort", abortHandler, {
118713
119084
  once: true
118714
119085
  });
118715
- abortCleanup = () => ctx.abortSignal.removeEventListener("abort", abortHandler);
119086
+ abortCleanup = () => ctx.abortSignal?.removeEventListener("abort", abortHandler);
118716
119087
  }
118717
119088
  const safeResolve = (result) => {
118718
119089
  if (resolved)
@@ -118720,7 +119091,7 @@ search with flags or a more specific directory if results are truncated.`,
118720
119091
  resolved = true;
118721
119092
  clearTimeout(timeout);
118722
119093
  abortCleanup?.();
118723
- resolve2(result);
119094
+ resolve3(result);
118724
119095
  };
118725
119096
  const timeout = setTimeout(() => {
118726
119097
  child.kill("SIGTERM");
@@ -118764,28 +119135,44 @@ search with flags or a more specific directory if results are truncated.`,
118764
119135
  // src/core/agents/offSecAgent/tools/httpRequest.ts
118765
119136
  init_dist();
118766
119137
  init_zod();
118767
- import { existsSync as existsSync10, mkdirSync as mkdirSync9, writeFileSync as writeFileSync12 } from "fs";
118768
- import { join as join14 } from "path";
119138
+ import { existsSync as existsSync10, mkdirSync as mkdirSync9, writeFileSync as writeFileSync12 } from "node:fs";
119139
+ import { join as join16 } from "node:path";
118769
119140
  var MAX_INLINE_BODY = 5000;
119141
+ var promptInjectionRefSchema = exports_external.object({
119142
+ kind: exports_external.literal("prompt_injection_ref"),
119143
+ id: exports_external.string().describe("Stable prompt-injection id returned by list_prompt_injections")
119144
+ });
118770
119145
  var httpRequestInputSchema = exports_external.object({
118771
119146
  url: exports_external.string().describe("The URL to request"),
118772
119147
  method: exports_external.enum(["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"]).default("GET"),
118773
119148
  headers: exports_external.string().optional().describe(`HTTP headers as a JSON-encoded object string, e.g. '{"Content-Type": "application/json", "Authorization": "Bearer token"}'`),
118774
- body: exports_external.string().optional().describe("Request body (for POST, PUT, PATCH)"),
119149
+ body: exports_external.union([exports_external.string(), promptInjectionRefSchema]).optional().describe("Request body (for POST, PUT, PATCH). To use a hidden prompt-injection payload, pass a PromptInjectionRef object instead of raw payload text."),
118775
119150
  followRedirects: exports_external.boolean().default(false).describe("Whether to follow HTTP redirects (3xx). Defaults to false so you can see redirect responses with Location and Set-Cookie headers."),
118776
119151
  timeout: exports_external.number().default(1e4),
118777
119152
  toolCallDescription: exports_external.string().describe("A concise, human-readable description of what this tool call is doing (e.g., 'Testing SQL injection on login endpoint')")
118778
119153
  });
119154
+ function containsPromptInjectionRef(value) {
119155
+ if (typeof value === "object" && value !== null && value.kind === "prompt_injection_ref") {
119156
+ return true;
119157
+ }
119158
+ if (Array.isArray(value)) {
119159
+ return value.some((item) => containsPromptInjectionRef(item));
119160
+ }
119161
+ if (typeof value === "object" && value !== null) {
119162
+ return Object.values(value).some((nested) => containsPromptInjectionRef(nested));
119163
+ }
119164
+ return false;
119165
+ }
118779
119166
  function maybeSaveBody(body, ctx) {
118780
119167
  if (body.length <= MAX_INLINE_BODY)
118781
119168
  return { text: body };
118782
- const outputDir = join14(ctx.session.logsPath, "http-responses");
119169
+ const outputDir = join16(ctx.session.logsPath, "http-responses");
118783
119170
  if (!existsSync10(outputDir)) {
118784
119171
  mkdirSync9(outputDir, { recursive: true });
118785
119172
  }
118786
119173
  const ts = new Date().toISOString().replace(/[:.]/g, "-");
118787
119174
  const filename = `response-${ts}.txt`;
118788
- const filePath = join14(outputDir, filename);
119175
+ const filePath = join16(outputDir, filename);
118789
119176
  try {
118790
119177
  writeFileSync12(filePath, body);
118791
119178
  } catch {
@@ -118868,16 +119255,39 @@ COMMON TESTING PATTERNS:
118868
119255
  }
118869
119256
  throw e;
118870
119257
  }
118871
- const headers = parseHeaders(rawHeaders);
119258
+ let headers = parseHeaders(rawHeaders);
119259
+ let resolvedBody;
119260
+ let library = EMPTY_PROMPT_INJECTION_LIBRARY;
119261
+ try {
119262
+ const needsLibrary = containsPromptInjectionRef(body) || containsPromptInjectionRef(headers);
119263
+ library = needsLibrary ? await getPromptInjectionLibrary({
119264
+ library: ctx.promptInjectionLibrary,
119265
+ source: ctx.promptInjectionLibrarySource
119266
+ }) : EMPTY_PROMPT_INJECTION_LIBRARY;
119267
+ headers = resolvePromptInjectionRefs(headers, library);
119268
+ resolvedBody = body === undefined ? undefined : String(resolvePromptInjectionRefs(body, library));
119269
+ } catch (e) {
119270
+ return {
119271
+ success: false,
119272
+ error: e instanceof Error ? e.message : String(e),
119273
+ url,
119274
+ method,
119275
+ status: 0,
119276
+ statusText: "",
119277
+ headers: {},
119278
+ body: "",
119279
+ redirected: false
119280
+ };
119281
+ }
118872
119282
  if (ctx.sandbox) {
118873
119283
  return executeSandboxHttpRequest(ctx, {
118874
119284
  url,
118875
119285
  method,
118876
119286
  headers,
118877
- body,
119287
+ body: resolvedBody,
118878
119288
  followRedirects,
118879
119289
  timeout
118880
- });
119290
+ }, library);
118881
119291
  }
118882
119292
  let timeoutId;
118883
119293
  try {
@@ -118900,7 +119310,7 @@ COMMON TESTING PATTERNS:
118900
119310
  const response = await targetFetch(resolverSessionFromCtx(ctx), url, {
118901
119311
  method,
118902
119312
  headers,
118903
- body: body || undefined,
119313
+ body: resolvedBody || undefined,
118904
119314
  redirect: followRedirects ? "follow" : "manual",
118905
119315
  signal: combinedSignal
118906
119316
  });
@@ -118915,12 +119325,17 @@ COMMON TESTING PATTERNS:
118915
119325
  } catch {
118916
119326
  responseBody = "(unable to read response body)";
118917
119327
  }
118918
- const { text: truncatedBody } = maybeSaveBody(responseBody, ctx);
119328
+ const redactedBody = redactPromptInjectionPayloads(responseBody, library);
119329
+ const redactedHeaders = Object.fromEntries(Object.entries(responseHeaders).map(([key, value]) => [
119330
+ key,
119331
+ redactPromptInjectionPayloads(value, library)
119332
+ ]));
119333
+ const { text: truncatedBody } = maybeSaveBody(redactedBody, ctx);
118919
119334
  return {
118920
119335
  success: true,
118921
119336
  status: response.status,
118922
119337
  statusText: response.statusText,
118923
- headers: responseHeaders,
119338
+ headers: redactedHeaders,
118924
119339
  body: truncatedBody,
118925
119340
  url: response.url,
118926
119341
  redirected: response.redirected
@@ -118945,7 +119360,7 @@ COMMON TESTING PATTERNS:
118945
119360
  }
118946
119361
  });
118947
119362
  }
118948
- async function executeSandboxHttpRequest(ctx, opts) {
119363
+ async function executeSandboxHttpRequest(ctx, opts, library) {
118949
119364
  const { url, method, headers, body, followRedirects, timeout } = opts;
118950
119365
  try {
118951
119366
  let curlCommand = `curl -i -X ${method}`;
@@ -118953,9 +119368,30 @@ async function executeSandboxHttpRequest(ctx, opts) {
118953
119368
  for (const [key, value] of Object.entries(mergedHeaders)) {
118954
119369
  curlCommand += ` -H "${shellQuote(`${key}: ${value}`)}"`;
118955
119370
  }
119371
+ const { sandbox } = ctx;
119372
+ if (!sandbox) {
119373
+ throw new Error("executeSandboxHttpRequest requires a sandbox");
119374
+ }
119375
+ let bodyTempFile = null;
118956
119376
  if (body && ["POST", "PUT", "PATCH"].includes(method)) {
118957
- const escapedBody = body.replace(/"/g, "\\\"").replace(/\$/g, "\\$");
118958
- curlCommand += ` -d "${escapedBody}"`;
119377
+ bodyTempFile = `/tmp/apex_http_body_${Date.now()}_${Math.random().toString(36).slice(2, 11)}.txt`;
119378
+ const escapedForPrintf = body.replace(/\\/g, "\\\\").replace(/%/g, "%%");
119379
+ const writeCommand = `printf '%s' '${escapedForPrintf.replace(/'/g, "'\\''")}' > ${bodyTempFile}`;
119380
+ const writeResult = await sandbox.execute(writeCommand, { timeout: 30 });
119381
+ if (!writeResult.success || writeResult.exitCode !== 0) {
119382
+ return {
119383
+ success: false,
119384
+ error: `Failed to write request body to sandbox temp file: ${writeResult.stderr || writeResult.stdout}`,
119385
+ url,
119386
+ method,
119387
+ status: 0,
119388
+ statusText: "",
119389
+ headers: {},
119390
+ body: "",
119391
+ redirected: false
119392
+ };
119393
+ }
119394
+ curlCommand += ` --data-binary @${bodyTempFile}`;
118959
119395
  }
118960
119396
  if (followRedirects) {
118961
119397
  curlCommand += " -L";
@@ -118964,7 +119400,7 @@ async function executeSandboxHttpRequest(ctx, opts) {
118964
119400
  curlCommand += ` --max-time ${timeoutSeconds}`;
118965
119401
  curlCommand += ` "${url}" 2>&1`;
118966
119402
  const ssmTimeout = Math.max(timeoutSeconds, 30);
118967
- const result = await ctx.sandbox.execute(curlCommand, {
119403
+ const result = await sandbox.execute(curlCommand, {
118968
119404
  timeout: ssmTimeout
118969
119405
  });
118970
119406
  const output = result.stdout || "";
@@ -118991,16 +119427,21 @@ async function executeSandboxHttpRequest(ctx, opts) {
118991
119427
  }
118992
119428
  }
118993
119429
  const statusMatch = statusLine.match(/HTTP\/[\d.]+\s+(\d+)\s+(.+)/);
118994
- const status = statusMatch ? parseInt(statusMatch[1]) : 0;
119430
+ const status = statusMatch ? parseInt(statusMatch[1], 10) : 0;
118995
119431
  const statusText = statusMatch ? statusMatch[2] : "Unknown";
118996
119432
  const responseBody = lines.slice(bodyStartIndex).join(`
118997
119433
  `);
118998
- const { text: truncatedBody } = maybeSaveBody(responseBody, ctx);
119434
+ const redactedBody = redactPromptInjectionPayloads(responseBody, library);
119435
+ const redactedHeaders = Object.fromEntries(Object.entries(responseHeaders).map(([key, value]) => [
119436
+ key,
119437
+ redactPromptInjectionPayloads(value, library)
119438
+ ]));
119439
+ const { text: truncatedBody } = maybeSaveBody(redactedBody, ctx);
118999
119440
  return {
119000
119441
  success: status >= 200 && status < 400,
119001
119442
  status,
119002
119443
  statusText,
119003
- headers: responseHeaders,
119444
+ headers: redactedHeaders,
119004
119445
  body: truncatedBody,
119005
119446
  url,
119006
119447
  redirected: false
@@ -119023,8 +119464,8 @@ async function executeSandboxHttpRequest(ctx, opts) {
119023
119464
  // src/core/agents/offSecAgent/tools/listFiles.ts
119024
119465
  init_dist();
119025
119466
  init_zod();
119026
- import { readdir, stat } from "fs/promises";
119027
- import { isAbsolute as isAbsolute2, join as join15, relative, resolve as resolve2 } from "path";
119467
+ import { readdir, stat } from "node:fs/promises";
119468
+ import { isAbsolute as isAbsolute3, join as join17, relative as relative2, resolve as resolve3 } from "node:path";
119028
119469
  var listFilesInputSchema = exports_external.object({
119029
119470
  directory: exports_external.string().optional().describe("Absolute or relative path to the directory to list (defaults to current working directory)"),
119030
119471
  recursive: exports_external.boolean().optional().describe("If true, list files recursively (default: false)"),
@@ -119044,7 +119485,7 @@ async function listRecursive(dir, maxEntries) {
119044
119485
  }
119045
119486
  for (const entry of entries) {
119046
119487
  total++;
119047
- const fullPath = join15(current, entry.name);
119488
+ const fullPath = join17(current, entry.name);
119048
119489
  if (entry.isDirectory()) {
119049
119490
  if (results.length < maxEntries)
119050
119491
  results.push(`${fullPath}/`);
@@ -119061,7 +119502,7 @@ async function listRecursive(dir, maxEntries) {
119061
119502
  function toRelative(base, paths) {
119062
119503
  return paths.map((p) => {
119063
119504
  const isDir = p.endsWith("/");
119064
- const rel = relative(base, isDir ? p.slice(0, -1) : p);
119505
+ const rel = relative2(base, isDir ? p.slice(0, -1) : p);
119065
119506
  return isDir ? `${rel}/` : rel;
119066
119507
  });
119067
119508
  }
@@ -119081,7 +119522,7 @@ Each directory entry is suffixed with "/" for easy identification.`,
119081
119522
  directory,
119082
119523
  recursive = false
119083
119524
  }) => {
119084
- const dir = directory ? isAbsolute2(directory) ? directory : resolve2(ctx.agentCwd, directory) : ctx.agentCwd;
119525
+ const dir = directory ? isAbsolute3(directory) ? directory : resolve3(ctx.agentCwd, directory) : ctx.agentCwd;
119085
119526
  try {
119086
119527
  const info = await stat(dir);
119087
119528
  if (!info.isDirectory()) {
@@ -119107,7 +119548,7 @@ Each directory entry is suffixed with "/" for easy identification.`,
119107
119548
  }
119108
119549
  const entries = await readdir(dir, { withFileTypes: true });
119109
119550
  const fullPaths = entries.map((e) => {
119110
- const name = join15(dir, e.name);
119551
+ const name = join17(dir, e.name);
119111
119552
  return e.isDirectory() ? `${name}/` : name;
119112
119553
  });
119113
119554
  const capped = fullPaths.slice(0, MAX_NON_RECURSIVE);
@@ -119237,38 +119678,38 @@ Returns tasks sorted by ID with per-status counts.`,
119237
119678
  }
119238
119679
 
119239
119680
  // src/core/agents/offSecAgent/tools/persistentShell.ts
119240
- import { spawn as spawn4, spawnSync } from "child_process";
119241
- import { randomBytes } from "crypto";
119681
+ import { spawn as spawn4, spawnSync } from "node:child_process";
119682
+ import { randomBytes } from "node:crypto";
119242
119683
  import {
119243
119684
  closeSync,
119244
119685
  mkdirSync as mkdirSync10,
119245
119686
  openSync,
119246
- readFileSync as readFileSync2,
119687
+ readFileSync as readFileSync3,
119247
119688
  readSync,
119248
- statSync as statSync2,
119689
+ statSync as statSync3,
119249
119690
  unlinkSync as unlinkSync2
119250
- } from "fs";
119251
- import { tmpdir } from "os";
119252
- import { join as join16 } from "path";
119691
+ } from "node:fs";
119692
+ import { tmpdir } from "node:os";
119693
+ import { join as join18 } from "node:path";
119253
119694
  var MAX_BUFFER = 5000000;
119254
- var APEX_TMP_ROOT = join16(tmpdir(), `apex-shell-${process.pid}`);
119695
+ var APEX_TMP_ROOT = join18(tmpdir(), `apex-shell-${process.pid}`);
119255
119696
  try {
119256
119697
  mkdirSync10(APEX_TMP_ROOT, { recursive: true });
119257
119698
  } catch {}
119258
119699
  function readTempfileCapped(path) {
119259
119700
  try {
119260
- const stat2 = statSync2(path);
119701
+ const stat2 = statSync3(path);
119261
119702
  if (stat2.size === 0)
119262
119703
  return "";
119263
119704
  if (stat2.size <= MAX_BUFFER) {
119264
- return readFileSync2(path, "utf-8");
119705
+ return readFileSync3(path, "utf-8");
119265
119706
  }
119266
119707
  const fd = openSync(path, "r");
119267
119708
  try {
119268
119709
  const buf = Buffer.alloc(MAX_BUFFER);
119269
119710
  readSync(fd, buf, 0, MAX_BUFFER, stat2.size - MAX_BUFFER);
119270
119711
  return `(stdout truncated)...
119271
- ` + buf.toString("utf-8");
119712
+ ${buf.toString("utf-8")}`;
119272
119713
  } finally {
119273
119714
  closeSync(fd);
119274
119715
  }
@@ -119426,16 +119867,16 @@ class PersistentShell {
119426
119867
  let commandOutput = cmd.authoritativeStdout.substring(0, markerIdx);
119427
119868
  if (cmd.stdoutTruncated) {
119428
119869
  commandOutput = `(stdout truncated)...
119429
- ` + commandOutput;
119870
+ ${commandOutput}`;
119430
119871
  }
119431
- const effectiveExit = cmd.forcedExitCode != null ? cmd.forcedExitCode : isNaN(naturalExitCode) ? 1 : naturalExitCode;
119872
+ const effectiveExit = cmd.forcedExitCode != null ? cmd.forcedExitCode : Number.isNaN(naturalExitCode) ? 1 : naturalExitCode;
119432
119873
  const effectiveStderr = cmd.forcedStderrSuffix ? (cmd.stderr || "") + cmd.forcedStderrSuffix : cmd.stderr || "";
119433
119874
  unlinkSafe(cmd.outPath);
119434
119875
  unlinkSafe(cmd.errPath);
119435
- const resolve3 = cmd.resolve;
119876
+ const resolve4 = cmd.resolve;
119436
119877
  this.current = null;
119437
119878
  this.pendingCancel = null;
119438
- resolve3({
119879
+ resolve4({
119439
119880
  stdout: commandOutput || "(no output)",
119440
119881
  stderr: effectiveStderr,
119441
119882
  exitCode: effectiveExit
@@ -119471,7 +119912,7 @@ class PersistentShell {
119471
119912
  }
119472
119913
  cmd.stderr += chunk;
119473
119914
  if (cmd.stderr.length > MAX_BUFFER) {
119474
- cmd.stderr = cmd.stderr.substring(0, MAX_BUFFER) + `...
119915
+ cmd.stderr = `${cmd.stderr.substring(0, MAX_BUFFER)}...
119475
119916
  (stderr truncated)`;
119476
119917
  }
119477
119918
  }
@@ -119492,10 +119933,10 @@ class PersistentShell {
119492
119933
  }
119493
119934
  this.ensureAlive();
119494
119935
  const proc = this.proc;
119495
- if (!proc || !proc.stdin || !proc.stdout || !proc.stderr) {
119936
+ if (!proc?.stdin || !proc.stdout || !proc.stderr) {
119496
119937
  return { stdout: "", stderr: "Failed to spawn shell", exitCode: 1 };
119497
119938
  }
119498
- return await new Promise((resolve3) => {
119939
+ return await new Promise((resolve4) => {
119499
119940
  let resolved = false;
119500
119941
  let timeoutTimer;
119501
119942
  let abortCleanup;
@@ -119503,8 +119944,8 @@ class PersistentShell {
119503
119944
  const marker = `__APEX_${nonceHex}__`;
119504
119945
  const exitMarkerPrefix = `${marker}_EXIT_`;
119505
119946
  const cutoverMarker = `${marker}_CUTOVER`;
119506
- const outPath = join16(APEX_TMP_ROOT, `${nonceHex}.out`);
119507
- const errPath = join16(APEX_TMP_ROOT, `${nonceHex}.err`);
119947
+ const outPath = join18(APEX_TMP_ROOT, `${nonceHex}.out`);
119948
+ const errPath = join18(APEX_TMP_ROOT, `${nonceHex}.err`);
119508
119949
  const pending = {
119509
119950
  streamedStdout: "",
119510
119951
  authoritativeStdout: "",
@@ -119531,7 +119972,7 @@ class PersistentShell {
119531
119972
  pending._activeSalvageId = undefined;
119532
119973
  if (abortCleanup)
119533
119974
  abortCleanup();
119534
- resolve3(result);
119975
+ resolve4(result);
119535
119976
  }
119536
119977
  };
119537
119978
  this.current = pending;
@@ -119581,7 +120022,7 @@ class PersistentShell {
119581
120022
  ].join(`
119582
120023
  `);
119583
120024
  try {
119584
- proc.stdin.write(wrapped);
120025
+ proc.stdin?.write(wrapped);
119585
120026
  } catch {
119586
120027
  pending.resolve({
119587
120028
  stdout: "",
@@ -119922,8 +120363,8 @@ Returns discovered endpoints and recommended login approach.`,
119922
120363
  // src/core/agents/offSecAgent/tools/provideComparisonResults.ts
119923
120364
  init_dist();
119924
120365
  init_zod();
119925
- import { writeFileSync as writeFileSync13 } from "fs";
119926
- import { join as join17 } from "path";
120366
+ import { writeFileSync as writeFileSync13 } from "node:fs";
120367
+ import { join as join19 } from "node:path";
119927
120368
  function provideComparisonResults(ctx) {
119928
120369
  return tool({
119929
120370
  description: `Provide the final comparison results with matched, missed, and extra findings.
@@ -119969,7 +120410,7 @@ Results will be saved to: comparison-results.json in the session directory.`,
119969
120410
  recall,
119970
120411
  precision
119971
120412
  };
119972
- const resultsPath = join17(ctx.session.rootPath, "comparison-results.json");
120413
+ const resultsPath = join19(ctx.session.rootPath, "comparison-results.json");
119973
120414
  writeFileSync13(resultsPath, JSON.stringify(result, null, 2));
119974
120415
  return {
119975
120416
  success: true,
@@ -119983,8 +120424,8 @@ Results will be saved to: comparison-results.json in the session directory.`,
119983
120424
  // src/core/agents/offSecAgent/tools/readFile.ts
119984
120425
  init_dist();
119985
120426
  init_zod();
119986
- import { readFile as fsReadFile } from "fs/promises";
119987
- import { isAbsolute as isAbsolute3, resolve as resolve3 } from "path";
120427
+ import { readFile as fsReadFile } from "node:fs/promises";
120428
+ import { isAbsolute as isAbsolute4, resolve as resolve4 } from "node:path";
119988
120429
  var readFileInputSchema = exports_external.object({
119989
120430
  path: exports_external.string().describe("Absolute or relative path to the file to read. Must be a file, not a directory."),
119990
120431
  startLine: exports_external.number().optional().describe("1-based line number to start reading from (inclusive)"),
@@ -120002,7 +120443,7 @@ the end. If only endLine is given, reads from the beginning to that line.
120002
120443
  Output lines are prefixed with their line number for easy reference.`,
120003
120444
  inputSchema: readFileInputSchema,
120004
120445
  execute: async ({ path, startLine, endLine }) => {
120005
- const resolved = isAbsolute3(path) ? path : resolve3(ctx.agentCwd, path);
120446
+ const resolved = isAbsolute4(path) ? path : resolve4(ctx.agentCwd, path);
120006
120447
  try {
120007
120448
  const raw = await fsReadFile(resolved, "utf-8");
120008
120449
  const allLines = raw.split(`
@@ -120123,7 +120564,7 @@ should be passed directly to spawn_pentest_swarm for deep testing.`,
120123
120564
  });
120124
120565
  if (cwd) {
120125
120566
  try {
120126
- const { WhiteboxAttackSurfaceAgent } = await import("./index-3cbcjqw1.js");
120567
+ const { WhiteboxAttackSurfaceAgent } = await import("./index-speg9ebc.js");
120127
120568
  const localBus = new AgentEventBus;
120128
120569
  AgentEventBus.attachChild(localBus, ctx.eventBus, subagentId);
120129
120570
  const agent = new WhiteboxAttackSurfaceAgent({
@@ -120173,7 +120614,7 @@ should be passed directly to spawn_pentest_swarm for deep testing.`,
120173
120614
  }
120174
120615
  }
120175
120616
  try {
120176
- const { BlackboxAttackSurfaceAgent } = await import("./blackboxAgent-sgph70e4.js");
120617
+ const { BlackboxAttackSurfaceAgent } = await import("./blackboxAgent-80y8j499.js");
120177
120618
  const localBus = new AgentEventBus;
120178
120619
  AgentEventBus.attachChild(localBus, ctx.eventBus, subagentId);
120179
120620
  const agent = new BlackboxAttackSurfaceAgent({
@@ -120251,7 +120692,7 @@ Omit \`cwd\` for blackbox mode (live target probing only).`,
120251
120692
  toolCallDescription: exports_external.string().describe("A concise, human-readable description of what this tool call is doing")
120252
120693
  }),
120253
120694
  execute: async ({ target, cwd }) => {
120254
- const { runPentestWorkflow: workflow } = await import("./pentest-2vsjf0j8.js");
120695
+ const { runPentestWorkflow: workflow } = await import("./pentest-4v06edvf.js");
120255
120696
  if (!ctx.model) {
120256
120697
  return {
120257
120698
  success: false,
@@ -120317,9 +120758,9 @@ async function runWithBoundedConcurrency(items, concurrency, fn, abortSignal) {
120317
120758
  const parentContext = import_api.context.active();
120318
120759
  let nextIdx = 0;
120319
120760
  let completed = 0;
120320
- await new Promise((resolve4) => {
120761
+ await new Promise((resolve5) => {
120321
120762
  if (items.length === 0) {
120322
- resolve4();
120763
+ resolve5();
120323
120764
  return;
120324
120765
  }
120325
120766
  let active = 0;
@@ -120328,7 +120769,7 @@ async function runWithBoundedConcurrency(items, concurrency, fn, abortSignal) {
120328
120769
  }
120329
120770
  function next() {
120330
120771
  if (completed >= nextIdx && !canLaunchMore()) {
120331
- resolve4();
120772
+ resolve5();
120332
120773
  return;
120333
120774
  }
120334
120775
  while (canLaunchMore()) {
@@ -120356,29 +120797,29 @@ init_zod();
120356
120797
 
120357
120798
  // src/core/whitebox/adapters.ts
120358
120799
  import { existsSync as existsSync12 } from "node:fs";
120359
- import { join as join19 } from "node:path";
120800
+ import { join as join21 } from "node:path";
120360
120801
 
120361
120802
  // src/core/whitebox/artifacts.ts
120362
120803
  import { mkdir as mkdir2, readFile as readFile3, writeFile as writeFile2 } from "node:fs/promises";
120363
- import { basename as basename2, join as join18 } from "node:path";
120804
+ import { basename as basename2, join as join20 } from "node:path";
120364
120805
 
120365
120806
  // src/core/whitebox/paths.ts
120366
120807
  import { existsSync as existsSync11, realpathSync } from "node:fs";
120367
- import { isAbsolute as isAbsolute4, normalize, relative as relative2, resolve as resolve4 } from "node:path";
120808
+ import { isAbsolute as isAbsolute5, normalize, relative as relative3, resolve as resolve5 } from "node:path";
120368
120809
  function resolveWhiteboxCodebaseRoot(input) {
120369
- return resolve4(normalize(input.codebasePath ?? input.agentCwd));
120810
+ return resolve5(normalize(input.codebasePath ?? input.agentCwd));
120370
120811
  }
120371
120812
  function isUnderRoot(root, candidate) {
120372
- const rel = relative2(root, candidate);
120813
+ const rel = relative3(root, candidate);
120373
120814
  if (rel === "")
120374
120815
  return true;
120375
- if (rel.startsWith("..") || isAbsolute4(rel))
120816
+ if (rel.startsWith("..") || isAbsolute5(rel))
120376
120817
  return false;
120377
120818
  return true;
120378
120819
  }
120379
120820
  function resolvePathWithinCodebaseRoot(root, subPath = ".") {
120380
- const absRoot = resolve4(normalize(root));
120381
- const candidate = isAbsolute4(subPath) ? resolve4(normalize(subPath)) : resolve4(absRoot, normalize(subPath));
120821
+ const absRoot = resolve5(normalize(root));
120822
+ const candidate = isAbsolute5(subPath) ? resolve5(normalize(subPath)) : resolve5(absRoot, normalize(subPath));
120382
120823
  if (!isUnderRoot(absRoot, candidate)) {
120383
120824
  throw new Error(`Path escapes codebase root: ${subPath}`);
120384
120825
  }
@@ -120401,8 +120842,8 @@ function resolveSessionWhiteboxArtifactPath(input) {
120401
120842
  if (!allowed) {
120402
120843
  throw new Error(`Artifact path must start with logs/whitebox/ or scratchpad/whitebox/: ${input.artifactRelativePath}`);
120403
120844
  }
120404
- const resolved = resolve4(input.sessionRootPath, posixPath);
120405
- if (!isUnderRoot(resolve4(input.sessionRootPath), resolved)) {
120845
+ const resolved = resolve5(input.sessionRootPath, posixPath);
120846
+ if (!isUnderRoot(resolve5(input.sessionRootPath), resolved)) {
120406
120847
  throw new Error("Invalid artifact path");
120407
120848
  }
120408
120849
  if (existsSync11(resolved)) {
@@ -120421,10 +120862,10 @@ function safeName(value) {
120421
120862
  return value.toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/\.{2,}/g, ".").replace(/^-+|-+$/g, "").slice(0, 80);
120422
120863
  }
120423
120864
  function getWhiteboxLogsDir(session) {
120424
- return join18(session.logsPath, "whitebox");
120865
+ return join20(session.logsPath, "whitebox");
120425
120866
  }
120426
120867
  function getWhiteboxScratchDir(session) {
120427
- return join18(session.scratchpadPath, "whitebox");
120868
+ return join20(session.scratchpadPath, "whitebox");
120428
120869
  }
120429
120870
  async function ensureWhiteboxDirs(session) {
120430
120871
  await Promise.all([
@@ -120437,7 +120878,7 @@ async function writeWhiteboxArtifact(input) {
120437
120878
  const baseDir = input.area === "scratchpad" ? getWhiteboxScratchDir(input.session) : getWhiteboxLogsDir(input.session);
120438
120879
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
120439
120880
  const filename = `${timestamp}-${safeName(input.name)}${input.extension ?? ".txt"}`;
120440
- const absolutePath = join18(baseDir, filename);
120881
+ const absolutePath = join20(baseDir, filename);
120441
120882
  await writeFile2(absolutePath, input.content, "utf-8");
120442
120883
  const relativeRoot = input.area === "scratchpad" ? "scratchpad/whitebox" : "logs/whitebox";
120443
120884
  return {
@@ -120490,7 +120931,7 @@ async function runSpawnBounded(input) {
120490
120931
  };
120491
120932
  }
120492
120933
  const detached = input.detached === true && process.platform !== "win32";
120493
- return new Promise((resolve5) => {
120934
+ return new Promise((resolve6) => {
120494
120935
  const child = spawn5(program, input.command.slice(1), {
120495
120936
  cwd: input.cwd,
120496
120937
  stdio: ["ignore", "pipe", "pipe"],
@@ -120512,7 +120953,7 @@ async function runSpawnBounded(input) {
120512
120953
  clearTimeout(timeoutTimer);
120513
120954
  if (escalateTimer)
120514
120955
  clearTimeout(escalateTimer);
120515
- resolve5(result);
120956
+ resolve6(result);
120516
120957
  };
120517
120958
  const append = (target, data) => {
120518
120959
  if (totalBytes >= input.maxTotalBytes) {
@@ -120679,7 +121120,7 @@ var WHITEBOX_SCAN_ADAPTERS = [
120679
121120
  id: "npm-audit",
120680
121121
  kind: "dependencies",
120681
121122
  tool: "npm",
120682
- detect: (profile) => hasTool(profile, "npm") && (profile.packageManagers.includes("npm") || existsSync12(join19(profile.rootPath, "package-lock.json"))),
121123
+ detect: (profile) => hasTool(profile, "npm") && (profile.packageManagers.includes("npm") || existsSync12(join21(profile.rootPath, "package-lock.json"))),
120683
121124
  buildCommand: () => ["npm", "audit", "--json"],
120684
121125
  parseSummary: (raw) => simpleLineFindings("npm audit", raw)
120685
121126
  },
@@ -120788,15 +121229,15 @@ ${raw.stderr}` : "");
120788
121229
  // src/core/whitebox/candidates.ts
120789
121230
  import { existsSync as existsSync13 } from "node:fs";
120790
121231
  import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile3 } from "node:fs/promises";
120791
- import { join as join20 } from "node:path";
121232
+ import { join as join22 } from "node:path";
120792
121233
  var CANDIDATES_FILE = "candidates.json";
120793
121234
  var writeLocks = new Map;
120794
121235
  function withCandidateLock(session, fn) {
120795
121236
  const key = session.scratchpadPath;
120796
121237
  const prev = writeLocks.get(key) ?? Promise.resolve();
120797
121238
  let release;
120798
- const gate = new Promise((resolve5) => {
120799
- release = resolve5;
121239
+ const gate = new Promise((resolve6) => {
121240
+ release = resolve6;
120800
121241
  });
120801
121242
  writeLocks.set(key, gate);
120802
121243
  return prev.then(fn).finally(() => {
@@ -120815,10 +121256,10 @@ var ALLOWED_TRANSITIONS = {
120815
121256
  deferred: ["hypothesis", "investigating"]
120816
121257
  };
120817
121258
  function candidatesDir(session) {
120818
- return join20(session.scratchpadPath, "whitebox");
121259
+ return join22(session.scratchpadPath, "whitebox");
120819
121260
  }
120820
121261
  function candidatesPath(session) {
120821
- return join20(candidatesDir(session), CANDIDATES_FILE);
121262
+ return join22(candidatesDir(session), CANDIDATES_FILE);
120822
121263
  }
120823
121264
  function makeId2(title) {
120824
121265
  const slug = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 48);
@@ -121284,11 +121725,11 @@ import {
121284
121725
  existsSync as existsSync14,
121285
121726
  mkdirSync as mkdirSync11,
121286
121727
  openSync as openSync2,
121287
- readFileSync as readFileSync3,
121728
+ readFileSync as readFileSync4,
121288
121729
  readSync as readSync2,
121289
- statSync as statSync3
121730
+ statSync as statSync4
121290
121731
  } from "node:fs";
121291
- import { join as join21 } from "node:path";
121732
+ import { join as join23 } from "node:path";
121292
121733
  var MAX_JOB_LOG_INLINE = 40000;
121293
121734
  var MAX_JOB_LOG_BYTES = 10 * 1024 * 1024;
121294
121735
  var PRUNE_AFTER_MS = 60000;
@@ -121363,7 +121804,7 @@ function startWhiteboxJob(input) {
121363
121804
  const logsDir = getWhiteboxLogsDir(input.session);
121364
121805
  mkdirSync11(logsDir, { recursive: true });
121365
121806
  const safeName2 = (input.name ?? "job").replace(/[^a-z0-9._-]+/gi, "-").replace(/\.{2,}/g, ".");
121366
- const logPath = join21(logsDir, `${id}-${safeName2}.log`);
121807
+ const logPath = join23(logsDir, `${id}-${safeName2}.log`);
121367
121808
  const now = new Date().toISOString();
121368
121809
  writeLog(logPath, `$ ${input.command}
121369
121810
 
@@ -121467,9 +121908,9 @@ function readWhiteboxJobLog(id, sessionId) {
121467
121908
  if (!record3 || !existsSync14(record3.logPath)) {
121468
121909
  return { content: "", truncated: false, record: record3 };
121469
121910
  }
121470
- const fileSize = statSync3(record3.logPath).size;
121911
+ const fileSize = statSync4(record3.logPath).size;
121471
121912
  if (fileSize <= MAX_JOB_LOG_INLINE) {
121472
- const raw = readFileSync3(record3.logPath, "utf-8");
121913
+ const raw = readFileSync4(record3.logPath, "utf-8");
121473
121914
  return { content: raw, truncated: false, record: record3 };
121474
121915
  }
121475
121916
  const readBytes = Math.min(fileSize, MAX_JOB_LOG_INLINE);
@@ -121489,12 +121930,12 @@ function readWhiteboxJobLog(id, sessionId) {
121489
121930
  };
121490
121931
  }
121491
121932
  // src/core/whitebox/repoProfile.ts
121492
- import { execFile } from "node:child_process";
121933
+ import { execFile as execFile2 } from "node:child_process";
121493
121934
  import { existsSync as existsSync15, realpathSync as realpathSync2 } from "node:fs";
121494
121935
  import { readdir as readdir2, readFile as readFile5, stat as stat2 } from "node:fs/promises";
121495
- import { basename as basename3, extname as extname2, join as join22, relative as relative3, resolve as resolve5 } from "node:path";
121496
- import { promisify } from "node:util";
121497
- var execFileAsync = promisify(execFile);
121936
+ import { basename as basename3, extname as extname2, join as join24, relative as relative4, resolve as resolve6 } from "node:path";
121937
+ import { promisify as promisify2 } from "node:util";
121938
+ var execFileAsync2 = promisify2(execFile2);
121498
121939
  var MAX_PROFILE_FILES = 5000;
121499
121940
  var LANGUAGE_BY_EXTENSION = {
121500
121941
  ".ts": "typescript",
@@ -121580,7 +122021,7 @@ function shouldSkipDir(name) {
121580
122021
  }
121581
122022
  async function walkFiles(rootPath) {
121582
122023
  const files = [];
121583
- const absRoot = resolve5(rootPath);
122024
+ const absRoot = resolve6(rootPath);
121584
122025
  function isWithinRoot(path) {
121585
122026
  try {
121586
122027
  const real = realpathSync2(path);
@@ -121601,7 +122042,7 @@ async function walkFiles(rootPath) {
121601
122042
  for (const entry of entries) {
121602
122043
  if (files.length >= MAX_PROFILE_FILES)
121603
122044
  return;
121604
- const fullPath = join22(current, entry.name);
122045
+ const fullPath = join24(current, entry.name);
121605
122046
  if (entry.isDirectory()) {
121606
122047
  if (shouldSkipDir(entry.name))
121607
122048
  continue;
@@ -121611,7 +122052,7 @@ async function walkFiles(rootPath) {
121611
122052
  continue;
121612
122053
  }
121613
122054
  if (entry.isFile()) {
121614
- files.push(relative3(rootPath, fullPath));
122055
+ files.push(relative4(rootPath, fullPath));
121615
122056
  }
121616
122057
  }
121617
122058
  }
@@ -121663,7 +122104,7 @@ function detectEntryHints(files) {
121663
122104
  return hints.slice(0, 100);
121664
122105
  }
121665
122106
  async function readPackageScripts(rootPath) {
121666
- const packageJsonPath = join22(rootPath, "package.json");
122107
+ const packageJsonPath = join24(rootPath, "package.json");
121667
122108
  if (!existsSync15(packageJsonPath)) {
121668
122109
  return { buildCommands: [], testCommands: [], runCommands: [] };
121669
122110
  }
@@ -121682,7 +122123,7 @@ async function readPackageScripts(rootPath) {
121682
122123
  }
121683
122124
  async function runGit(rootPath, args) {
121684
122125
  try {
121685
- const { stdout } = await execFileAsync("git", args, {
122126
+ const { stdout } = await execFileAsync2("git", args, {
121686
122127
  cwd: rootPath,
121687
122128
  timeout: 5000,
121688
122129
  maxBuffer: 1024 * 1024
@@ -121695,7 +122136,7 @@ async function runGit(rootPath, args) {
121695
122136
  async function detectTool(name) {
121696
122137
  const cmd = process.platform === "win32" ? "where" : "which";
121697
122138
  try {
121698
- const { stdout } = await execFileAsync(cmd, [name], {
122139
+ const { stdout } = await execFileAsync2(cmd, [name], {
121699
122140
  timeout: 2000,
121700
122141
  maxBuffer: 1024 * 64
121701
122142
  });
@@ -121827,7 +122268,7 @@ Returns an array of results with the text output from each agent.`,
121827
122268
  });
121828
122269
  }
121829
122270
  async function runSingleCodingAgent(ctx, codebasePath, objective, agentIndex, name) {
121830
- const { CodeAgent } = await import("./agent-4g69jwmq.js");
122271
+ const { CodeAgent } = await import("./agent-m3bsrs09.js");
121831
122272
  const subagentId = `coding-agent-${agentIndex}`;
121832
122273
  ctx.eventBus?.emit("subagent-spawn", {
121833
122274
  subagentId,
@@ -121876,8 +122317,8 @@ init_zod();
121876
122317
  init_ai();
121877
122318
  init_structured();
121878
122319
  init_lazyLogger();
121879
- import { existsSync as existsSync16, readdirSync as readdirSync3, readFileSync as readFileSync4 } from "fs";
121880
- import { join as join23 } from "path";
122320
+ import { existsSync as existsSync16, readdirSync as readdirSync3, readFileSync as readFileSync5 } from "node:fs";
122321
+ import { join as join25 } from "node:path";
121881
122322
  var log9 = scopedLogger(() => createLogger("findings:registry"));
121882
122323
  var VULN_CLASS_PATTERNS = [
121883
122324
  [/sql\s*injection/i, "sql-injection"],
@@ -122000,6 +122441,15 @@ ${existingList}
122000
122441
 
122001
122442
  Is the new finding a duplicate of any existing finding?`;
122002
122443
  }
122444
+ var SEVERITY_RANK = {
122445
+ CRITICAL: 4,
122446
+ HIGH: 3,
122447
+ MEDIUM: 2,
122448
+ LOW: 1
122449
+ };
122450
+ function maxSeverity(severities) {
122451
+ return severities.reduce((acc, s) => SEVERITY_RANK[s] > SEVERITY_RANK[acc] ? s : acc, "LOW");
122452
+ }
122003
122453
  var RootCauseGroupResultSchema = exports_external.object({
122004
122454
  groups: exports_external.array(exports_external.object({
122005
122455
  groupId: exports_external.string().describe("Short kebab-case identifier for the group"),
@@ -122060,7 +122510,7 @@ class FindingsRegistry {
122060
122510
  log9.debug(`fromDirectory: path=${findingsPath}, jsonFiles=${files.length}`);
122061
122511
  for (const file of files) {
122062
122512
  try {
122063
- const raw = readFileSync4(join23(findingsPath, file), "utf-8");
122513
+ const raw = readFileSync5(join25(findingsPath, file), "utf-8");
122064
122514
  const finding = JSON.parse(raw);
122065
122515
  if (finding && typeof finding.title === "string" && typeof finding.endpoint === "string") {
122066
122516
  registry.indexFinding(finding);
@@ -122104,19 +122554,19 @@ class FindingsRegistry {
122104
122554
  }
122105
122555
  async register(finding) {
122106
122556
  log9.debug(`register: checking "${finding.title}" endpoint="${finding.endpoint}"`);
122107
- const fastResult = await new Promise((resolve6) => {
122557
+ const fastResult = await new Promise((resolve7) => {
122108
122558
  this.mutex = this.mutex.then(() => {
122109
122559
  const check = this.isDuplicate(finding);
122110
122560
  if (check.duplicate) {
122111
122561
  log9.debug(`register: DUPLICATE (${check.matchType}) "${finding.title}" matched="${check.matchedFinding?.title}"`);
122112
- resolve6(check);
122562
+ resolve7(check);
122113
122563
  } else if (!this.model || this.findings.length === 0) {
122114
122564
  this.indexFinding(finding);
122115
122565
  log9.debug(`register: UNIQUE (Tier 1+2, no LLM needed) "${finding.title}" — registry size=${this.size}`);
122116
- resolve6({ duplicate: false });
122566
+ resolve7({ duplicate: false });
122117
122567
  } else {
122118
122568
  log9.debug(`register: Tier 1+2 pass — proceeding to Tier 3 LLM check for "${finding.title}"`);
122119
- resolve6(null);
122569
+ resolve7(null);
122120
122570
  }
122121
122571
  });
122122
122572
  });
@@ -122133,16 +122583,16 @@ class FindingsRegistry {
122133
122583
  log9.debug(`register: DUPLICATE (semantic/Tier 3) "${finding.title}" matched="${semanticResult.matchedFinding?.title}"`);
122134
122584
  return semanticResult;
122135
122585
  }
122136
- return new Promise((resolve6) => {
122586
+ return new Promise((resolve7) => {
122137
122587
  this.mutex = this.mutex.then(() => {
122138
122588
  const recheck = this.isDuplicate(finding);
122139
122589
  if (recheck.duplicate) {
122140
122590
  log9.debug(`register: DUPLICATE (race re-check, ${recheck.matchType}) "${finding.title}" matched="${recheck.matchedFinding?.title}"`);
122141
- resolve6(recheck);
122591
+ resolve7(recheck);
122142
122592
  } else {
122143
122593
  this.indexFinding(finding);
122144
122594
  log9.debug(`register: UNIQUE (all tiers passed) "${finding.title}" — registry size=${this.size}`);
122145
- resolve6({ duplicate: false });
122595
+ resolve7({ duplicate: false });
122146
122596
  }
122147
122597
  });
122148
122598
  });
@@ -122174,10 +122624,10 @@ class FindingsRegistry {
122174
122624
  return { duplicate: false };
122175
122625
  }
122176
122626
  async unregister(finding) {
122177
- return new Promise((resolve6) => {
122627
+ return new Promise((resolve7) => {
122178
122628
  this.mutex = this.mutex.then(() => {
122179
122629
  this.removeFinding(finding);
122180
- resolve6();
122630
+ resolve7();
122181
122631
  });
122182
122632
  });
122183
122633
  }
@@ -122202,24 +122652,38 @@ class FindingsRegistry {
122202
122652
  return [];
122203
122653
  }
122204
122654
  const sanitised = [];
122205
- await new Promise((resolve6) => {
122655
+ await new Promise((resolve7) => {
122206
122656
  this.mutex = this.mutex.then(() => {
122657
+ const baseSeverities = snapshot.map((f) => f.severity);
122207
122658
  for (const group of result.groups) {
122208
122659
  const validIndices = group.findingIndices.filter((i) => i >= 0 && i < snapshot.length);
122209
122660
  if (validIndices.length < 2)
122210
122661
  continue;
122662
+ const normalizedSeverity = maxSeverity(validIndices.map((i) => baseSeverities[i]));
122663
+ const leadFindingIndex = validIndices.reduce((best, i) => {
122664
+ const aRank = SEVERITY_RANK[baseSeverities[i]];
122665
+ const bRank = SEVERITY_RANK[baseSeverities[best]];
122666
+ if (aRank !== bRank) {
122667
+ return aRank > bRank ? i : best;
122668
+ }
122669
+ return (snapshot[i].description?.length ?? 0) > (snapshot[best].description?.length ?? 0) ? i : best;
122670
+ }, validIndices[0]);
122211
122671
  sanitised.push({
122212
122672
  groupId: group.groupId,
122213
122673
  findingIndices: validIndices,
122214
- rootCause: group.rootCause
122674
+ rootCause: group.rootCause,
122675
+ normalizedSeverity,
122676
+ leadFindingIndex
122215
122677
  });
122216
122678
  for (const idx of validIndices) {
122217
122679
  const finding = snapshot[idx];
122218
122680
  finding.rootCauseGroup = group.groupId;
122219
- finding.relatedFindings = validIndices.filter((i) => i !== idx).map((i) => snapshot[i].title);
122681
+ finding.severity = normalizedSeverity;
122682
+ finding.rootCauseLead = idx === leadFindingIndex;
122683
+ finding.relatedFindings = validIndices.filter((i) => i !== idx).map((i) => snapshot[i]?.title);
122220
122684
  }
122221
122685
  }
122222
- resolve6();
122686
+ resolve7();
122223
122687
  });
122224
122688
  });
122225
122689
  return sanitised;
@@ -122250,19 +122714,19 @@ class FindingsRegistry {
122250
122714
  }
122251
122715
 
122252
122716
  // src/core/plan/index.ts
122253
- import { existsSync as existsSync17, readFileSync as readFileSync5 } from "fs";
122254
- import { join as join24 } from "path";
122717
+ import { existsSync as existsSync17, readFileSync as readFileSync6 } from "node:fs";
122718
+ import { join as join26 } from "node:path";
122255
122719
  var PLAN_FILENAME = "plan.md";
122256
122720
  function planFilePath(sessionRootPath, subagentId) {
122257
122721
  if (subagentId) {
122258
- return join24(sessionRootPath, "subagents", `${subagentId}-plan.md`);
122722
+ return join26(sessionRootPath, "subagents", `${subagentId}-plan.md`);
122259
122723
  }
122260
- return join24(sessionRootPath, PLAN_FILENAME);
122724
+ return join26(sessionRootPath, PLAN_FILENAME);
122261
122725
  }
122262
122726
  function readPlan(sessionRootPath, subagentId) {
122263
122727
  const path = planFilePath(sessionRootPath, subagentId);
122264
122728
  try {
122265
- return readFileSync5(path, "utf-8");
122729
+ return readFileSync6(path, "utf-8");
122266
122730
  } catch {
122267
122731
  return null;
122268
122732
  }
@@ -122310,7 +122774,7 @@ Returns the worker's summary, objective results, and finding count — but NOT t
122310
122774
  message: "spawn_pentest_agent requires a model in the tool context."
122311
122775
  };
122312
122776
  }
122313
- const { TargetedPentestAgent } = await import("./agent-x7n47c84.js");
122777
+ const { TargetedPentestAgent } = await import("./agent-067x1n67.js");
122314
122778
  const findingsRegistry = ctx.findingsRegistry ?? FindingsRegistry.fromDirectory(ctx.session.findingsPath, {
122315
122779
  model: ctx.model,
122316
122780
  authConfig: ctx.authConfig,
@@ -122464,7 +122928,7 @@ Pass every target you want tested — the swarm handles concurrency automaticall
122464
122928
  toolCallDescription: exports_external.string().describe("A concise, human-readable description of what this tool call is doing")
122465
122929
  }),
122466
122930
  execute: async ({ targets }) => {
122467
- const { runPentestSwarm, DEFAULT_CONCURRENCY: DEFAULT_CONCURRENCY2 } = await import("./pentest-2vsjf0j8.js");
122931
+ const { runPentestSwarm, DEFAULT_CONCURRENCY: DEFAULT_CONCURRENCY2 } = await import("./pentest-4v06edvf.js");
122468
122932
  if (!ctx.model) {
122469
122933
  return {
122470
122934
  success: false,
@@ -122532,7 +122996,7 @@ Only call this when the plan is complete and ready for review.`,
122532
122996
  const planPath = planFilePath(ctx.session.rootPath, scopeId);
122533
122997
  log11.debug(`enter: path=${planPath}`);
122534
122998
  const plan = readPlan(ctx.session.rootPath, scopeId);
122535
- if (!plan || !plan.trim()) {
122999
+ if (!plan?.trim()) {
122536
123000
  return {
122537
123001
  success: false,
122538
123002
  error: "Plan file not found or empty. Write the plan first using write_plan.",
@@ -122630,8 +123094,8 @@ Use this to:
122630
123094
  // src/core/agents/offSecAgent/tools/updateFile.ts
122631
123095
  init_dist();
122632
123096
  init_zod();
122633
- import { readFile as readFile6, writeFile as writeFile4 } from "fs/promises";
122634
- import { isAbsolute as isAbsolute5, resolve as resolve6 } from "path";
123097
+ import { readFile as readFile6, writeFile as writeFile4 } from "node:fs/promises";
123098
+ import { isAbsolute as isAbsolute6, resolve as resolve7 } from "node:path";
122635
123099
  var updateFileInputSchema = exports_external.object({
122636
123100
  path: exports_external.string().describe("Absolute or relative path to the file to update"),
122637
123101
  oldContent: exports_external.string().describe("The exact string to find in the file. Must match character-for-character including whitespace and indentation."),
@@ -122659,7 +123123,7 @@ operation fails with an error — double-check whitespace and indentation.`,
122659
123123
  newContent,
122660
123124
  replaceAll = false
122661
123125
  }) => {
122662
- const resolved = isAbsolute5(filePath) ? filePath : resolve6(ctx.agentCwd, filePath);
123126
+ const resolved = isAbsolute6(filePath) ? filePath : resolve7(ctx.agentCwd, filePath);
122663
123127
  if (ctx.sandbox) {
122664
123128
  return executeSandboxUpdate(ctx, resolved, oldContent, newContent, replaceAll);
122665
123129
  }
@@ -123099,9 +123563,9 @@ async function handleSearchResponse(response) {
123099
123563
  init_dist();
123100
123564
  init_zod();
123101
123565
  init_structured();
123102
- import { mkdirSync as mkdirSync12 } from "fs";
123103
- import { writeFile as writeFile5 } from "fs/promises";
123104
- import { dirname as dirname4 } from "path";
123566
+ import { mkdirSync as mkdirSync12 } from "node:fs";
123567
+ import { writeFile as writeFile5 } from "node:fs/promises";
123568
+ import { dirname as dirname6 } from "node:path";
123105
123569
  init_lazyLogger();
123106
123570
  var log12 = scopedLogger(() => createLogger("write_plan"));
123107
123571
  var writePlanInputSchema = exports_external.object({
@@ -123127,7 +123591,7 @@ Required plan sections:
123127
123591
  execute: async ({ content }) => {
123128
123592
  const scopeId = ctx.planSubagentId ?? ctx.subagentId;
123129
123593
  const planPath = planFilePath(ctx.session.rootPath, scopeId);
123130
- mkdirSync12(dirname4(planPath), { recursive: true });
123594
+ mkdirSync12(dirname6(planPath), { recursive: true });
123131
123595
  log12.debug(`enter: contentLen=${content.length}, path=${planPath}`);
123132
123596
  try {
123133
123597
  await writeFile5(planPath, content, "utf-8");
@@ -123146,6 +123610,38 @@ Required plan sections:
123146
123610
  }
123147
123611
  });
123148
123612
  }
123613
+ // src/core/agents/offSecAgent/tools/listPromptInjections.ts
123614
+ init_dist();
123615
+ init_zod();
123616
+ function listPromptInjections(ctx) {
123617
+ return tool({
123618
+ description: "List available prompt-injection test payloads by safe metadata only. " + "The raw payload text is never returned. Use the returned id as a " + 'PromptInjectionRef: {"kind":"prompt_injection_ref","id":"<id>"} when a tool supports runtime injection references.',
123619
+ inputSchema: exports_external.object({
123620
+ category: exports_external.enum([
123621
+ "instruction-hijack",
123622
+ "data-exfiltration",
123623
+ "tool-misuse",
123624
+ "role-confusion",
123625
+ "encoding"
123626
+ ]).optional().describe("Optional category filter."),
123627
+ tag: exports_external.string().optional().describe("Optional tag filter."),
123628
+ toolCallDescription: exports_external.string().describe("A concise, human-readable description of why you are listing prompt-injection payloads.")
123629
+ }),
123630
+ execute: async ({ category, tag }) => {
123631
+ const library = await getPromptInjectionLibrary({
123632
+ library: ctx.promptInjectionLibrary,
123633
+ source: ctx.promptInjectionLibrarySource
123634
+ });
123635
+ const injections = library.listCatalog().filter((entry) => !category || entry.category === category).filter((entry) => !tag || entry.tags.includes(tag));
123636
+ return {
123637
+ success: true,
123638
+ configured: library.listCatalog().length > 0,
123639
+ count: injections.length,
123640
+ injections
123641
+ };
123642
+ }
123643
+ });
123644
+ }
123149
123645
  // src/core/agents/offSecAgent/tools/profileCodebase.ts
123150
123646
  init_dist();
123151
123647
  init_zod();
@@ -123321,7 +123817,7 @@ Use this instead of asking for the whole playbook. Examples:
123321
123817
  // src/core/agents/offSecAgent/tools/runCodeQuery.ts
123322
123818
  init_dist();
123323
123819
  init_zod();
123324
- import { relative as relative4 } from "node:path";
123820
+ import { relative as relative5 } from "node:path";
123325
123821
  var MAX_INLINE_MATCHES = 40;
123326
123822
  var MAX_QUERY_CAPTURE_BYTES = 2 * 1024 * 1024;
123327
123823
  var QueryEngineSchema = exports_external.enum(["rg", "grep", "ast-grep", "comby"]);
@@ -123392,7 +123888,7 @@ instead of flooding context with every match. Output size and runtime are bounde
123392
123888
  let targetPathForEngine = ".";
123393
123889
  try {
123394
123890
  const absTarget = resolvePathWithinCodebaseRoot(rootPath, query.path ?? ".");
123395
- targetPathForEngine = relative4(rootPath, absTarget) || ".";
123891
+ targetPathForEngine = relative5(rootPath, absTarget) || ".";
123396
123892
  } catch (error) {
123397
123893
  results.push({
123398
123894
  engine,
@@ -123757,10 +124253,10 @@ function listWhiteboxCandidates2(ctx) {
123757
124253
  // src/core/agents/offSecAgent/tools/whiteboxJobs.ts
123758
124254
  init_dist();
123759
124255
  init_zod();
123760
- import { isAbsolute as isAbsolute6, relative as relative5, sep } from "node:path";
124256
+ import { isAbsolute as isAbsolute7, relative as relative6, sep as sep2 } from "node:path";
123761
124257
  function displayPath(ctx, path) {
123762
- const prefix = ctx.session.rootPath.endsWith(sep) ? ctx.session.rootPath : `${ctx.session.rootPath}${sep}`;
123763
- return path === ctx.session.rootPath || path.startsWith(prefix) ? relative5(ctx.session.rootPath, path) : path;
124258
+ const prefix = ctx.session.rootPath.endsWith(sep2) ? ctx.session.rootPath : `${ctx.session.rootPath}${sep2}`;
124259
+ return path === ctx.session.rootPath || path.startsWith(prefix) ? relative6(ctx.session.rootPath, path) : path;
123764
124260
  }
123765
124261
  function startWhiteboxJob2(ctx) {
123766
124262
  return tool({
@@ -123895,9 +124391,9 @@ function stopWhiteboxJob2(ctx) {
123895
124391
  });
123896
124392
  }
123897
124393
  function normalizeArtifactRelativePath(ctx, userPath) {
123898
- if (isAbsolute6(userPath)) {
123899
- const rel = relative5(ctx.session.rootPath, userPath);
123900
- if (rel.startsWith("..") || rel === ".." || isAbsolute6(rel)) {
124394
+ if (isAbsolute7(userPath)) {
124395
+ const rel = relative6(ctx.session.rootPath, userPath);
124396
+ if (rel.startsWith("..") || rel === ".." || isAbsolute7(rel)) {
123901
124397
  throw new Error("Artifact path must be inside the session directory.");
123902
124398
  }
123903
124399
  return rel.replace(/\\/g, "/");
@@ -124030,6 +124526,7 @@ function createAllTools(ctx) {
124030
124526
  add_memory: addMemory2(ctx),
124031
124527
  list_memories: listMemories2(ctx),
124032
124528
  get_memory: getMemory2(ctx),
124529
+ list_prompt_injections: listPromptInjections(ctx),
124033
124530
  ...createEmailToolset(ctx),
124034
124531
  email_list_inboxes: emailListInboxes(ctx),
124035
124532
  email_list_messages: emailListMessages(ctx),
@@ -124092,6 +124589,7 @@ var ALL_TOOL_NAMES = [
124092
124589
  "add_memory",
124093
124590
  "list_memories",
124094
124591
  "get_memory",
124592
+ "list_prompt_injections",
124095
124593
  "email_list_inboxes",
124096
124594
  "email_list_messages",
124097
124595
  "email_get_message",
@@ -124138,6 +124636,7 @@ var PLAN_MODE_TOOL_NAMES = [
124138
124636
  "add_memory",
124139
124637
  "list_memories",
124140
124638
  "get_memory",
124639
+ "list_prompt_injections",
124141
124640
  "email_list_inboxes",
124142
124641
  "email_list_messages",
124143
124642
  "email_get_message",
@@ -124154,9 +124653,9 @@ var PLAN_MODE_TOOL_NAMES = [
124154
124653
  var SKILL_TOOL_NAMES = ["read_skill"];
124155
124654
 
124156
124655
  // src/core/agents/offSecAgent/trace.ts
124157
- import { createHash } from "crypto";
124158
- import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync13 } from "fs";
124159
- import { dirname as dirname5 } from "path";
124656
+ import { createHash as createHash2 } from "node:crypto";
124657
+ import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync13 } from "node:fs";
124658
+ import { dirname as dirname7 } from "node:path";
124160
124659
  var OUTPUT_PREVIEW_LIMIT = 2000;
124161
124660
  var INPUT_PREVIEW_LIMIT = 1000;
124162
124661
  var SYSTEM_PROMPT_HASH_PREFIX_LENGTH = 12;
@@ -124217,7 +124716,7 @@ class StepTraceWriter {
124217
124716
  const now = Date.now();
124218
124717
  this.agentStartTime = now;
124219
124718
  this.lastStepTime = now;
124220
- mkdirSync13(dirname5(this.tracePath), { recursive: true });
124719
+ mkdirSync13(dirname7(this.tracePath), { recursive: true });
124221
124720
  }
124222
124721
  writeInit(data) {
124223
124722
  const { systemPrompt, ...rest } = data;
@@ -124225,7 +124724,7 @@ class StepTraceWriter {
124225
124724
  type: "init",
124226
124725
  timestamp: new Date().toISOString(),
124227
124726
  agentId: this.agentId,
124228
- systemPromptHash: createHash("sha256").update(systemPrompt).digest("hex").slice(0, SYSTEM_PROMPT_HASH_PREFIX_LENGTH),
124727
+ systemPromptHash: createHash2("sha256").update(systemPrompt).digest("hex").slice(0, SYSTEM_PROMPT_HASH_PREFIX_LENGTH),
124229
124728
  systemPrompt,
124230
124729
  ...rest
124231
124730
  };
@@ -124341,7 +124840,7 @@ class StepTraceWriter {
124341
124840
  }
124342
124841
  appendRecord(record3) {
124343
124842
  try {
124344
- appendFileSync3(this.tracePath, JSON.stringify(record3) + `
124843
+ appendFileSync3(this.tracePath, `${JSON.stringify(record3)}
124345
124844
  `);
124346
124845
  } catch {}
124347
124846
  try {
@@ -124356,15 +124855,15 @@ class StepTraceWriter {
124356
124855
  // src/core/agents/offSecAgent/offensiveSecurityAgent.ts
124357
124856
  init_dist();
124358
124857
  init_ai();
124359
- import { existsSync as existsSync18, mkdirSync as mkdirSync14 } from "fs";
124360
- import { writeFile as writeFile6 } from "fs/promises";
124361
- import { join as join25 } from "path";
124858
+ import { existsSync as existsSync18, mkdirSync as mkdirSync14 } from "node:fs";
124859
+ import { writeFile as writeFile6 } from "node:fs/promises";
124860
+ import { join as join27 } from "node:path";
124362
124861
  init_structured();
124363
124862
  init_observability();
124364
124863
 
124365
124864
  // src/core/operator/approvalGate.ts
124366
- import { randomBytes as randomBytes2 } from "crypto";
124367
- import { EventEmitter as EventEmitter3 } from "events";
124865
+ import { randomBytes as randomBytes2 } from "node:crypto";
124866
+ import { EventEmitter as EventEmitter3 } from "node:events";
124368
124867
  var DEFAULT_DECISION_TIMEOUT_MS = 15 * 60 * 1000;
124369
124868
  var INTERNAL_ID_PATTERN = /^(apr|act|tc)_\d+_[0-9a-f]{8}$/;
124370
124869
 
@@ -124409,8 +124908,8 @@ class ApprovalGate extends EventEmitter3 {
124409
124908
  tier: 1,
124410
124909
  timestamp: Date.now()
124411
124910
  };
124412
- return new Promise((resolve7, reject) => {
124413
- const deferred = { approval, resolve: resolve7, reject };
124911
+ return new Promise((resolve8, reject) => {
124912
+ const deferred = { approval, resolve: resolve8, reject };
124414
124913
  this.pendingApprovals.set(approval.id, deferred);
124415
124914
  const timeoutMs = this.config.decisionTimeoutMs;
124416
124915
  if (timeoutMs !== undefined && timeoutMs > 0) {
@@ -124648,6 +125147,7 @@ class OffensiveSecurityAgent {
124648
125147
  subagentId;
124649
125148
  persistentShell;
124650
125149
  browserSession;
125150
+ ownsBrowserSession;
124651
125151
  abortSignal;
124652
125152
  userPrompt;
124653
125153
  _session;
@@ -124687,19 +125187,22 @@ class OffensiveSecurityAgent {
124687
125187
  }
124688
125188
  if (!input.sandbox) {
124689
125189
  const sessionHeaders = input.target ? resolveEffectiveHeaders(input.session, input.target) : input.session.config?.headers;
125190
+ this.ownsBrowserSession = !input.browserSession;
124690
125191
  this.browserSession = input.browserSession ?? new PlaywrightMcpSession({
124691
125192
  extraHttpHeaders: stripBrowserManagedHeaders(sessionHeaders)
124692
125193
  });
125194
+ } else {
125195
+ this.ownsBrowserSession = false;
124693
125196
  }
124694
- const messagesDir = input.messagesDir ?? (input.subagentId ? join25(input.session.rootPath, "subagents", input.subagentId) : input.session.rootPath);
124695
- const tracePath = input.subagentId ? join25(input.session.rootPath, "subagents", `${input.subagentId}.trace.jsonl`) : join25(messagesDir, "trace.jsonl");
125197
+ const messagesDir = input.messagesDir ?? (input.subagentId ? join27(input.session.rootPath, "subagents", input.subagentId) : input.session.rootPath);
125198
+ const tracePath = input.subagentId ? join27(input.session.rootPath, "subagents", `${input.subagentId}.trace.jsonl`) : join27(messagesDir, "trace.jsonl");
124696
125199
  const traceWriter = new StepTraceWriter({
124697
125200
  tracePath,
124698
125201
  agentId: input.subagentId ?? null,
124699
125202
  eventBus: this.eventBus
124700
125203
  });
124701
125204
  const taskDriven = input.session.config?.taskDriven ?? false;
124702
- const tasksDir = input.tasksDir ?? (taskDriven ? input.subagentId ? join25(input.session.rootPath, "subagents", `${input.subagentId}-tasks`) : join25(input.session.rootPath, "tasks") : undefined);
125205
+ const tasksDir = input.tasksDir ?? (taskDriven ? input.subagentId ? join27(input.session.rootPath, "subagents", `${input.subagentId}-tasks`) : join27(input.session.rootPath, "tasks") : undefined);
124703
125206
  const credentialManager = input.credentialManager ?? input.session.credentialManager;
124704
125207
  const builtinTools = createAllTools({
124705
125208
  session: input.session,
@@ -124715,6 +125218,8 @@ class OffensiveSecurityAgent {
124715
125218
  credentialManager,
124716
125219
  persistentShell: this.persistentShell,
124717
125220
  skillsRegistry: input.skillsRegistry,
125221
+ promptInjectionLibrary: input.promptInjectionLibrary,
125222
+ promptInjectionLibrarySource: input.promptInjectionLibrarySource ?? input.session.config?.promptInjectionLibrarySource,
124718
125223
  traceWriter,
124719
125224
  tasksDir,
124720
125225
  enableThinking: input.enableThinking,
@@ -124775,7 +125280,7 @@ class OffensiveSecurityAgent {
124775
125280
  if (!existsSync18(messagesDir)) {
124776
125281
  mkdirSync14(messagesDir, { recursive: true });
124777
125282
  }
124778
- const messagesPath = join25(messagesDir, "messages.json");
125283
+ const messagesPath = join27(messagesDir, "messages.json");
124779
125284
  const initialMessagesRef = {
124780
125285
  current: input.messages ? [...input.messages] : [
124781
125286
  {
@@ -124893,6 +125398,9 @@ class OffensiveSecurityAgent {
124893
125398
  }
124894
125399
  } finally {
124895
125400
  this.persistentShell?.dispose();
125401
+ if (this.ownsBrowserSession && this.browserSession) {
125402
+ await this.browserSession.disconnect().catch(() => {});
125403
+ }
124896
125404
  }
124897
125405
  if (this.abortSignal?.aborted) {
124898
125406
  throw new DOMException("Agent aborted by user", "AbortError");