@pensar/apex 2.1.3-canary.fff17bfd → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/agent-3cdfwxcd.js +19 -0
- package/build/agent-q5hwjdtb.js +27 -0
- package/build/{agent-c06jb5zv.js → agent-yayy5x2a.js} +10 -8
- package/build/{apps-mxhfapvz.js → apps-0es69e2s.js} +17 -16
- package/build/{auth-9ysskv2q.js → auth-q73k9bh9.js} +17 -16
- package/build/authentication-tqx2brcv.js +19 -0
- package/build/blackboxAgent-d0smgqt7.js +19 -0
- package/build/{blackboxPentest-pfs3d1nx.js → blackboxPentest-h28nykk5.js} +15 -14
- package/build/{cli-90dw3gm4.js → cli-1cf5vy5m.js} +9 -6
- package/build/{cli-f8tgnegf.js → cli-1f636vzd.js} +2 -2
- package/build/{cli-tg7mcs43.js → cli-1re2kv5v.js} +5 -3
- package/build/cli-2jn8104w.js +195 -0
- package/build/{cli-29yqhrjq.js → cli-3k1x5rn3.js} +1 -1
- package/build/{cli-k941a7ft.js → cli-4tc6888c.js} +1 -1
- package/build/{cli-qb3eddc7.js → cli-51dkmt5p.js} +1 -1
- package/build/{cli-v34r5t8t.js → cli-6kx46ck0.js} +6186 -513
- package/build/{cli-a1acedxf.js → cli-7e5ad5js.js} +15 -6
- package/build/{cli-8qb62k90.js → cli-7n43wz82.js} +1 -1
- package/build/{cli-fj04wady.js → cli-knqx15w6.js} +5 -2
- package/build/{cli-9wd7jy2s.js → cli-n114n8mk.js} +102 -21
- package/build/{cli-9h847y2w.js → cli-ptzy9ak5.js} +2 -2
- package/build/{cli-g6cjpbr9.js → cli-s43t5ay0.js} +1 -1
- package/build/{cli-nth9zebw.js → cli-tz9yg4ew.js} +1147 -336
- package/build/{cli-2cvp6x4p.js → cli-vgg6h2ax.js} +1 -1
- package/build/{cli-akhax3yn.js → cli-xbdn034b.js} +671 -105
- package/build/{cli-wkpsqyjc.js → cli-xpn9tsw0.js} +27 -5
- package/build/cli.js +48 -39
- package/build/{config-ky5za80x.js → config-xcf7rc6x.js} +3 -3
- package/build/{doctor-t94dqmcs.js → doctor-98zperf9.js} +7 -7
- package/build/fastStrike-9tm6bedh.js +156 -0
- package/build/{fixes-fv2zmk0m.js → fixes-1dry8j61.js} +17 -16
- package/build/{index-s2jr2ve2.js → index-0j880wqc.js} +70 -44
- package/build/{index-8mgv8hke.js → index-31rwrakh.js} +2 -2
- package/build/{index-b7zrdy9b.js → index-34h2nb6x.js} +3 -3
- package/build/{index-pmsx73c3.js → index-4hqbyzf5.js} +11 -9
- package/build/{index-qshyncep.js → index-6dbym5jy.js} +8 -7
- package/build/{index-pycryjc3.js → index-f6ttv7np.js} +4 -4
- package/build/{index-n1yh9e86.js → index-gq9h8j5j.js} +1 -1
- package/build/{index-rxskwf3k.js → index-pxwwcefn.js} +10 -10
- package/build/{issues-bwdnb233.js → issues-wjakj8yy.js} +28 -16
- package/build/{logs-2g3rsh9f.js → logs-ewyzcspy.js} +17 -16
- package/build/{offesecAgent-4ykghkvs.js → offesecAgent-7m9smy0t.js} +9 -9
- package/build/pentest-1cb5t0dt.js +29 -0
- package/build/{pentests-d9dt495f.js → pentests-1hcqjyk2.js} +17 -16
- package/build/targetedPentest-3x13kqvc.js +56 -0
- package/build/{targets-3n7wsm3g.js → targets-nqz8w37e.js} +17 -16
- package/build/threatModel-7f02av7y.js +27 -0
- package/build/{uninstall-jvjv6d2n.js → uninstall-p1q5pkx2.js} +1 -1
- package/build/{upload-x2b8s1xb.js → upload-x7etpfp4.js} +7 -7
- package/build/{utils-kx8jqmv0.js → utils-kw6yh5yn.js} +7 -7
- package/package.json +2 -2
- package/build/agent-7ab546zf.js +0 -19
- package/build/agent-dsqssedb.js +0 -25
- package/build/authentication-h1zxd74t.js +0 -19
- package/build/blackboxAgent-32zwxt6w.js +0 -19
- package/build/pentest-91bygv3h.js +0 -28
- package/build/targetedPentest-eavq5h7v.js +0 -43
- package/build/threatModel-2re9tykx.js +0 -26
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
detectOSAndEnhancePrompt
|
|
3
|
-
} from "./cli-
|
|
3
|
+
} from "./cli-s43t5ay0.js";
|
|
4
4
|
import {
|
|
5
5
|
parseTargetUrl
|
|
6
6
|
} from "./cli-c8131c4q.js";
|
|
@@ -30,15 +30,16 @@ import {
|
|
|
30
30
|
scopedLogger,
|
|
31
31
|
stepCountIs,
|
|
32
32
|
streamResponse,
|
|
33
|
+
withSubagentSessionBaggage,
|
|
33
34
|
write
|
|
34
|
-
} from "./cli-
|
|
35
|
+
} from "./cli-6kx46ck0.js";
|
|
35
36
|
import {
|
|
36
37
|
ensureValidToken,
|
|
37
38
|
getPensarApiUrl,
|
|
38
39
|
init_auth,
|
|
39
40
|
init_constants,
|
|
40
41
|
signGatewayRequest
|
|
41
|
-
} from "./cli-
|
|
42
|
+
} from "./cli-4tc6888c.js";
|
|
42
43
|
import {
|
|
43
44
|
_enum,
|
|
44
45
|
_null,
|
|
@@ -65,11 +66,11 @@ import {
|
|
|
65
66
|
tool,
|
|
66
67
|
union,
|
|
67
68
|
unknown
|
|
68
|
-
} from "./cli-
|
|
69
|
+
} from "./cli-3k1x5rn3.js";
|
|
69
70
|
import {
|
|
70
71
|
config,
|
|
71
72
|
init_config
|
|
72
|
-
} from "./cli-
|
|
73
|
+
} from "./cli-51dkmt5p.js";
|
|
73
74
|
import {
|
|
74
75
|
__commonJS,
|
|
75
76
|
__require,
|
|
@@ -99665,7 +99666,7 @@ class AgentEventBus {
|
|
|
99665
99666
|
}
|
|
99666
99667
|
emitStreamPart(chunk, ids) {
|
|
99667
99668
|
const ctx = typeof ids === "string" ? { subagentId: ids } : ids ?? {};
|
|
99668
|
-
const subagentId = ctx.subagentId
|
|
99669
|
+
const subagentId = ctx.subagentId;
|
|
99669
99670
|
const sessionId = ctx.sessionId;
|
|
99670
99671
|
const messageId = ctx.messageId;
|
|
99671
99672
|
switch (chunk.type) {
|
|
@@ -99909,11 +99910,11 @@ You can perform the full lifecycle of a penetration test and support a wide rang
|
|
|
99909
99910
|
You run inside Pensar Apex, and the \`pensar\` CLI is available on this machine. Invoke it through \`execute_command\` to perform Console/workspace operations your other tools don't cover — most importantly managing the **attack surface** and triaging results. These commands act on the workspace the user connected with \`pensar login\` and print JSON to stdout, so you can parse and chain them.
|
|
99910
99911
|
|
|
99911
99912
|
- **Attack surface (apps & endpoints)** — \`pensar apps\` (list), \`apps get <appId>\`, \`apps create\`, \`apps update <appId>\`, \`apps delete <appId>\`; endpoints via \`apps endpoints <appId>\`, \`apps endpoint <endpointId>\`, \`apps endpoint-create <appId>\`, \`apps endpoint-update <endpointId>\`, \`apps endpoint-delete <endpointId>\`; and \`apps search <query>\` / \`apps search-endpoints <query>\`.
|
|
99912
|
-
- **Issues & fixes** — \`pensar issues [--status --severity --scan --branch]\`, \`issues get <id>\`, \`issues update <id>\`; \`pensar fixes <issueId>\`, \`fixes get <fixId>\`.
|
|
99913
|
+
- **Issues & fixes** — \`pensar issues [--status --severity --scan --branch]\`, \`issues get <id>\`, \`issues update <id>\`, \`issues retest <id>\`; \`pensar fixes <issueId>\`, \`fixes get <fixId>\`.
|
|
99913
99914
|
- **Scans** — \`pensar pentests\`, \`pentests get <id>\`, \`pentests dispatch [--branch --level]\`.
|
|
99914
99915
|
- **Agent logs** — \`pensar logs <issueId>\`, \`logs search <issueId> <query>\`.
|
|
99915
99916
|
|
|
99916
|
-
Run \`pensar --help\` or \`pensar <command> --help\` for exact flags — the CLI is the source of truth. These commands require the user to be logged in; if one reports it is not authenticated, tell the user to run \`pensar login\` rather than attempting the device flow yourself. Confirm with the user before any mutating command (\`create\`/\`update\`/\`delete\`, \`endpoint-*\`, \`pentests dispatch\`, \`issues update\`). Do NOT launch nested engagements from here (\`pensar pentest\`, \`pensar targeted-pentest\`, \`pensar operator\`, or \`pensar -p\`) — use your own tools for testing.
|
|
99917
|
+
Run \`pensar --help\` or \`pensar <command> --help\` for exact flags — the CLI is the source of truth. These commands require the user to be logged in; if one reports it is not authenticated, tell the user to run \`pensar login\` rather than attempting the device flow yourself. Confirm with the user before any mutating command (\`create\`/\`update\`/\`delete\`, \`endpoint-*\`, \`pentests dispatch\`, \`issues update\`, \`issues retest\`). Do NOT launch nested engagements from here (\`pensar pentest\`, \`pensar targeted-pentest\`, \`pensar operator\`, or \`pensar -p\`) — use your own tools for testing.
|
|
99917
99918
|
|
|
99918
99919
|
# How to Work
|
|
99919
99920
|
|
|
@@ -102688,12 +102689,25 @@ var CAMOUFOX_OPTIONS = {
|
|
|
102688
102689
|
humanize: true,
|
|
102689
102690
|
block_webrtc: true
|
|
102690
102691
|
};
|
|
102692
|
+
var MEMORY_FIREFOX_PREFS = {
|
|
102693
|
+
"fission.autostart": false,
|
|
102694
|
+
"dom.ipc.processCount": 1,
|
|
102695
|
+
"dom.ipc.processPrelaunch.enabled": false,
|
|
102696
|
+
"browser.cache.disk.enable": false,
|
|
102697
|
+
"browser.cache.memory.enable": false,
|
|
102698
|
+
"browser.sessionhistory.max_total_viewers": 0
|
|
102699
|
+
};
|
|
102691
102700
|
async function resolveCamoufoxLaunchOptions(headless) {
|
|
102692
102701
|
const { launchOptions: camoufoxLaunchOptions } = await import("camoufox-js");
|
|
102693
|
-
|
|
102702
|
+
const opts = await camoufoxLaunchOptions({
|
|
102694
102703
|
...CAMOUFOX_OPTIONS,
|
|
102695
102704
|
headless
|
|
102696
102705
|
});
|
|
102706
|
+
opts.firefoxUserPrefs = {
|
|
102707
|
+
...opts.firefoxUserPrefs,
|
|
102708
|
+
...MEMORY_FIREFOX_PREFS
|
|
102709
|
+
};
|
|
102710
|
+
return opts;
|
|
102697
102711
|
}
|
|
102698
102712
|
var ensurePromise = null;
|
|
102699
102713
|
function ensureCamoufox(log) {
|
|
@@ -102805,6 +102819,16 @@ function withTimeout(promise2, ms, message) {
|
|
|
102805
102819
|
});
|
|
102806
102820
|
return Promise.race([promise2, timeout]).finally(() => clearTimeout(timer));
|
|
102807
102821
|
}
|
|
102822
|
+
function readProcStartTime(pid) {
|
|
102823
|
+
try {
|
|
102824
|
+
const stat = readFileSync(`/proc/${pid}/stat`, "utf8");
|
|
102825
|
+
const afterComm = stat.slice(stat.lastIndexOf(")") + 2).split(" ");
|
|
102826
|
+
const starttime = Number(afterComm[19]);
|
|
102827
|
+
return Number.isFinite(starttime) ? starttime : null;
|
|
102828
|
+
} catch {
|
|
102829
|
+
return null;
|
|
102830
|
+
}
|
|
102831
|
+
}
|
|
102808
102832
|
function collectDescendantPids(rootPid) {
|
|
102809
102833
|
let entries;
|
|
102810
102834
|
try {
|
|
@@ -102907,11 +102931,16 @@ class PlaywrightMcpSession {
|
|
|
102907
102931
|
forceKillProcess(proc = this.mcpProcess) {
|
|
102908
102932
|
if (!proc || proc.exitCode !== null)
|
|
102909
102933
|
return;
|
|
102910
|
-
const
|
|
102934
|
+
const rootPid = proc.pid ?? null;
|
|
102935
|
+
const descendants = rootPid != null ? collectDescendantPids(rootPid) : [];
|
|
102936
|
+
const descendantStarts = new Map;
|
|
102937
|
+
for (const pid of descendants) {
|
|
102938
|
+
descendantStarts.set(pid, readProcStartTime(pid));
|
|
102939
|
+
}
|
|
102911
102940
|
try {
|
|
102912
|
-
if (
|
|
102941
|
+
if (rootPid != null) {
|
|
102913
102942
|
try {
|
|
102914
|
-
process.kill(-
|
|
102943
|
+
process.kill(-rootPid, "SIGKILL");
|
|
102915
102944
|
} catch {
|
|
102916
102945
|
proc.kill("SIGKILL");
|
|
102917
102946
|
}
|
|
@@ -102920,6 +102949,12 @@ class PlaywrightMcpSession {
|
|
|
102920
102949
|
}
|
|
102921
102950
|
} catch {}
|
|
102922
102951
|
for (const pid of descendants) {
|
|
102952
|
+
const expected = descendantStarts.get(pid);
|
|
102953
|
+
if (expected != null) {
|
|
102954
|
+
const now = readProcStartTime(pid);
|
|
102955
|
+
if (now == null || now !== expected)
|
|
102956
|
+
continue;
|
|
102957
|
+
}
|
|
102923
102958
|
try {
|
|
102924
102959
|
process.kill(pid, "SIGKILL");
|
|
102925
102960
|
} catch {}
|
|
@@ -104892,6 +104927,10 @@ const fs = require('fs');
|
|
|
104892
104927
|
try {
|
|
104893
104928
|
context = await firefox.launchPersistentContext('/tmp/pw-user-data', {
|
|
104894
104929
|
...__camou,
|
|
104930
|
+
// Layer memory prefs over Camoufox's fingerprint prefs (ours win); see
|
|
104931
|
+
// MEMORY_FIREFOX_PREFS in ./camoufox — collapses Fission/content-process
|
|
104932
|
+
// fan-out that otherwise costs ~3 GB across the run.
|
|
104933
|
+
firefoxUserPrefs: { ...__camou.firefoxUserPrefs, ...${JSON.stringify(MEMORY_FIREFOX_PREFS)} },
|
|
104895
104934
|
...(__extraHeaders ? { extraHTTPHeaders: __extraHeaders } : {}),
|
|
104896
104935
|
});
|
|
104897
104936
|
const pages = context.pages();
|
|
@@ -105094,6 +105133,7 @@ Use this to document:
|
|
|
105094
105133
|
mkdirSync2(dir, { recursive: true });
|
|
105095
105134
|
}
|
|
105096
105135
|
writeFileSync2(localPath, Buffer.from(result.data, "base64"));
|
|
105136
|
+
sandbox.execute(`rm -f ${sandboxPath}`, { timeout: 10 }).catch(() => {});
|
|
105097
105137
|
return {
|
|
105098
105138
|
success: true,
|
|
105099
105139
|
path: localPath,
|
|
@@ -106412,6 +106452,7 @@ init_zod();
|
|
|
106412
106452
|
init_credentials();
|
|
106413
106453
|
import { writeFileSync as writeFileSync6 } from "node:fs";
|
|
106414
106454
|
import { join as join10 } from "node:path";
|
|
106455
|
+
init_id();
|
|
106415
106456
|
init_structured();
|
|
106416
106457
|
init_lazyLogger();
|
|
106417
106458
|
var log4 = scopedLogger(() => createLogger("delegate_auth"));
|
|
@@ -106498,6 +106539,8 @@ IMPORTANT: Pass protectedEndpoints in authHints when you've discovered 401/403 e
|
|
|
106498
106539
|
authHints,
|
|
106499
106540
|
reason
|
|
106500
106541
|
}) => {
|
|
106542
|
+
const subagentId = newSessionId();
|
|
106543
|
+
const subagentName = "Authentication Agent";
|
|
106501
106544
|
try {
|
|
106502
106545
|
if (!ctx.model) {
|
|
106503
106546
|
return {
|
|
@@ -106523,9 +106566,9 @@ IMPORTANT: Pass protectedEndpoints in authHints when you've discovered 401/403 e
|
|
|
106523
106566
|
tokens = { ...stored.tokens };
|
|
106524
106567
|
}
|
|
106525
106568
|
}
|
|
106526
|
-
const subagentId = "auth-agent";
|
|
106527
106569
|
ctx.eventBus?.emit("subagent-spawn", {
|
|
106528
106570
|
subagentId,
|
|
106571
|
+
name: subagentName,
|
|
106529
106572
|
input: { target, reason },
|
|
106530
106573
|
parentSubagentId: ctx.subagentId
|
|
106531
106574
|
});
|
|
@@ -106570,7 +106613,7 @@ IMPORTANT: Pass protectedEndpoints in authHints when you've discovered 401/403 e
|
|
|
106570
106613
|
if (credentials) {
|
|
106571
106614
|
ctx.session.credentialManager.addFromAuthCredentials(credentials);
|
|
106572
106615
|
}
|
|
106573
|
-
const { runAuthenticationAgent } = await import("./authentication-
|
|
106616
|
+
const { runAuthenticationAgent } = await import("./authentication-tqx2brcv.js");
|
|
106574
106617
|
const localBus = new AgentEventBus;
|
|
106575
106618
|
AgentEventBus.attachChild(localBus, ctx.eventBus, subagentId);
|
|
106576
106619
|
const result = await runAuthenticationAgent({
|
|
@@ -106581,7 +106624,9 @@ IMPORTANT: Pass protectedEndpoints in authHints when you've discovered 401/403 e
|
|
|
106581
106624
|
authConfig: ctx.authConfig,
|
|
106582
106625
|
abortSignal: ctx.abortSignal,
|
|
106583
106626
|
eventBus: localBus,
|
|
106584
|
-
subagentId
|
|
106627
|
+
subagentId,
|
|
106628
|
+
subagentName,
|
|
106629
|
+
secretValues: ctx.secretValues
|
|
106585
106630
|
});
|
|
106586
106631
|
ctx.eventBus?.emit("subagent-complete", {
|
|
106587
106632
|
subagentId,
|
|
@@ -106635,7 +106680,7 @@ Auth data saved to: ${result.authDataPath}` : ""}` : `Authentication subagent fa
|
|
|
106635
106680
|
};
|
|
106636
106681
|
} catch (error) {
|
|
106637
106682
|
ctx.eventBus?.emit("subagent-complete", {
|
|
106638
|
-
subagentId
|
|
106683
|
+
subagentId,
|
|
106639
106684
|
status: "failed",
|
|
106640
106685
|
parentSubagentId: ctx.subagentId
|
|
106641
106686
|
});
|
|
@@ -106896,6 +106941,87 @@ Each application creates a JSON file in the apps directory for tracking and anal
|
|
|
106896
106941
|
});
|
|
106897
106942
|
}
|
|
106898
106943
|
|
|
106944
|
+
// src/core/agents/specialized/attackSurface/grpcSchema.ts
|
|
106945
|
+
init_zod();
|
|
106946
|
+
var EndpointTransportEnum = exports_external.enum([
|
|
106947
|
+
"http",
|
|
106948
|
+
"grpc",
|
|
106949
|
+
"grpc_web",
|
|
106950
|
+
"connect"
|
|
106951
|
+
]);
|
|
106952
|
+
var GrpcStreamingTypeEnum = exports_external.enum([
|
|
106953
|
+
"unary",
|
|
106954
|
+
"server_stream",
|
|
106955
|
+
"client_stream",
|
|
106956
|
+
"bidi"
|
|
106957
|
+
]);
|
|
106958
|
+
var GrpcSchemaSourceEnum = exports_external.enum([
|
|
106959
|
+
"proto",
|
|
106960
|
+
"reflection",
|
|
106961
|
+
"protoset",
|
|
106962
|
+
"js_bundle",
|
|
106963
|
+
"gateway_derived",
|
|
106964
|
+
"unknown"
|
|
106965
|
+
]);
|
|
106966
|
+
var GrpcGatewayTypeEnum = exports_external.enum(["rest", "graphql", "connect"]);
|
|
106967
|
+
var GrpcEndpointMetadataSchema = exports_external.object({
|
|
106968
|
+
serviceFqn: exports_external.string().describe("Fully-qualified service name, e.g. 'account.v1.AccountService'"),
|
|
106969
|
+
method: exports_external.string().describe("RPC method name, e.g. 'GetAccount'"),
|
|
106970
|
+
streamingType: GrpcStreamingTypeEnum.default("unary"),
|
|
106971
|
+
reflectionAvailable: exports_external.boolean().optional(),
|
|
106972
|
+
schemaSource: GrpcSchemaSourceEnum.optional(),
|
|
106973
|
+
host: exports_external.string().nullish().describe("Authority override; null falls back to the app domain"),
|
|
106974
|
+
frontingGatewayOperation: exports_external.object({
|
|
106975
|
+
gatewayType: GrpcGatewayTypeEnum,
|
|
106976
|
+
operation: exports_external.string()
|
|
106977
|
+
}).nullish()
|
|
106978
|
+
});
|
|
106979
|
+
var GrpcPentestContextSchema = exports_external.object({
|
|
106980
|
+
transport: exports_external.enum(["grpc", "grpc_web", "connect"]),
|
|
106981
|
+
serviceFqn: exports_external.string(),
|
|
106982
|
+
method: exports_external.string(),
|
|
106983
|
+
streamingType: GrpcStreamingTypeEnum.optional(),
|
|
106984
|
+
reflectionAvailable: exports_external.boolean().optional(),
|
|
106985
|
+
schemaSource: GrpcSchemaSourceEnum.optional(),
|
|
106986
|
+
host: exports_external.string().nullish().describe("Authority override; null falls back to the app domain"),
|
|
106987
|
+
frontingGatewayOperation: exports_external.object({
|
|
106988
|
+
gatewayType: GrpcGatewayTypeEnum,
|
|
106989
|
+
operation: exports_external.string()
|
|
106990
|
+
}).nullish()
|
|
106991
|
+
});
|
|
106992
|
+
function deriveGrpcMetadataFromPath(path) {
|
|
106993
|
+
if (!path)
|
|
106994
|
+
return;
|
|
106995
|
+
const wire = path.replace(/^\//, "").split("?")[0];
|
|
106996
|
+
const slash = wire.lastIndexOf("/");
|
|
106997
|
+
if (slash <= 0 || slash === wire.length - 1)
|
|
106998
|
+
return;
|
|
106999
|
+
return { serviceFqn: wire.slice(0, slash), method: wire.slice(slash + 1) };
|
|
107000
|
+
}
|
|
107001
|
+
function toGrpcPentestContext(transport, grpc, path) {
|
|
107002
|
+
if (!transport || transport === "http")
|
|
107003
|
+
return;
|
|
107004
|
+
const derived = grpc ?? deriveGrpcMetadataFromPath(path);
|
|
107005
|
+
if (!derived)
|
|
107006
|
+
return;
|
|
107007
|
+
return {
|
|
107008
|
+
transport,
|
|
107009
|
+
serviceFqn: derived.serviceFqn,
|
|
107010
|
+
method: derived.method,
|
|
107011
|
+
streamingType: derived.streamingType,
|
|
107012
|
+
reflectionAvailable: derived.reflectionAvailable,
|
|
107013
|
+
schemaSource: derived.schemaSource,
|
|
107014
|
+
host: derived.host,
|
|
107015
|
+
frontingGatewayOperation: derived.frontingGatewayOperation
|
|
107016
|
+
};
|
|
107017
|
+
}
|
|
107018
|
+
function grpcAuthorityTarget(grpc, path) {
|
|
107019
|
+
if (!grpc?.host)
|
|
107020
|
+
return;
|
|
107021
|
+
const wirePath = path.startsWith("/") ? path : `/${path}`;
|
|
107022
|
+
return `grpc://${grpc.host}${wirePath}`;
|
|
107023
|
+
}
|
|
107024
|
+
|
|
106899
107025
|
// src/core/agents/offSecAgent/tools/documentEndpoint.ts
|
|
106900
107026
|
init_dist();
|
|
106901
107027
|
init_zod();
|
|
@@ -107218,6 +107344,7 @@ function validateConcurrency(concurrency) {
|
|
|
107218
107344
|
|
|
107219
107345
|
// src/core/agents/offSecAgent/tools/threatModelGenerator.ts
|
|
107220
107346
|
init_zod();
|
|
107347
|
+
init_id();
|
|
107221
107348
|
init_structured();
|
|
107222
107349
|
init_lazyLogger();
|
|
107223
107350
|
var log5 = scopedLogger(() => createLogger("threat-model-generator"));
|
|
@@ -107242,8 +107369,8 @@ var PentestObjectiveSchema = exports_external.object({
|
|
|
107242
107369
|
});
|
|
107243
107370
|
var SCHEMA_SOURCE_UNAVAILABLE_NOTE = "If the handler source is unreachable in your environment (source-unavailable mode — see prompt body), cite the grounding source you actually read (endpoint description, route table, OpenAPI spec, README) instead of `file:line` and tag the claim `[unverified: source unavailable]`. Never fabricate `file:line` references or invent code paths.";
|
|
107244
107371
|
var ThreatModelResultSchema = exports_external.object({
|
|
107245
|
-
businessLogic: exports_external.string().describe("Comprehensive narrative (aim for 800-2000 words) of what this endpoint does and the " + "rules it must uphold. Use markdown headings. Cover, in order: " + "(1) Purpose — what the endpoint accomplishes in user terms. " + "(2) Actors — who legitimately interacts with it, what they can do, how they authenticate. " + "(3) Data flow — inputs (with channel and trust level), transformations, side effects, outputs. " + "(4) Invariants — falsifiable business rules the endpoint must uphold, with enforcement " + "location (file:line) and confidence level. " + "(5) Trust boundaries — what actually guards each crossing (not what should). " + "(6) Analysis gaps — what you did NOT trace into and why. " + "Cite file:line for every concrete claim. Prefer completeness over brevity. " + SCHEMA_SOURCE_UNAVAILABLE_NOTE),
|
|
107246
|
-
threatModel: exports_external.string().describe("Comprehensive threat model (aim for 800-2000 words) grounded in the business logic. " + "Use markdown headings. Cover: " + "(1) Attacker profiles — 2-4 realistic attackers with motivation, skill, position, and goal. " + "(2) Attack vectors — enumerate thoroughly (typically 8-15 for a non-trivial endpoint). " + "Each vector must reference a concrete
|
|
107372
|
+
businessLogic: exports_external.string().describe("Comprehensive narrative (aim for 800-2000 words) of what this endpoint does and the " + "rules it must uphold. Use markdown headings. Cover, in order: " + "(1) Purpose — what the endpoint accomplishes in user terms. " + "(2) Actors — who legitimately interacts with it, what they can do, how they authenticate. " + "(3) Data flow — inputs including implicit framework-provided entry points reachable through the endpoint (with channel and trust level), transformations, side effects, outputs. " + "(4) Invariants — falsifiable business rules the endpoint must uphold, with enforcement " + "location (file:line) and confidence level. " + "(5) Trust boundaries — what actually guards each crossing (not what should). " + "(6) Analysis gaps — what you did NOT trace into and why. " + "Cite file:line for every concrete claim. Prefer completeness over brevity. " + SCHEMA_SOURCE_UNAVAILABLE_NOTE),
|
|
107373
|
+
threatModel: exports_external.string().describe("Comprehensive threat model (aim for 800-2000 words) grounded in the business logic. " + "Use markdown headings. Cover: " + "(1) Attacker profiles — 2-4 realistic attackers with motivation, skill, position, and goal. " + "(2) Attack vectors — enumerate thoroughly (typically 8-15 for a non-trivial endpoint). " + "Each vector must reference a concrete entry point from the business logic (including implicit framework-provided entry points), the invariant it " + "would break, the mechanism, the observable signal of success, an attacker profile, " + "likelihood, and impact. Cite file:line. " + "(3) Risk assessment — worst-case impact and vector prioritization. " + "Do not include generic OWASP filler ungrounded in evidence you actually read. " + SCHEMA_SOURCE_UNAVAILABLE_NOTE),
|
|
107247
107374
|
exposure: exports_external.number().min(0).max(3).describe("Exposure Level (0-3): how reachable is this endpoint by an attacker? " + "3 = Public, no authentication required. " + "2 = Standard authenticated user can reach it. " + "1 = Requires privileged/admin role. " + "0 = Private, internal-only, IP-restricted, or behind a service mesh."),
|
|
107248
107375
|
exposureReasoning: exports_external.string().describe("Cite specific code/config signals (file:line) that determined the exposure score: " + "route registration, auth middleware, role guards, IP allowlists, network placement. " + "E.g. 'Route registered on public router with no auth middleware (app.ts:18). " + "Handler does not check req.user.' " + SCHEMA_SOURCE_UNAVAILABLE_NOTE),
|
|
107249
107376
|
dataSensitivity: exports_external.number().min(0).max(3).describe("Data Sensitivity (0-3): how sensitive is the data this endpoint reads, writes, or returns? " + "3 = PII, PHI, financial records, passwords, tokens, secrets, session material. " + "2 = Business-operations data, tenant configs, internal settings, non-public metadata. " + "1 = Low-value user data (public profile, preferences). " + "0 = No meaningful data (static content, health checks, public catalog)."),
|
|
@@ -107277,11 +107404,12 @@ async function generateThreatModelForEndpoint(ctx, input) {
|
|
|
107277
107404
|
return threatModelLimiter(async () => {
|
|
107278
107405
|
if (ctx.abortSignal?.aborted)
|
|
107279
107406
|
return null;
|
|
107280
|
-
const { CodeAgent } = await import("./agent-
|
|
107281
|
-
const subagentId =
|
|
107407
|
+
const { CodeAgent } = await import("./agent-3cdfwxcd.js");
|
|
107408
|
+
const subagentId = newSessionId();
|
|
107409
|
+
const subagentName = `Threat Model: ${input.routePath}`;
|
|
107282
107410
|
ctx.eventBus?.emit("subagent-spawn", {
|
|
107283
107411
|
subagentId,
|
|
107284
|
-
name:
|
|
107412
|
+
name: subagentName,
|
|
107285
107413
|
input: { app: input.appName, endpoint: input.routePath },
|
|
107286
107414
|
parentSubagentId: ctx.subagentId
|
|
107287
107415
|
});
|
|
@@ -107307,6 +107435,7 @@ async function generateThreatModelForEndpoint(ctx, input) {
|
|
|
107307
107435
|
abortSignal: childAbort.signal,
|
|
107308
107436
|
eventBus: localBus,
|
|
107309
107437
|
subagentId,
|
|
107438
|
+
subagentName,
|
|
107310
107439
|
responseSchema: ThreatModelResultSchema,
|
|
107311
107440
|
stopWhen: stepCountIs(THREAT_MODEL_MAX_STEPS),
|
|
107312
107441
|
excludeTools: ["document_endpoint", "document_app"]
|
|
@@ -107356,6 +107485,13 @@ function buildThreatModelPrompt(input, projectThreatModel) {
|
|
|
107356
107485
|
const lineRange = input.line ? `around line ${input.line}` : "";
|
|
107357
107486
|
const authInfo = input.authRequired ? "Authentication required" : "No authentication required";
|
|
107358
107487
|
const methodStr = Array.isArray(input.method) ? input.method.join(", ") : input.method ?? "unknown";
|
|
107488
|
+
const isGrpc = !!input.transport && input.transport !== "http";
|
|
107489
|
+
const grpcSection = isGrpc ? `- **Transport**: ${input.transport} — this is a **gRPC method**, not an HTTP route. \`Path\` is the wire path \`/package.Service/Method\`; do NOT model it as a REST URL.
|
|
107490
|
+
- **gRPC service**: ${input.grpc?.serviceFqn ?? "(derive from Path)"}
|
|
107491
|
+
- **gRPC method**: ${input.grpc?.method ?? "(derive from Path)"}
|
|
107492
|
+
- **Streaming**: ${input.grpc?.streamingType ?? "unary"}
|
|
107493
|
+
The threat model and pentest objectives must be gRPC-specific (reflection/schema recovery, per-method missing-auth, BOLA on request-message IDs, metadata trust, \`:path\` authz bypass, protobuf fuzzing, streaming abuse) rather than HTTP-centric.
|
|
107494
|
+
` : "";
|
|
107359
107495
|
let prompt = `# Endpoint Analysis
|
|
107360
107496
|
|
|
107361
107497
|
## Target Endpoint
|
|
@@ -107366,7 +107502,7 @@ function buildThreatModelPrompt(input, projectThreatModel) {
|
|
|
107366
107502
|
- **Handler**: ${input.handler ?? "unknown"}
|
|
107367
107503
|
- **Auth**: ${authInfo}
|
|
107368
107504
|
- **Description**: ${input.description}
|
|
107369
|
-
|
|
107505
|
+
${grpcSection}
|
|
107370
107506
|
## Reading the code
|
|
107371
107507
|
|
|
107372
107508
|
1. Read the source file at \`${input.file ?? "(unknown)"}\` ${lineRange ? `(${lineRange})` : ""} to understand the implementation.
|
|
@@ -107389,7 +107525,7 @@ Produce a comprehensive narrative of what this endpoint does and what must be tr
|
|
|
107389
107525
|
Who legitimately interacts with this endpoint. For each actor list their role, what they can legitimately do via this endpoint, and how they authenticate (session cookie, JWT, signed webhook, mTLS, API key, IP allowlist, etc.).
|
|
107390
107526
|
|
|
107391
107527
|
### Data Flow
|
|
107392
|
-
- **Inputs**: each input
|
|
107528
|
+
- **Inputs**: each input reachable through this endpoint — name, channel (path / query / body / header / cookie / file / env / upstream-service / queue / webhook / server-action / rsc), trust level (untrusted / semi-trusted / trusted), and any observed validation. Include not just what the handler's signature accepts but implicit, framework-provided entry points a client can reach through this endpoint (e.g. server actions invoked from a page, RSC data fetches, framework-generated routes). Cite file:line.
|
|
107393
107529
|
- **Transformations**: the ordered steps the handler takes — fetch, validate, authorize, compute, call external service. Cite file:line for each.
|
|
107394
107530
|
- **Side effects**: every write the handler causes — DB writes, external API calls, email/queue/file writes, auth-state changes, payments. Name the target (table, service, queue).
|
|
107395
107531
|
- **Outputs**: what the response body, headers, and status codes contain.
|
|
@@ -107444,10 +107580,29 @@ Before enumerating, name the 1–3 **functional roles** this endpoint plays (fro
|
|
|
107444
107580
|
|
|
107445
107581
|
This is a **recall checklist, not a license to invent.** Skip role classes that have no anchor in this endpoint's code. Endpoint-specific vectors that don't fall under a listed role are welcome — mark them "endpoint-specific". Endpoint descriptions that name a role (e.g. "AI assistant", "payment intent", "webhook receiver", "password reset") are a strong signal to classify the corresponding role; if the handler source is unreachable, classify the role anyway and proceed under **source-unavailable mode** (defined in the reading-the-code section) — vectors still emit, but they're tagged \`[unverified: source unavailable]\` and capped at \`p1\` in Part 4.
|
|
107446
107582
|
|
|
107583
|
+
#### Step 1b — recall framework-derived surface
|
|
107584
|
+
|
|
107585
|
+
Identify the framework and stack this endpoint runs on — from the code where available (package.json, config, imports, file-system conventions), or from the endpoint description in source-unavailable mode. Frameworks expose implicit, convention-based surface that is reachable *through* this endpoint but never appears as an explicit route in the endpoint list. Enumerate it and fold it into this endpoint's threat model and test plan.
|
|
107586
|
+
|
|
107587
|
+
The classes below are high-signal framework sharp edges, with a few frameworks named under each. **They are examples to jog recall — not an exhaustive catalog, and not a fixed list of frameworks.** The named frameworks are illustrations; every stack has its own version of each class, and classes not listed here exist too. Skip any class with no anchor in this endpoint's code, and **generalize the same reasoning to whatever framework you actually detect**, including ones not named here — the point is the *class of sharp edge*, not the specific example.
|
|
107588
|
+
|
|
107589
|
+
| Framework sharp-edge class (examples) | Where it shows up (example frameworks) | Probe / confirming signal |
|
|
107590
|
+
|---|---|---|
|
|
107591
|
+
| **Hidden data/RPC endpoint reachable by suffix or header** — auth enforced in the UI component, not the loader/action/endpoint | e.g. Next.js server actions (POST the page URL + \`Next-Action: <hash>\`), RSC stream (\`RSC: 1\`); Remix / React Router \`<route>.data\` or \`?_data=<id>\`; SvelteKit \`<route>/__data.json\`, \`+server.ts\`; Nuxt \`<route>/_payload.json\`, \`/__nuxt_island/<Name>_<hash>?props=\`, \`server/api/**\`; FastAPI \`/openapi.json\` | Hit the data URL directly with no / other-tenant session; a 200 with data instead of 302/401 means access control lives only in the UI |
|
|
107592
|
+
| **Debug/error mode shipped to prod → secret leak, often RCE** — force a 500 and fingerprint the framework error UI | e.g. Django technical-500 (dumps \`SECRET_KEY\`), Flask/Werkzeug \`/console\`, Rails dev pages + \`/rails/info\`, Laravel Ignition (\`POST /_ignition/execute-solution\` = unauth RCE), ASP.NET dev-exception page / \`elmah.axd\` / \`Trace.axd\`, Nuxt devtools + \`/_nuxt/*.map\` | Trigger an unhandled error; a framework-styled traceback means debug is on — chase the signing secret or the console/Ignition RCE from there |
|
|
107593
|
+
| **Conventional admin / introspection / actuator paths** | e.g. Spring \`/actuator/{env,heapdump,mappings,gateway/routes}\` (heapdump → creds, env → RCE), Django \`/admin\`, Laravel \`/telescope\` \`/horizon\`, Rails \`/rails/info/routes\` | GET the known paths directly; 200 = exposed (\`/actuator/heapdump\` returning an \`octet-stream\` hprof is the tell) |
|
|
107594
|
+
| **Signing key / app secret → cookie & session forgery (sometimes RCE)** | e.g. Django \`SECRET_KEY\` (+ pickle sessions → RCE), Flask \`SECRET_KEY\`, Rails \`secret_key_base\` (Marshal cookie → RCE), Laravel \`APP_KEY\`, ASP.NET \`machineKey\` / ViewState | Recover the key via a debug/config leak, forge an elevated session cookie, replay it |
|
|
107595
|
+
| **"Public" env by naming prefix → secret inlined into the client bundle** | e.g. Next \`NEXT_PUBLIC_*\`, SvelteKit \`PUBLIC_*\` (\`/_app/env.js\`), Nuxt \`runtimeConfig.public\` (\`__NUXT_DATA__\`) | Grep \`/_next/static\`, \`/_app/immutable\`, and hydration blobs for secret-shaped values and \`.map\` files |
|
|
107596
|
+
| **ORM mass-assignment via binding defaults** | e.g. Django \`ModelForm fields='__all__'\` / DRF, Rails \`permit!\`, Laravel \`$guarded = []\`, NestJS missing \`whitelist: true\`, FastAPI missing \`response_model\` (over-serializes \`hashed_password\`) | Over-post \`is_admin\` / \`role\` / \`owner_id\`; check whether it persists or leaks |
|
|
107597
|
+
| **Built-in fetch or image proxy → SSRF / traversal** | e.g. Next \`/_next/image?url=\`, Nuxt \`/_ipx/\`, Rails \`open()\` / open-uri | Point it at \`http://169.254.169.254/…\` or an internal host; a proxied or timing-differentiated response confirms |
|
|
107598
|
+
| **Framework expression / deserialization RCE** | e.g. Spring SpEL (\`#{T(java.lang.Runtime)…}\`) and data-binding classloader (\`class.module.classLoader.*\`), ASP.NET ViewState / Json.NET \`$type\`, Rails YAML/Marshal, template injection in Jinja / Blade / ERB, Node prototype pollution (\`__proto__[x]\`) | A framework-specific canary (\`#{7*7}\`, \`{{7*7}}\`, a bad-\`$type\` error, \`__proto__\` reflection) that proves evaluation |
|
|
107599
|
+
|
|
107600
|
+
Treat any framework-derived surface you find this way as in-scope for this endpoint whenever this endpoint can reach it, and carry it into Part 4's test plan.
|
|
107601
|
+
|
|
107447
107602
|
#### Step 2 — enumerate
|
|
107448
107603
|
|
|
107449
107604
|
Each vector must:
|
|
107450
|
-
- Reference a concrete **
|
|
107605
|
+
- Reference a concrete **entry point** — an input from Part 1's data flow, including the framework-derived entry points captured there (Step 1b).
|
|
107451
107606
|
- Reference the **invariant(s)** from Part 1 that it would break, when applicable. If a vector is a config/infrastructure concern with no business invariant, say so.
|
|
107452
107607
|
- Describe the **mechanism** concretely — reference actual parameters, data flows, and code patterns you observed. Cite file:line (or, in source-unavailable mode, the grounding source you read — see the reading-the-code section).
|
|
107453
107608
|
- State the **observable signal** of a successful exploit (what you would see externally to confirm it worked).
|
|
@@ -107563,9 +107718,6 @@ function flattenPentestObjective(o) {
|
|
|
107563
107718
|
].join(`
|
|
107564
107719
|
`);
|
|
107565
107720
|
}
|
|
107566
|
-
function sanitize(s) {
|
|
107567
|
-
return s.toLowerCase().replace(/[^a-z0-9-_.]/g, "_");
|
|
107568
|
-
}
|
|
107569
107721
|
|
|
107570
107722
|
// src/core/agents/offSecAgent/tools/documentEndpoint.ts
|
|
107571
107723
|
function sanitizeName2(name) {
|
|
@@ -107574,7 +107726,9 @@ function sanitizeName2(name) {
|
|
|
107574
107726
|
var documentEndpointInputSchema = exports_external.object({
|
|
107575
107727
|
appName: exports_external.string().describe("Name of the parent application this endpoint belongs to. " + "Must match the appName used in a prior document_app call."),
|
|
107576
107728
|
routePath: exports_external.string().describe("The endpoint's unique identity — its HTTP route or access pattern. " + "This is the URL path a client requests, NOT a source-file path. " + "Examples: '/api/users', '/dashboard', '/auth/login', " + "'/{objectKey}?X-Amz-Signature=...', 'arn:aws:s3:::bucket-name'. " + "For cloud-resource endpoints (endpointType 'asset') use the specific " + "access pattern, not the base domain URL (which is stored on the parent " + "application). The route path is the endpoint's display identity — there " + "is no separate name field."),
|
|
107577
|
-
endpointType: exports_external.enum(["api-endpoint", "web-endpoint", "asset"]).describe("Type of endpoint: 'api-endpoint' for REST/GraphQL APIs, " + "'web-endpoint' for pages/views, 'asset' for other resources"),
|
|
107729
|
+
endpointType: exports_external.enum(["api-endpoint", "web-endpoint", "asset"]).describe("Type of endpoint: 'api-endpoint' for REST/GraphQL APIs, " + "'web-endpoint' for pages/views, 'asset' for other resources. " + "A gRPC method is still 'api-endpoint' — set `transport` to mark it gRPC."),
|
|
107730
|
+
transport: EndpointTransportEnum.optional().describe("Wire transport. Omit or 'http' for normal endpoints. Set 'grpc' " + "(or 'grpc_web' / 'connect') for a gRPC method and populate `grpc`."),
|
|
107731
|
+
grpc: GrpcEndpointMetadataSchema.optional().describe("gRPC attributes — required when transport is a gRPC variant. Put the " + "wire path '/package.Service/Method' in `routePath`; do not glue on a host."),
|
|
107578
107732
|
description: exports_external.string().describe("Detailed description of the endpoint including what it does"),
|
|
107579
107733
|
method: exports_external.union([exports_external.string(), exports_external.array(exports_external.string())]).optional().describe("HTTP method(s) supported (e.g., 'GET', 'POST', or ['GET', 'POST', 'DELETE']). " + "Use 'PAGE' for web pages/views."),
|
|
107580
107734
|
handler: exports_external.string().optional().describe("Handler function or component name (whitebox analysis)"),
|
|
@@ -107671,7 +107825,9 @@ Each endpoint creates a JSON file in the assets directory for tracking and analy
|
|
|
107671
107825
|
line: input.line,
|
|
107672
107826
|
handler: input.handler,
|
|
107673
107827
|
authRequired: input.authRequired,
|
|
107674
|
-
description: input.description
|
|
107828
|
+
description: input.description,
|
|
107829
|
+
transport: input.transport,
|
|
107830
|
+
grpc: input.grpc
|
|
107675
107831
|
};
|
|
107676
107832
|
const threatModelOutput = await generateThreatModelForEndpoint(ctx, subagentInput);
|
|
107677
107833
|
const riskScore = threatModelOutput?.riskScore ?? heuristicRiskScore;
|
|
@@ -107707,6 +107863,8 @@ Each endpoint creates a JSON file in the assets directory for tracking and analy
|
|
|
107707
107863
|
appName: input.appName,
|
|
107708
107864
|
routePath: input.routePath,
|
|
107709
107865
|
endpointType: input.endpointType,
|
|
107866
|
+
transport: input.transport,
|
|
107867
|
+
grpc: input.grpc,
|
|
107710
107868
|
riskLevel: input.riskLevel,
|
|
107711
107869
|
filepath,
|
|
107712
107870
|
businessLogic: businessLogic ?? undefined,
|
|
@@ -107747,6 +107905,7 @@ function hasCanonicalName(cwe) {
|
|
|
107747
107905
|
}
|
|
107748
107906
|
|
|
107749
107907
|
// src/core/agents/offSecAgent/tools/documentFinding.ts
|
|
107908
|
+
init_id();
|
|
107750
107909
|
init_structured();
|
|
107751
107910
|
init_lazyLogger();
|
|
107752
107911
|
|
|
@@ -109168,7 +109327,7 @@ init_lazyLogger();
|
|
|
109168
109327
|
var log6 = scopedLogger(() => createLogger("FindingJudge"));
|
|
109169
109328
|
async function judgeFinding(input, ctx) {
|
|
109170
109329
|
try {
|
|
109171
|
-
const { FindingJudgeAgent } = await import("./agent-
|
|
109330
|
+
const { FindingJudgeAgent } = await import("./agent-yayy5x2a.js");
|
|
109172
109331
|
const agent = new FindingJudgeAgent({
|
|
109173
109332
|
finding: input,
|
|
109174
109333
|
model: ctx.model,
|
|
@@ -109177,9 +109336,11 @@ async function judgeFinding(input, ctx) {
|
|
|
109177
109336
|
abortSignal: ctx.abortSignal,
|
|
109178
109337
|
eventBus: ctx.eventBus,
|
|
109179
109338
|
subagentId: ctx.subagentId,
|
|
109339
|
+
subagentName: ctx.subagentName,
|
|
109180
109340
|
sandbox: ctx.sandbox,
|
|
109181
109341
|
target: input.target ?? ctx.target ?? ctx.session.targets[0],
|
|
109182
109342
|
enableThinking: ctx.enableThinking,
|
|
109343
|
+
thinkingEffort: ctx.thinkingEffort,
|
|
109183
109344
|
openAIReasoningEffort: ctx.openAIReasoningEffort
|
|
109184
109345
|
});
|
|
109185
109346
|
const result = await agent.consume();
|
|
@@ -109402,10 +109563,11 @@ CRITICAL RULES — READ BEFORE CALLING:
|
|
|
109402
109563
|
vulnerabilityClass: input.vulnerabilityClass
|
|
109403
109564
|
}
|
|
109404
109565
|
};
|
|
109405
|
-
const judgeSubagentId =
|
|
109566
|
+
const judgeSubagentId = newSessionId();
|
|
109567
|
+
const judgeSubagentName = "Finding Judge";
|
|
109406
109568
|
ctx.eventBus?.emit("subagent-spawn", {
|
|
109407
109569
|
subagentId: judgeSubagentId,
|
|
109408
|
-
name:
|
|
109570
|
+
name: judgeSubagentName,
|
|
109409
109571
|
input: { title: input.title, endpoint: input.endpoint },
|
|
109410
109572
|
parentSubagentId: ctx.subagentId
|
|
109411
109573
|
});
|
|
@@ -109420,9 +109582,11 @@ CRITICAL RULES — READ BEFORE CALLING:
|
|
|
109420
109582
|
abortSignal: ctx.abortSignal,
|
|
109421
109583
|
eventBus: judgeBus,
|
|
109422
109584
|
subagentId: judgeSubagentId,
|
|
109585
|
+
subagentName: judgeSubagentName,
|
|
109423
109586
|
sandbox: ctx.sandbox,
|
|
109424
109587
|
target: ctx.target,
|
|
109425
109588
|
enableThinking: ctx.enableThinking,
|
|
109589
|
+
thinkingEffort: ctx.thinkingEffort,
|
|
109426
109590
|
openAIReasoningEffort: ctx.openAIReasoningEffort
|
|
109427
109591
|
});
|
|
109428
109592
|
} catch (error) {
|
|
@@ -109735,14 +109899,6 @@ ${finding.references}` : ""}
|
|
|
109735
109899
|
}
|
|
109736
109900
|
});
|
|
109737
109901
|
}
|
|
109738
|
-
var judgeCounters = new Map;
|
|
109739
|
-
function nextJudgeSubagentId(parentSubagentId) {
|
|
109740
|
-
const key = parentSubagentId ?? "";
|
|
109741
|
-
const next = (judgeCounters.get(key) ?? 0) + 1;
|
|
109742
|
-
judgeCounters.set(key, next);
|
|
109743
|
-
const prefix = parentSubagentId ? `${parentSubagentId}-` : "";
|
|
109744
|
-
return `${prefix}finding-judge-${next}`;
|
|
109745
|
-
}
|
|
109746
109902
|
async function executeLocalPoc(ctx, input) {
|
|
109747
109903
|
const pocsPath = ctx.session.pocsPath;
|
|
109748
109904
|
if (!existsSync8(pocsPath)) {
|
|
@@ -113266,7 +113422,306 @@ var SEND_EMAIL_TOOL_NAME = "send_email";
|
|
|
113266
113422
|
init_dist();
|
|
113267
113423
|
init_zod();
|
|
113268
113424
|
import { existsSync as existsSync9, mkdirSync as mkdirSync8, writeFileSync as writeFileSync10 } from "node:fs";
|
|
113425
|
+
import { join as join15 } from "node:path";
|
|
113426
|
+
|
|
113427
|
+
// src/core/agents/offSecAgent/tools/agentScratch.ts
|
|
113269
113428
|
import { join as join14 } from "node:path";
|
|
113429
|
+
function agentLogsDir(ctx) {
|
|
113430
|
+
return ctx.subagentId ? join14(ctx.session.rootPath, "subagents", ctx.subagentId, "logs") : ctx.session.logsPath;
|
|
113431
|
+
}
|
|
113432
|
+
|
|
113433
|
+
// src/core/agents/offSecAgent/tools/destructiveGuard.ts
|
|
113434
|
+
var NOT_DESTRUCTIVE = { destructive: false };
|
|
113435
|
+
function safeDecode2(input) {
|
|
113436
|
+
let out = input ?? "";
|
|
113437
|
+
for (let pass = 0;pass < 2; pass++) {
|
|
113438
|
+
const decoded = out.replace(/\+/g, " ").replace(/%[0-9a-fA-F]{2}/g, (m) => {
|
|
113439
|
+
try {
|
|
113440
|
+
return decodeURIComponent(m);
|
|
113441
|
+
} catch {
|
|
113442
|
+
return m;
|
|
113443
|
+
}
|
|
113444
|
+
});
|
|
113445
|
+
if (decoded === out)
|
|
113446
|
+
break;
|
|
113447
|
+
out = decoded;
|
|
113448
|
+
}
|
|
113449
|
+
return out;
|
|
113450
|
+
}
|
|
113451
|
+
var SQL_SEP = String.raw`(?:\s|/\*[\s\S]*?\*/)+`;
|
|
113452
|
+
var SQL_DESTRUCTIVE_STATEMENT = new RegExp(`(?:drop${SQL_SEP}(?:table|database|schema|index|view|column|role|user|sequence|trigger|function|procedure)` + `|truncate${SQL_SEP}(?:table${SQL_SEP})?[\`"\\w]` + `|delete${SQL_SEP}from${SQL_SEP}[\`"\\w]` + `|alter${SQL_SEP}table${SQL_SEP}[^;]*\\bdrop\\b)`, "i");
|
|
113453
|
+
var SQL_STATEMENT_START = new RegExp(`^\\s*['"\`;)\\s]*(?:${SQL_DESTRUCTIVE_STATEMENT.source})`, "i");
|
|
113454
|
+
var SQL_INJECTION_CONTEXT = new RegExp(`['"\`]\\s*;?\\s*(?:${SQL_DESTRUCTIVE_STATEMENT.source})|;\\s*(?:${SQL_DESTRUCTIVE_STATEMENT.source})`, "i");
|
|
113455
|
+
function httpCarriesDestructiveSql(decoded) {
|
|
113456
|
+
if (!SQL_DESTRUCTIVE_STATEMENT.test(decoded))
|
|
113457
|
+
return false;
|
|
113458
|
+
return SQL_STATEMENT_START.test(decoded) || SQL_INJECTION_CONTEXT.test(decoded);
|
|
113459
|
+
}
|
|
113460
|
+
var NOSQL_HTTP_DESTRUCTIVE = /\bdb(?:\.\w+)+\.(?:drop(?:Database)?|deleteMany|remove)\s*\(|\.dropDatabase\s*\(|\.drop\s*\(\s*\)|\bdeleteMany\s*\(\s*\{|(?:^|[\n;])\s*(?:flushall|flushdb)\b/i;
|
|
113461
|
+
var NOSQL_CMD_DESTRUCTIVE = /\bdb(?:\.\w+)*\.(?:drop(?:Database)?|deleteMany|remove)\s*\(|\.dropDatabase\s*\(|\.drop\s*\(\s*\)|\bflushall\b|\bflushdb\b/i;
|
|
113462
|
+
var WRITE_METHODS = new Set(["POST", "PUT", "PATCH"]);
|
|
113463
|
+
var DESTRUCTIVE_PATH_PATTERN = /(?:^|[/_?&=.-])(?:delete|destroy|drop|purge|truncate|wipe|obliterate|nuke|remove|hard[-_]?delete|force[-_]?delete)(?:[/_?&=.-]|$)/i;
|
|
113464
|
+
var METHOD_OVERRIDE_DELETE_PATTERN = /(?:_method|x-http-method-override|x-http-method|x-method-override|x-method|httpmethod)\s*[=:]\s*['"]?delete\b/i;
|
|
113465
|
+
var CMD_BOUNDARY = String.raw`(?:^|[\n;&|(]|&&|\|\||-[a-z]*c\s+["']?)\s*(?:sudo\s+)?`;
|
|
113466
|
+
var HOME_REF = /^(?:~[^/]*|\$\{?HOME\}?)(?:\/|$)/;
|
|
113467
|
+
function normalizeRmTarget(raw) {
|
|
113468
|
+
const unquoted = raw.replace(/^['"]|['"]$/g, "");
|
|
113469
|
+
if (HOME_REF.test(unquoted))
|
|
113470
|
+
return "~";
|
|
113471
|
+
if (!unquoted.startsWith("/"))
|
|
113472
|
+
return unquoted;
|
|
113473
|
+
const stack = [];
|
|
113474
|
+
for (const seg of unquoted.split("/")) {
|
|
113475
|
+
if (seg === "" || seg === ".")
|
|
113476
|
+
continue;
|
|
113477
|
+
if (seg === "..") {
|
|
113478
|
+
stack.pop();
|
|
113479
|
+
continue;
|
|
113480
|
+
}
|
|
113481
|
+
stack.push(seg);
|
|
113482
|
+
}
|
|
113483
|
+
return `/${stack.join("/")}`;
|
|
113484
|
+
}
|
|
113485
|
+
function isDangerousRm(command) {
|
|
113486
|
+
const rmRe = /\brm\b([^\n;|&]*)/gi;
|
|
113487
|
+
for (const match of command.matchAll(rmRe)) {
|
|
113488
|
+
const args = match[1] ?? "";
|
|
113489
|
+
const hasRecursive = /(?:^|\s)(?:-[a-z]*r[a-z]*|--recursive)\b/i.test(args);
|
|
113490
|
+
const hasForce = /(?:^|\s)(?:-[a-z]*f[a-z]*|--force)\b/i.test(args);
|
|
113491
|
+
if (!hasRecursive || !hasForce)
|
|
113492
|
+
continue;
|
|
113493
|
+
if (/--no-preserve-root/i.test(args))
|
|
113494
|
+
return true;
|
|
113495
|
+
for (const rawToken of args.split(/\s+/)) {
|
|
113496
|
+
if (!rawToken || rawToken.startsWith("-"))
|
|
113497
|
+
continue;
|
|
113498
|
+
if (/^['"]?\/\*/.test(rawToken))
|
|
113499
|
+
return true;
|
|
113500
|
+
const norm = normalizeRmTarget(rawToken);
|
|
113501
|
+
if (norm === "~")
|
|
113502
|
+
return true;
|
|
113503
|
+
if (norm === "/")
|
|
113504
|
+
return true;
|
|
113505
|
+
if (/^\/(?:etc|var|usr|bin|sbin|boot|lib|lib64|root|home|opt|srv|sys|proc|dev)(?:\/|$)/i.test(norm)) {
|
|
113506
|
+
return true;
|
|
113507
|
+
}
|
|
113508
|
+
}
|
|
113509
|
+
}
|
|
113510
|
+
return false;
|
|
113511
|
+
}
|
|
113512
|
+
var HOST_DESTRUCTIVE_RULES = [
|
|
113513
|
+
{ id: "rm-rf-root", test: isDangerousRm },
|
|
113514
|
+
{
|
|
113515
|
+
id: "dd-to-device",
|
|
113516
|
+
test: (c) => {
|
|
113517
|
+
const m = new RegExp(`${CMD_BOUNDARY}dd\\b[^\\n;|&]*\\bof=\\s*['"]?(/dev/\\S+)`, "i").exec(c);
|
|
113518
|
+
if (!m)
|
|
113519
|
+
return false;
|
|
113520
|
+
const dev = m[1].replace(/['"].*$/, "");
|
|
113521
|
+
return !/^\/dev\/(?:null|zero|full|random|urandom|stdout|stderr|tty|fd\/)/i.test(dev);
|
|
113522
|
+
}
|
|
113523
|
+
},
|
|
113524
|
+
{
|
|
113525
|
+
id: "mkfs",
|
|
113526
|
+
test: (c) => new RegExp(`${CMD_BOUNDARY}(?:/s?bin/)?mkfs(?:\\.\\w+)?\\b`, "i").test(c)
|
|
113527
|
+
},
|
|
113528
|
+
{
|
|
113529
|
+
id: "clobber-device",
|
|
113530
|
+
test: (c) => />\s*['"]?\/dev\/(?:sd|nvme|hd|vd|xvd|mapper|disk|loop|dm-|md)/i.test(c)
|
|
113531
|
+
},
|
|
113532
|
+
{
|
|
113533
|
+
id: "fork-bomb",
|
|
113534
|
+
test: (c) => /:\s*\(\s*\)\s*\{\s*:\s*\|\s*:\s*&\s*\}\s*;\s*:/.test(c)
|
|
113535
|
+
},
|
|
113536
|
+
{
|
|
113537
|
+
id: "power-state",
|
|
113538
|
+
test: (c) => new RegExp(`${CMD_BOUNDARY}(?:/(?:usr/)?s?bin/)?(?:shutdown|reboot|halt|poweroff)\\b`, "i").test(c) || new RegExp(`${CMD_BOUNDARY}init\\s+0\\b`, "i").test(c)
|
|
113539
|
+
}
|
|
113540
|
+
];
|
|
113541
|
+
var HTTP_CLIENT_PATTERN = /\b(?:curl|wget|xh|httpie)\b/i;
|
|
113542
|
+
var URL_IN_COMMAND = /https?:\/\/[^\s"'`;|&)<>]+/gi;
|
|
113543
|
+
var CURL_DELETE = /(?:-X|--request|--method)[=\s]*['"]?delete\b/i;
|
|
113544
|
+
var HTTPIE_METHOD = new RegExp(`${CMD_BOUNDARY}(?:https?|xh|httpie)\\s+(?:-{1,2}\\S+\\s+)*(delete|post|put|patch)\\b`, "i");
|
|
113545
|
+
var CURL_WRITE_METHOD = /(?:-X|--request|--method)[=\s]*['"]?(?:post|put|patch)\b/i;
|
|
113546
|
+
var CURL_DATA_FLAG = /(?:^|\s)(?:-d|--data(?:-raw|-binary|-urlencode|-ascii)?|-F|--form|--json|--post-data|--post-file|--body-data|--body-file)\b/i;
|
|
113547
|
+
var JS_METHOD_DELETE = /\bmethod\s*:\s*['"`]?\s*delete\b/i;
|
|
113548
|
+
var JS_HTTP_CLIENT_HINT = /\b(?:fetch|axios|got|ky|superagent|needle|node-fetch|undici|phin|XMLHttpRequest|xhr)\b|\.\s*(?:request|open)\s*\(/i;
|
|
113549
|
+
var JS_CLIENT_DELETE_CALL = /\b(?:axios|got|ky|superagent|needle|supertest|phin|page|apiContext|apiRequestContext|request)\s*(?:\.\s*\w+)*\.\s*delete\s*\(/i;
|
|
113550
|
+
function classifyCommandHttp(command) {
|
|
113551
|
+
const decoded = safeDecode2(command);
|
|
113552
|
+
const httpieMethod = HTTPIE_METHOD.exec(command)?.[1]?.toLowerCase();
|
|
113553
|
+
const hasShellHttpClient = HTTP_CLIENT_PATTERN.test(command) || httpieMethod !== undefined;
|
|
113554
|
+
const hasJsHttpClient = JS_HTTP_CLIENT_HINT.test(command);
|
|
113555
|
+
if (hasShellHttpClient && (CURL_DELETE.test(command) || httpieMethod === "delete")) {
|
|
113556
|
+
return {
|
|
113557
|
+
destructive: true,
|
|
113558
|
+
category: "http-delete-method",
|
|
113559
|
+
ruleId: "cmd-http-delete",
|
|
113560
|
+
reason: "command issues an HTTP DELETE against the target"
|
|
113561
|
+
};
|
|
113562
|
+
}
|
|
113563
|
+
if (JS_METHOD_DELETE.test(command) && hasJsHttpClient || JS_CLIENT_DELETE_CALL.test(command)) {
|
|
113564
|
+
return {
|
|
113565
|
+
destructive: true,
|
|
113566
|
+
category: "http-delete-method",
|
|
113567
|
+
ruleId: "cmd-script-http-delete",
|
|
113568
|
+
reason: "command runs an in-script HTTP DELETE (fetch/axios/Playwright) against the target"
|
|
113569
|
+
};
|
|
113570
|
+
}
|
|
113571
|
+
if ((hasShellHttpClient || hasJsHttpClient) && METHOD_OVERRIDE_DELETE_PATTERN.test(decoded)) {
|
|
113572
|
+
return {
|
|
113573
|
+
destructive: true,
|
|
113574
|
+
category: "http-delete-method",
|
|
113575
|
+
ruleId: "cmd-http-override-delete",
|
|
113576
|
+
reason: "command overrides the HTTP method to DELETE"
|
|
113577
|
+
};
|
|
113578
|
+
}
|
|
113579
|
+
if (hasShellHttpClient && httpCarriesDestructiveSql(decoded)) {
|
|
113580
|
+
return {
|
|
113581
|
+
destructive: true,
|
|
113582
|
+
category: "sql-destructive",
|
|
113583
|
+
ruleId: "cmd-http-sql",
|
|
113584
|
+
reason: "command sends a destructive SQL statement in an HTTP request (DROP/TRUNCATE/DELETE FROM/ALTER…DROP)"
|
|
113585
|
+
};
|
|
113586
|
+
}
|
|
113587
|
+
if (hasShellHttpClient && NOSQL_HTTP_DESTRUCTIVE.test(decoded)) {
|
|
113588
|
+
return {
|
|
113589
|
+
destructive: true,
|
|
113590
|
+
category: "nosql-destructive",
|
|
113591
|
+
ruleId: "cmd-http-nosql",
|
|
113592
|
+
reason: "command sends a destructive NoSQL/cache operation in an HTTP request"
|
|
113593
|
+
};
|
|
113594
|
+
}
|
|
113595
|
+
const writeIndicated = CURL_WRITE_METHOD.test(command) || CURL_DATA_FLAG.test(command) || httpieMethod === "post" || httpieMethod === "put" || httpieMethod === "patch";
|
|
113596
|
+
if (hasShellHttpClient && writeIndicated) {
|
|
113597
|
+
for (const rawUrl of command.match(URL_IN_COMMAND) ?? []) {
|
|
113598
|
+
if (DESTRUCTIVE_PATH_PATTERN.test(safeDecode2(rawUrl))) {
|
|
113599
|
+
return {
|
|
113600
|
+
destructive: true,
|
|
113601
|
+
category: "http-destructive-path",
|
|
113602
|
+
ruleId: "cmd-http-destructive-path",
|
|
113603
|
+
reason: "command sends a write request to a delete/destroy/purge route"
|
|
113604
|
+
};
|
|
113605
|
+
}
|
|
113606
|
+
}
|
|
113607
|
+
}
|
|
113608
|
+
return NOT_DESTRUCTIVE;
|
|
113609
|
+
}
|
|
113610
|
+
var DB_CLIENT_PATTERN = /\b(?:psql|mysql|mariadb|mongosh|mongo|sqlite3|sqlcmd|sqlplus|cqlsh|clickhouse-client|redis-cli|sqlmap)\b|\bcockroach\s+sql\b/i;
|
|
113611
|
+
function classifyHttpAction(input) {
|
|
113612
|
+
const method = input.method.toUpperCase();
|
|
113613
|
+
const decodedUrl = safeDecode2(input.url);
|
|
113614
|
+
const decodedBody = safeDecode2(typeof input.body === "string" ? input.body : "");
|
|
113615
|
+
const headerText = input.headers ? Object.entries(input.headers).map(([name, value]) => `${name}: ${String(value)}`).join(`
|
|
113616
|
+
`) : "";
|
|
113617
|
+
const overrideHaystack = `${decodedUrl}
|
|
113618
|
+
${decodedBody}
|
|
113619
|
+
${headerText}`;
|
|
113620
|
+
if (method === "DELETE") {
|
|
113621
|
+
return {
|
|
113622
|
+
destructive: true,
|
|
113623
|
+
category: "http-delete-method",
|
|
113624
|
+
ruleId: "http-method-delete",
|
|
113625
|
+
reason: "HTTP DELETE removes a resource on the target"
|
|
113626
|
+
};
|
|
113627
|
+
}
|
|
113628
|
+
if (METHOD_OVERRIDE_DELETE_PATTERN.test(overrideHaystack)) {
|
|
113629
|
+
return {
|
|
113630
|
+
destructive: true,
|
|
113631
|
+
category: "http-delete-method",
|
|
113632
|
+
ruleId: "http-method-override-delete",
|
|
113633
|
+
reason: "request overrides the HTTP method to DELETE"
|
|
113634
|
+
};
|
|
113635
|
+
}
|
|
113636
|
+
if (httpCarriesDestructiveSql(`${decodedUrl}
|
|
113637
|
+
${decodedBody}`)) {
|
|
113638
|
+
return {
|
|
113639
|
+
destructive: true,
|
|
113640
|
+
category: "sql-destructive",
|
|
113641
|
+
ruleId: "http-body-sql",
|
|
113642
|
+
reason: "request carries a destructive SQL statement (DROP/TRUNCATE/DELETE FROM/ALTER…DROP)"
|
|
113643
|
+
};
|
|
113644
|
+
}
|
|
113645
|
+
if (NOSQL_HTTP_DESTRUCTIVE.test(decodedBody)) {
|
|
113646
|
+
return {
|
|
113647
|
+
destructive: true,
|
|
113648
|
+
category: "nosql-destructive",
|
|
113649
|
+
ruleId: "http-body-nosql",
|
|
113650
|
+
reason: "request carries a destructive NoSQL/cache operation (drop/deleteMany/flush)"
|
|
113651
|
+
};
|
|
113652
|
+
}
|
|
113653
|
+
if (WRITE_METHODS.has(method) && DESTRUCTIVE_PATH_PATTERN.test(decodedUrl)) {
|
|
113654
|
+
return {
|
|
113655
|
+
destructive: true,
|
|
113656
|
+
category: "http-destructive-path",
|
|
113657
|
+
ruleId: "http-destructive-path",
|
|
113658
|
+
reason: "write request targets a delete/destroy/purge route"
|
|
113659
|
+
};
|
|
113660
|
+
}
|
|
113661
|
+
return NOT_DESTRUCTIVE;
|
|
113662
|
+
}
|
|
113663
|
+
function classifyCommandAction(command) {
|
|
113664
|
+
for (const { id, test } of HOST_DESTRUCTIVE_RULES) {
|
|
113665
|
+
if (test(command)) {
|
|
113666
|
+
return {
|
|
113667
|
+
destructive: true,
|
|
113668
|
+
category: "host-destructive",
|
|
113669
|
+
ruleId: id,
|
|
113670
|
+
reason: `command performs a catastrophic host operation (${id})`
|
|
113671
|
+
};
|
|
113672
|
+
}
|
|
113673
|
+
}
|
|
113674
|
+
const decodedCommand = safeDecode2(command);
|
|
113675
|
+
if (DB_CLIENT_PATTERN.test(command)) {
|
|
113676
|
+
if (SQL_DESTRUCTIVE_STATEMENT.test(decodedCommand)) {
|
|
113677
|
+
return {
|
|
113678
|
+
destructive: true,
|
|
113679
|
+
category: "sql-destructive",
|
|
113680
|
+
ruleId: "cmd-sql",
|
|
113681
|
+
reason: "command runs a destructive SQL statement via a DB client (DROP/TRUNCATE/DELETE FROM/ALTER…DROP)"
|
|
113682
|
+
};
|
|
113683
|
+
}
|
|
113684
|
+
if (NOSQL_CMD_DESTRUCTIVE.test(decodedCommand)) {
|
|
113685
|
+
return {
|
|
113686
|
+
destructive: true,
|
|
113687
|
+
category: "nosql-destructive",
|
|
113688
|
+
ruleId: "cmd-nosql",
|
|
113689
|
+
reason: "command runs a destructive NoSQL/cache operation via a DB client (drop/deleteMany/flush)"
|
|
113690
|
+
};
|
|
113691
|
+
}
|
|
113692
|
+
}
|
|
113693
|
+
return classifyCommandHttp(command);
|
|
113694
|
+
}
|
|
113695
|
+
|
|
113696
|
+
class DestructiveActionError extends Error {
|
|
113697
|
+
classification;
|
|
113698
|
+
constructor(classification, subject) {
|
|
113699
|
+
super(`Destructive action blocked: ${subject} — ${classification.reason ?? "destructive operation"}. ` + `Destructive testing (DB deletes/drops, API write-deletes, catastrophic host operations) is NOT authorized for this engagement. ` + `Prove the flaw without completing the destructive step (e.g. demonstrate the authorization boundary is crossed with a read or a reversible action), or ask the operator to enable destructive testing.`);
|
|
113700
|
+
this.classification = classification;
|
|
113701
|
+
this.name = "DestructiveActionError";
|
|
113702
|
+
}
|
|
113703
|
+
}
|
|
113704
|
+
function isDestructiveTestingAllowed(ctx) {
|
|
113705
|
+
return ctx.session?.config?.allowDestructiveActions === true;
|
|
113706
|
+
}
|
|
113707
|
+
function assertHttpActionAllowed(input, ctx) {
|
|
113708
|
+
if (isDestructiveTestingAllowed(ctx))
|
|
113709
|
+
return;
|
|
113710
|
+
const classification = classifyHttpAction(input);
|
|
113711
|
+
if (classification.destructive) {
|
|
113712
|
+
throw new DestructiveActionError(classification, `${input.method.toUpperCase()} ${input.url}`);
|
|
113713
|
+
}
|
|
113714
|
+
}
|
|
113715
|
+
function assertCommandActionAllowed(command, ctx) {
|
|
113716
|
+
if (isDestructiveTestingAllowed(ctx))
|
|
113717
|
+
return;
|
|
113718
|
+
const classification = classifyCommandAction(command);
|
|
113719
|
+
if (classification.destructive) {
|
|
113720
|
+
throw new DestructiveActionError(classification, command);
|
|
113721
|
+
}
|
|
113722
|
+
}
|
|
113723
|
+
|
|
113724
|
+
// src/core/agents/offSecAgent/tools/executeCommand.ts
|
|
113270
113725
|
var MAX_INLINE = 50000;
|
|
113271
113726
|
var MS_TIMEOUT_THRESHOLD = 1e4;
|
|
113272
113727
|
var DEFAULT_PROMPT_INJECTION_FILE_ENV = "APEX_PROMPT_INJECTION_FILE";
|
|
@@ -113309,13 +113764,13 @@ function maybeSaveFullOutput(raw, ctx) {
|
|
|
113309
113764
|
if (raw.length <= MAX_INLINE) {
|
|
113310
113765
|
return { text: raw || "(no output)" };
|
|
113311
113766
|
}
|
|
113312
|
-
const outputDir =
|
|
113767
|
+
const outputDir = join15(agentLogsDir(ctx), "cmd-output");
|
|
113313
113768
|
if (!existsSync9(outputDir)) {
|
|
113314
113769
|
mkdirSync8(outputDir, { recursive: true });
|
|
113315
113770
|
}
|
|
113316
113771
|
const ts = new Date().toISOString().replace(/[:.]/g, "-");
|
|
113317
113772
|
const filename = `output-${ts}.txt`;
|
|
113318
|
-
const filePath =
|
|
113773
|
+
const filePath = join15(outputDir, filename);
|
|
113319
113774
|
try {
|
|
113320
113775
|
writeFileSync10(filePath, raw);
|
|
113321
113776
|
} catch {
|
|
@@ -113336,6 +113791,15 @@ function maybeSaveFullOutput(raw, ctx) {
|
|
|
113336
113791
|
function shellQuote2(value) {
|
|
113337
113792
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
113338
113793
|
}
|
|
113794
|
+
function redactSecretValues(text, secrets) {
|
|
113795
|
+
if (!secrets?.length)
|
|
113796
|
+
return text;
|
|
113797
|
+
let out = text;
|
|
113798
|
+
for (const s of [...secrets].filter((v) => v && v.length >= 6).sort((a, b) => b.length - a.length)) {
|
|
113799
|
+
out = out.split(s).join("[REDACTED]");
|
|
113800
|
+
}
|
|
113801
|
+
return out;
|
|
113802
|
+
}
|
|
113339
113803
|
function wrapCommandWithEnv(command, envVars) {
|
|
113340
113804
|
if (!envVars || Object.keys(envVars).length === 0)
|
|
113341
113805
|
return command;
|
|
@@ -113488,6 +113952,20 @@ IMPORTANT: Always analyze results and adjust your approach based on findings.`,
|
|
|
113488
113952
|
};
|
|
113489
113953
|
}
|
|
113490
113954
|
const commandWithHeaders = inject.status === "injected" ? inject.command : command;
|
|
113955
|
+
try {
|
|
113956
|
+
assertCommandActionAllowed(commandWithHeaders, ctx);
|
|
113957
|
+
} catch (e) {
|
|
113958
|
+
if (e instanceof DestructiveActionError) {
|
|
113959
|
+
return {
|
|
113960
|
+
success: false,
|
|
113961
|
+
error: e.message,
|
|
113962
|
+
stdout: "",
|
|
113963
|
+
stderr: e.message,
|
|
113964
|
+
command
|
|
113965
|
+
};
|
|
113966
|
+
}
|
|
113967
|
+
throw e;
|
|
113968
|
+
}
|
|
113491
113969
|
let promptInjectionLibrary;
|
|
113492
113970
|
let promptInjectionEnvVars;
|
|
113493
113971
|
let promptInjectionPayloadContent;
|
|
@@ -113515,7 +113993,10 @@ IMPORTANT: Always analyze results and adjust your approach based on findings.`,
|
|
|
113515
113993
|
command
|
|
113516
113994
|
};
|
|
113517
113995
|
}
|
|
113518
|
-
const redact = (value) =>
|
|
113996
|
+
const redact = (value) => {
|
|
113997
|
+
const stripped = promptInjectionLibrary ? redactPromptInjectionPayloads(value, promptInjectionLibrary) : value;
|
|
113998
|
+
return redactSecretValues(stripped, ctx.secretValues);
|
|
113999
|
+
};
|
|
113519
114000
|
if (ctx.sandbox) {
|
|
113520
114001
|
try {
|
|
113521
114002
|
const ssmOpts = {};
|
|
@@ -113908,7 +114389,7 @@ search with flags or a more specific directory if results are truncated.`,
|
|
|
113908
114389
|
init_dist();
|
|
113909
114390
|
init_zod();
|
|
113910
114391
|
import { existsSync as existsSync10, mkdirSync as mkdirSync9, writeFileSync as writeFileSync11 } from "node:fs";
|
|
113911
|
-
import { join as
|
|
114392
|
+
import { join as join16 } from "node:path";
|
|
113912
114393
|
var MAX_INLINE_BODY = 5000;
|
|
113913
114394
|
var promptInjectionRefSchema = exports_external.object({
|
|
113914
114395
|
kind: exports_external.literal("prompt_injection_ref"),
|
|
@@ -113938,13 +114419,13 @@ function containsPromptInjectionRef(value) {
|
|
|
113938
114419
|
function maybeSaveBody(body, ctx) {
|
|
113939
114420
|
if (body.length <= MAX_INLINE_BODY)
|
|
113940
114421
|
return { text: body };
|
|
113941
|
-
const outputDir =
|
|
114422
|
+
const outputDir = join16(agentLogsDir(ctx), "http-responses");
|
|
113942
114423
|
if (!existsSync10(outputDir)) {
|
|
113943
114424
|
mkdirSync9(outputDir, { recursive: true });
|
|
113944
114425
|
}
|
|
113945
114426
|
const ts = new Date().toISOString().replace(/[:.]/g, "-");
|
|
113946
114427
|
const filename = `response-${ts}.txt`;
|
|
113947
|
-
const filePath =
|
|
114428
|
+
const filePath = join16(outputDir, filename);
|
|
113948
114429
|
try {
|
|
113949
114430
|
writeFileSync11(filePath, body);
|
|
113950
114431
|
} catch {
|
|
@@ -114009,6 +114490,7 @@ COMMON TESTING PATTERNS:
|
|
|
114009
114490
|
followRedirects,
|
|
114010
114491
|
timeout
|
|
114011
114492
|
}) => {
|
|
114493
|
+
let headers = parseHeaders(rawHeaders);
|
|
114012
114494
|
try {
|
|
114013
114495
|
assertUrlInScope(url, ctx);
|
|
114014
114496
|
} catch (e) {
|
|
@@ -114027,7 +114509,6 @@ COMMON TESTING PATTERNS:
|
|
|
114027
114509
|
}
|
|
114028
114510
|
throw e;
|
|
114029
114511
|
}
|
|
114030
|
-
let headers = parseHeaders(rawHeaders);
|
|
114031
114512
|
let resolvedBody;
|
|
114032
114513
|
let library = EMPTY_PROMPT_INJECTION_LIBRARY;
|
|
114033
114514
|
try {
|
|
@@ -114038,6 +114519,8 @@ COMMON TESTING PATTERNS:
|
|
|
114038
114519
|
}) : EMPTY_PROMPT_INJECTION_LIBRARY;
|
|
114039
114520
|
headers = resolvePromptInjectionRefs(headers, library);
|
|
114040
114521
|
resolvedBody = body === undefined ? undefined : String(resolvePromptInjectionRefs(body, library));
|
|
114522
|
+
const effectiveHeaders = resolveEffectiveHeaders(resolverSessionFromCtx(ctx), url, headers);
|
|
114523
|
+
assertHttpActionAllowed({ method, url, body: resolvedBody, headers: effectiveHeaders }, ctx);
|
|
114041
114524
|
} catch (e) {
|
|
114042
114525
|
return {
|
|
114043
114526
|
success: false,
|
|
@@ -114137,17 +114620,17 @@ COMMON TESTING PATTERNS:
|
|
|
114137
114620
|
}
|
|
114138
114621
|
async function executeSandboxHttpRequest(ctx, opts, library) {
|
|
114139
114622
|
const { url, method, headers, body, followRedirects, timeout } = opts;
|
|
114623
|
+
const { sandbox } = ctx;
|
|
114624
|
+
if (!sandbox) {
|
|
114625
|
+
throw new Error("executeSandboxHttpRequest requires a sandbox");
|
|
114626
|
+
}
|
|
114627
|
+
let bodyTempFile = null;
|
|
114140
114628
|
try {
|
|
114141
114629
|
let curlCommand = `curl -i -X ${method}`;
|
|
114142
114630
|
const mergedHeaders = resolveEffectiveHeaders(resolverSessionFromCtx(ctx), url, headers);
|
|
114143
114631
|
for (const [key, value] of Object.entries(mergedHeaders)) {
|
|
114144
114632
|
curlCommand += ` -H "${shellQuote(`${key}: ${value}`)}"`;
|
|
114145
114633
|
}
|
|
114146
|
-
const { sandbox } = ctx;
|
|
114147
|
-
if (!sandbox) {
|
|
114148
|
-
throw new Error("executeSandboxHttpRequest requires a sandbox");
|
|
114149
|
-
}
|
|
114150
|
-
let bodyTempFile = null;
|
|
114151
114634
|
if (body && ["POST", "PUT", "PATCH"].includes(method)) {
|
|
114152
114635
|
bodyTempFile = `/tmp/apex_http_body_${Date.now()}_${Math.random().toString(36).slice(2, 11)}.txt`;
|
|
114153
114636
|
const escapedForPrintf = body.replace(/\\/g, "\\\\").replace(/%/g, "%%");
|
|
@@ -114233,6 +114716,10 @@ async function executeSandboxHttpRequest(ctx, opts, library) {
|
|
|
114233
114716
|
url,
|
|
114234
114717
|
redirected: false
|
|
114235
114718
|
};
|
|
114719
|
+
} finally {
|
|
114720
|
+
if (bodyTempFile) {
|
|
114721
|
+
await sandbox.execute(`rm -f ${bodyTempFile}`, { timeout: 10 }).catch(() => {});
|
|
114722
|
+
}
|
|
114236
114723
|
}
|
|
114237
114724
|
}
|
|
114238
114725
|
|
|
@@ -114240,7 +114727,7 @@ async function executeSandboxHttpRequest(ctx, opts, library) {
|
|
|
114240
114727
|
init_dist();
|
|
114241
114728
|
init_zod();
|
|
114242
114729
|
import { readdir, stat } from "node:fs/promises";
|
|
114243
|
-
import { isAbsolute as isAbsolute3, join as
|
|
114730
|
+
import { isAbsolute as isAbsolute3, join as join17, relative as relative2, resolve as resolve3 } from "node:path";
|
|
114244
114731
|
var listFilesInputSchema = exports_external.object({
|
|
114245
114732
|
directory: exports_external.string().optional().describe("Absolute or relative path to the directory to list (defaults to current working directory)"),
|
|
114246
114733
|
recursive: exports_external.boolean().optional().describe("If true, list files recursively (default: false)"),
|
|
@@ -114260,7 +114747,7 @@ async function listRecursive(dir, maxEntries) {
|
|
|
114260
114747
|
}
|
|
114261
114748
|
for (const entry of entries) {
|
|
114262
114749
|
total++;
|
|
114263
|
-
const fullPath =
|
|
114750
|
+
const fullPath = join17(current, entry.name);
|
|
114264
114751
|
if (entry.isDirectory()) {
|
|
114265
114752
|
if (results.length < maxEntries)
|
|
114266
114753
|
results.push(`${fullPath}/`);
|
|
@@ -114323,7 +114810,7 @@ Each directory entry is suffixed with "/" for easy identification.`,
|
|
|
114323
114810
|
}
|
|
114324
114811
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
114325
114812
|
const fullPaths = entries.map((e) => {
|
|
114326
|
-
const name =
|
|
114813
|
+
const name = join17(dir, e.name);
|
|
114327
114814
|
return e.isDirectory() ? `${name}/` : name;
|
|
114328
114815
|
});
|
|
114329
114816
|
const capped = fullPaths.slice(0, MAX_NON_RECURSIVE);
|
|
@@ -114465,9 +114952,9 @@ import {
|
|
|
114465
114952
|
unlinkSync as unlinkSync2
|
|
114466
114953
|
} from "node:fs";
|
|
114467
114954
|
import { tmpdir } from "node:os";
|
|
114468
|
-
import { join as
|
|
114955
|
+
import { join as join18 } from "node:path";
|
|
114469
114956
|
var MAX_BUFFER = 5000000;
|
|
114470
|
-
var APEX_TMP_ROOT =
|
|
114957
|
+
var APEX_TMP_ROOT = join18(tmpdir(), `apex-shell-${process.pid}`);
|
|
114471
114958
|
try {
|
|
114472
114959
|
mkdirSync10(APEX_TMP_ROOT, { recursive: true });
|
|
114473
114960
|
} catch {}
|
|
@@ -114739,8 +115226,8 @@ ${commandOutput}`;
|
|
|
114739
115226
|
const marker = `__APEX_${nonceHex}__`;
|
|
114740
115227
|
const exitMarkerPrefix = `${marker}_EXIT_`;
|
|
114741
115228
|
const cutoverMarker = `${marker}_CUTOVER`;
|
|
114742
|
-
const outPath =
|
|
114743
|
-
const errPath =
|
|
115229
|
+
const outPath = join18(APEX_TMP_ROOT, `${nonceHex}.out`);
|
|
115230
|
+
const errPath = join18(APEX_TMP_ROOT, `${nonceHex}.err`);
|
|
114744
115231
|
const pending = {
|
|
114745
115232
|
streamedStdout: "",
|
|
114746
115233
|
authoritativeStdout: "",
|
|
@@ -115159,7 +115646,7 @@ Returns discovered endpoints and recommended login approach.`,
|
|
|
115159
115646
|
init_dist();
|
|
115160
115647
|
init_zod();
|
|
115161
115648
|
import { writeFileSync as writeFileSync12 } from "node:fs";
|
|
115162
|
-
import { join as
|
|
115649
|
+
import { join as join19 } from "node:path";
|
|
115163
115650
|
function provideComparisonResults(ctx) {
|
|
115164
115651
|
return tool({
|
|
115165
115652
|
description: `Provide the final comparison results with matched, missed, and extra findings.
|
|
@@ -115205,7 +115692,7 @@ Results will be saved to: comparison-results.json in the session directory.`,
|
|
|
115205
115692
|
recall,
|
|
115206
115693
|
precision
|
|
115207
115694
|
};
|
|
115208
|
-
const resultsPath =
|
|
115695
|
+
const resultsPath = join19(ctx.session.rootPath, "comparison-results.json");
|
|
115209
115696
|
writeFileSync12(resultsPath, JSON.stringify(result, null, 2));
|
|
115210
115697
|
return {
|
|
115211
115698
|
success: true,
|
|
@@ -115363,6 +115850,7 @@ function createResponseTool(responseSchema, onResult) {
|
|
|
115363
115850
|
// src/core/agents/offSecAgent/tools/runAttackSurface.ts
|
|
115364
115851
|
init_dist();
|
|
115365
115852
|
init_zod();
|
|
115853
|
+
init_id();
|
|
115366
115854
|
init_structured();
|
|
115367
115855
|
init_lazyLogger();
|
|
115368
115856
|
var log8 = scopedLogger(() => createLogger("run_attack_surface"));
|
|
@@ -115394,15 +115882,17 @@ should be passed directly to spawn_pentest_swarm for deep testing.`,
|
|
|
115394
115882
|
message: "run_attack_surface requires a model in the tool context."
|
|
115395
115883
|
};
|
|
115396
115884
|
}
|
|
115397
|
-
const
|
|
115885
|
+
const subagentName = "Attack Surface";
|
|
115886
|
+
const subagentId = cwd ? newSessionId() : "attack-surface-agent";
|
|
115398
115887
|
ctx.eventBus?.emit("subagent-spawn", {
|
|
115399
115888
|
subagentId,
|
|
115889
|
+
name: subagentName,
|
|
115400
115890
|
input: { target, cwd },
|
|
115401
115891
|
parentSubagentId: ctx.subagentId
|
|
115402
115892
|
});
|
|
115403
115893
|
if (cwd) {
|
|
115404
115894
|
try {
|
|
115405
|
-
const { WhiteboxAttackSurfaceAgent } = await import("./index-
|
|
115895
|
+
const { WhiteboxAttackSurfaceAgent } = await import("./index-pxwwcefn.js");
|
|
115406
115896
|
const localBus = new AgentEventBus;
|
|
115407
115897
|
AgentEventBus.attachChild(localBus, ctx.eventBus, subagentId);
|
|
115408
115898
|
const agent = new WhiteboxAttackSurfaceAgent({
|
|
@@ -115413,14 +115903,19 @@ should be passed directly to spawn_pentest_swarm for deep testing.`,
|
|
|
115413
115903
|
abortSignal: ctx.abortSignal,
|
|
115414
115904
|
attackSurfaceRegistry: ctx.attackSurfaceRegistry,
|
|
115415
115905
|
eventBus: localBus,
|
|
115416
|
-
subagentId
|
|
115906
|
+
subagentId,
|
|
115907
|
+
subagentName
|
|
115417
115908
|
});
|
|
115418
115909
|
const result = await agent.consume();
|
|
115419
|
-
const targets = result.apps.flatMap((app) => [...app.pages, ...app.apiEndpoints].map((ep) =>
|
|
115420
|
-
|
|
115421
|
-
|
|
115422
|
-
|
|
115423
|
-
|
|
115910
|
+
const targets = result.apps.flatMap((app) => [...app.pages, ...app.apiEndpoints].map((ep) => {
|
|
115911
|
+
const grpc = toGrpcPentestContext(ep.transport, ep.grpc, ep.path);
|
|
115912
|
+
return {
|
|
115913
|
+
target: grpcAuthorityTarget(grpc, ep.path) ?? (ep.path.startsWith("http") ? ep.path : `${target}${ep.path}`),
|
|
115914
|
+
objective: ep.pentestObjectives.join("; "),
|
|
115915
|
+
rationale: `${app.framework} ${ep.method} endpoint in ${app.name} (${ep.file}${ep.line ? `:${ep.line}` : ""})`,
|
|
115916
|
+
grpc
|
|
115917
|
+
};
|
|
115918
|
+
}));
|
|
115424
115919
|
log8.info(`Whitebox attack surface complete: ${targets.length} targets from ${result.apps.length} apps`);
|
|
115425
115920
|
ctx.eventBus?.emit("subagent-complete", {
|
|
115426
115921
|
subagentId,
|
|
@@ -115452,7 +115947,7 @@ should be passed directly to spawn_pentest_swarm for deep testing.`,
|
|
|
115452
115947
|
}
|
|
115453
115948
|
}
|
|
115454
115949
|
try {
|
|
115455
|
-
const { BlackboxAttackSurfaceAgent } = await import("./blackboxAgent-
|
|
115950
|
+
const { BlackboxAttackSurfaceAgent } = await import("./blackboxAgent-d0smgqt7.js");
|
|
115456
115951
|
const localBus = new AgentEventBus;
|
|
115457
115952
|
AgentEventBus.attachChild(localBus, ctx.eventBus, subagentId);
|
|
115458
115953
|
const agent = new BlackboxAttackSurfaceAgent({
|
|
@@ -115530,7 +116025,7 @@ Omit \`cwd\` for blackbox mode (live target probing only).`,
|
|
|
115530
116025
|
toolCallDescription: exports_external.string().describe("A concise, human-readable description of what this tool call is doing")
|
|
115531
116026
|
}),
|
|
115532
116027
|
execute: async ({ target, cwd }) => {
|
|
115533
|
-
const { runPentestWorkflow: workflow } = await import("./pentest-
|
|
116028
|
+
const { runPentestWorkflow: workflow } = await import("./pentest-1cb5t0dt.js");
|
|
115534
116029
|
if (!ctx.model) {
|
|
115535
116030
|
return {
|
|
115536
116031
|
success: false,
|
|
@@ -115548,6 +116043,7 @@ Omit \`cwd\` for blackbox mode (live target probing only).`,
|
|
|
115548
116043
|
abortSignal: ctx.abortSignal,
|
|
115549
116044
|
eventBus: ctx.eventBus,
|
|
115550
116045
|
enableThinking: ctx.enableThinking,
|
|
116046
|
+
thinkingEffort: ctx.thinkingEffort,
|
|
115551
116047
|
openAIReasoningEffort: ctx.openAIReasoningEffort,
|
|
115552
116048
|
surfaceIntegrationEnabled: ctx.surfaceIntegrationEnabled
|
|
115553
116049
|
});
|
|
@@ -115636,11 +116132,11 @@ init_id();
|
|
|
115636
116132
|
|
|
115637
116133
|
// src/core/whitebox/adapters.ts
|
|
115638
116134
|
import { existsSync as existsSync12 } from "node:fs";
|
|
115639
|
-
import { join as
|
|
116135
|
+
import { join as join21 } from "node:path";
|
|
115640
116136
|
|
|
115641
116137
|
// src/core/whitebox/artifacts.ts
|
|
115642
116138
|
import { mkdir as mkdir2, readFile as readFile3, writeFile as writeFile2 } from "node:fs/promises";
|
|
115643
|
-
import { basename as basename2, join as
|
|
116139
|
+
import { basename as basename2, join as join20 } from "node:path";
|
|
115644
116140
|
|
|
115645
116141
|
// src/core/whitebox/paths.ts
|
|
115646
116142
|
import { existsSync as existsSync11, realpathSync } from "node:fs";
|
|
@@ -115701,10 +116197,10 @@ function safeName(value) {
|
|
|
115701
116197
|
return value.toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/\.{2,}/g, ".").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
115702
116198
|
}
|
|
115703
116199
|
function getWhiteboxLogsDir(session) {
|
|
115704
|
-
return
|
|
116200
|
+
return join20(session.logsPath, "whitebox");
|
|
115705
116201
|
}
|
|
115706
116202
|
function getWhiteboxScratchDir(session) {
|
|
115707
|
-
return
|
|
116203
|
+
return join20(session.scratchpadPath, "whitebox");
|
|
115708
116204
|
}
|
|
115709
116205
|
async function ensureWhiteboxDirs(session) {
|
|
115710
116206
|
await Promise.all([
|
|
@@ -115717,7 +116213,7 @@ async function writeWhiteboxArtifact(input) {
|
|
|
115717
116213
|
const baseDir = input.area === "scratchpad" ? getWhiteboxScratchDir(input.session) : getWhiteboxLogsDir(input.session);
|
|
115718
116214
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
|
|
115719
116215
|
const filename = `${timestamp}-${safeName(input.name)}${input.extension ?? ".txt"}`;
|
|
115720
|
-
const absolutePath =
|
|
116216
|
+
const absolutePath = join20(baseDir, filename);
|
|
115721
116217
|
await writeFile2(absolutePath, input.content, "utf-8");
|
|
115722
116218
|
const relativeRoot = input.area === "scratchpad" ? "scratchpad/whitebox" : "logs/whitebox";
|
|
115723
116219
|
return {
|
|
@@ -115959,7 +116455,7 @@ var WHITEBOX_SCAN_ADAPTERS = [
|
|
|
115959
116455
|
id: "npm-audit",
|
|
115960
116456
|
kind: "dependencies",
|
|
115961
116457
|
tool: "npm",
|
|
115962
|
-
detect: (profile) => hasTool(profile, "npm") && (profile.packageManagers.includes("npm") || existsSync12(
|
|
116458
|
+
detect: (profile) => hasTool(profile, "npm") && (profile.packageManagers.includes("npm") || existsSync12(join21(profile.rootPath, "package-lock.json"))),
|
|
115963
116459
|
buildCommand: () => ["npm", "audit", "--json"],
|
|
115964
116460
|
parseSummary: (raw) => simpleLineFindings("npm audit", raw)
|
|
115965
116461
|
},
|
|
@@ -116068,7 +116564,7 @@ ${raw.stderr}` : "");
|
|
|
116068
116564
|
// src/core/whitebox/candidates.ts
|
|
116069
116565
|
import { existsSync as existsSync13 } from "node:fs";
|
|
116070
116566
|
import { mkdir as mkdir3, readFile as readFile4, writeFile as writeFile3 } from "node:fs/promises";
|
|
116071
|
-
import { join as
|
|
116567
|
+
import { join as join22 } from "node:path";
|
|
116072
116568
|
var CANDIDATES_FILE = "candidates.json";
|
|
116073
116569
|
var writeLocks = new Map;
|
|
116074
116570
|
function withCandidateLock(session, fn) {
|
|
@@ -116095,10 +116591,10 @@ var ALLOWED_TRANSITIONS = {
|
|
|
116095
116591
|
deferred: ["hypothesis", "investigating"]
|
|
116096
116592
|
};
|
|
116097
116593
|
function candidatesDir(session) {
|
|
116098
|
-
return
|
|
116594
|
+
return join22(session.scratchpadPath, "whitebox");
|
|
116099
116595
|
}
|
|
116100
116596
|
function candidatesPath(session) {
|
|
116101
|
-
return
|
|
116597
|
+
return join22(candidatesDir(session), CANDIDATES_FILE);
|
|
116102
116598
|
}
|
|
116103
116599
|
function makeId2(title) {
|
|
116104
116600
|
const slug = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 48);
|
|
@@ -116568,7 +117064,7 @@ import {
|
|
|
116568
117064
|
readSync as readSync2,
|
|
116569
117065
|
statSync as statSync4
|
|
116570
117066
|
} from "node:fs";
|
|
116571
|
-
import { join as
|
|
117067
|
+
import { join as join23 } from "node:path";
|
|
116572
117068
|
var MAX_JOB_LOG_INLINE = 40000;
|
|
116573
117069
|
var MAX_JOB_LOG_BYTES = 10 * 1024 * 1024;
|
|
116574
117070
|
var PRUNE_AFTER_MS = 60000;
|
|
@@ -116643,7 +117139,7 @@ function startWhiteboxJob(input) {
|
|
|
116643
117139
|
const logsDir = getWhiteboxLogsDir(input.session);
|
|
116644
117140
|
mkdirSync11(logsDir, { recursive: true });
|
|
116645
117141
|
const safeName2 = (input.name ?? "job").replace(/[^a-z0-9._-]+/gi, "-").replace(/\.{2,}/g, ".");
|
|
116646
|
-
const logPath =
|
|
117142
|
+
const logPath = join23(logsDir, `${id}-${safeName2}.log`);
|
|
116647
117143
|
const now = new Date().toISOString();
|
|
116648
117144
|
writeLog(logPath, `$ ${input.command}
|
|
116649
117145
|
|
|
@@ -116772,7 +117268,7 @@ function readWhiteboxJobLog(id, sessionId) {
|
|
|
116772
117268
|
import { execFile as execFile2 } from "node:child_process";
|
|
116773
117269
|
import { existsSync as existsSync15, realpathSync as realpathSync2 } from "node:fs";
|
|
116774
117270
|
import { readdir as readdir2, readFile as readFile5, stat as stat2 } from "node:fs/promises";
|
|
116775
|
-
import { basename as basename3, extname as extname2, join as
|
|
117271
|
+
import { basename as basename3, extname as extname2, join as join24, relative as relative4, resolve as resolve6 } from "node:path";
|
|
116776
117272
|
import { promisify as promisify2 } from "node:util";
|
|
116777
117273
|
var execFileAsync2 = promisify2(execFile2);
|
|
116778
117274
|
var MAX_PROFILE_FILES = 5000;
|
|
@@ -116881,7 +117377,7 @@ async function walkFiles(rootPath) {
|
|
|
116881
117377
|
for (const entry of entries) {
|
|
116882
117378
|
if (files.length >= MAX_PROFILE_FILES)
|
|
116883
117379
|
return;
|
|
116884
|
-
const fullPath =
|
|
117380
|
+
const fullPath = join24(current, entry.name);
|
|
116885
117381
|
if (entry.isDirectory()) {
|
|
116886
117382
|
if (shouldSkipDir(entry.name))
|
|
116887
117383
|
continue;
|
|
@@ -116943,7 +117439,7 @@ function detectEntryHints(files) {
|
|
|
116943
117439
|
return hints.slice(0, 100);
|
|
116944
117440
|
}
|
|
116945
117441
|
async function readPackageScripts(rootPath) {
|
|
116946
|
-
const packageJsonPath =
|
|
117442
|
+
const packageJsonPath = join24(rootPath, "package.json");
|
|
116947
117443
|
if (!existsSync15(packageJsonPath)) {
|
|
116948
117444
|
return { buildCommands: [], testCommands: [], runCommands: [] };
|
|
116949
117445
|
}
|
|
@@ -117107,7 +117603,7 @@ Returns an array of results with the text output from each agent.`,
|
|
|
117107
117603
|
});
|
|
117108
117604
|
}
|
|
117109
117605
|
async function runSingleCodingAgent(ctx, codebasePath, objective, agentIndex, name) {
|
|
117110
|
-
const { CodeAgent } = await import("./agent-
|
|
117606
|
+
const { CodeAgent } = await import("./agent-3cdfwxcd.js");
|
|
117111
117607
|
const childSessionId = newSessionId();
|
|
117112
117608
|
const subagentId = childSessionId;
|
|
117113
117609
|
ctx.eventBus?.emit("subagent-spawn", {
|
|
@@ -117133,7 +117629,9 @@ async function runSingleCodingAgent(ctx, codebasePath, objective, agentIndex, na
|
|
|
117133
117629
|
abortSignal: ctx.abortSignal,
|
|
117134
117630
|
eventBus: localBus,
|
|
117135
117631
|
subagentId,
|
|
117632
|
+
subagentName: name,
|
|
117136
117633
|
enableThinking: ctx.enableThinking,
|
|
117634
|
+
thinkingEffort: ctx.thinkingEffort,
|
|
117137
117635
|
openAIReasoningEffort: ctx.openAIReasoningEffort
|
|
117138
117636
|
});
|
|
117139
117637
|
try {
|
|
@@ -117164,7 +117662,7 @@ init_ai();
|
|
|
117164
117662
|
init_structured();
|
|
117165
117663
|
init_lazyLogger();
|
|
117166
117664
|
import { existsSync as existsSync16, readdirSync as readdirSync4, readFileSync as readFileSync6 } from "node:fs";
|
|
117167
|
-
import { join as
|
|
117665
|
+
import { join as join25 } from "node:path";
|
|
117168
117666
|
var log9 = scopedLogger(() => createLogger("findings:registry"));
|
|
117169
117667
|
var VULN_CLASS_PATTERNS = [
|
|
117170
117668
|
[/sql\s*injection/i, "sql-injection"],
|
|
@@ -117356,7 +117854,7 @@ class FindingsRegistry {
|
|
|
117356
117854
|
log9.debug(`fromDirectory: path=${findingsPath}, jsonFiles=${files.length}`);
|
|
117357
117855
|
for (const file of files) {
|
|
117358
117856
|
try {
|
|
117359
|
-
const raw = readFileSync6(
|
|
117857
|
+
const raw = readFileSync6(join25(findingsPath, file), "utf-8");
|
|
117360
117858
|
const finding = JSON.parse(raw);
|
|
117361
117859
|
if (finding && typeof finding.title === "string" && typeof finding.endpoint === "string") {
|
|
117362
117860
|
registry.indexFinding(finding);
|
|
@@ -117561,13 +118059,13 @@ class FindingsRegistry {
|
|
|
117561
118059
|
|
|
117562
118060
|
// src/core/plan/index.ts
|
|
117563
118061
|
import { existsSync as existsSync17, readFileSync as readFileSync7 } from "node:fs";
|
|
117564
|
-
import { join as
|
|
118062
|
+
import { join as join26 } from "node:path";
|
|
117565
118063
|
var PLAN_FILENAME = "plan.md";
|
|
117566
118064
|
function planFilePath(sessionRootPath, subagentId) {
|
|
117567
118065
|
if (subagentId) {
|
|
117568
|
-
return
|
|
118066
|
+
return join26(sessionRootPath, "subagents", `${subagentId}-plan.md`);
|
|
117569
118067
|
}
|
|
117570
|
-
return
|
|
118068
|
+
return join26(sessionRootPath, PLAN_FILENAME);
|
|
117571
118069
|
}
|
|
117572
118070
|
function readPlan(sessionRootPath, subagentId) {
|
|
117573
118071
|
const path = planFilePath(sessionRootPath, subagentId);
|
|
@@ -117622,7 +118120,7 @@ Returns the worker's summary, objective results, and finding count — but NOT t
|
|
|
117622
118120
|
message: "spawn_pentest_agent requires a model in the tool context."
|
|
117623
118121
|
};
|
|
117624
118122
|
}
|
|
117625
|
-
const { TargetedPentestAgent } = await import("./agent-
|
|
118123
|
+
const { TargetedPentestAgent } = await import("./agent-q5hwjdtb.js");
|
|
117626
118124
|
const findingsRegistry = ctx.findingsRegistry ?? FindingsRegistry.fromDirectory(ctx.session.findingsPath, {
|
|
117627
118125
|
model: ctx.model,
|
|
117628
118126
|
authConfig: ctx.authConfig,
|
|
@@ -117652,6 +118150,7 @@ Returns the worker's summary, objective results, and finding count — but NOT t
|
|
|
117652
118150
|
try {
|
|
117653
118151
|
agent = new TargetedPentestAgent({
|
|
117654
118152
|
target,
|
|
118153
|
+
grpc: workerInheritsGrpc(target, ctx.grpc, ctx.target) ? ctx.grpc : undefined,
|
|
117655
118154
|
objectives,
|
|
117656
118155
|
context: enrichedContext,
|
|
117657
118156
|
model: ctx.model,
|
|
@@ -117661,8 +118160,11 @@ Returns the worker's summary, objective results, and finding count — but NOT t
|
|
|
117661
118160
|
findingsRegistry,
|
|
117662
118161
|
eventBus: childBus,
|
|
117663
118162
|
subagentId,
|
|
118163
|
+
subagentName: name,
|
|
117664
118164
|
sandbox: ctx.sandbox,
|
|
118165
|
+
secretValues: ctx.secretValues,
|
|
117665
118166
|
enableThinking: ctx.enableThinking,
|
|
118167
|
+
thinkingEffort: ctx.thinkingEffort,
|
|
117666
118168
|
openAIReasoningEffort: ctx.openAIReasoningEffort,
|
|
117667
118169
|
role: "worker",
|
|
117668
118170
|
browserSession: sharedBrowserSession,
|
|
@@ -117703,6 +118205,13 @@ Returns the worker's summary, objective results, and finding count — but NOT t
|
|
|
117703
118205
|
}
|
|
117704
118206
|
});
|
|
117705
118207
|
}
|
|
118208
|
+
function workerInheritsGrpc(target, grpc, orchestratorTarget) {
|
|
118209
|
+
if (!grpc)
|
|
118210
|
+
return false;
|
|
118211
|
+
if (orchestratorTarget && target === orchestratorTarget)
|
|
118212
|
+
return true;
|
|
118213
|
+
return target.includes(`${grpc.serviceFqn}/${grpc.method}`);
|
|
118214
|
+
}
|
|
117706
118215
|
function buildSharedBrowserSessionContext(existingContext) {
|
|
117707
118216
|
const note = `## Shared Browser Session
|
|
117708
118217
|
You are driving the orchestrator's live Playwright browser (NOT a private copy):
|
|
@@ -117739,12 +118248,13 @@ Pass every target you want tested — the swarm handles concurrency automaticall
|
|
|
117739
118248
|
targets: exports_external.array(exports_external.object({
|
|
117740
118249
|
name: exports_external.string().optional().describe("Short human-readable label for this agent shown in the UI (e.g. 'SQLi /api/users', 'IDOR orders')"),
|
|
117741
118250
|
target: exports_external.string().describe("Full target URL including endpoint to test"),
|
|
117742
|
-
objectives: exports_external.array(exports_external.string()).describe("Testing objectives for this target (e.g., 'Test for SQL injection on /api/users', 'Check IDOR on /api/orders/{id}')")
|
|
118251
|
+
objectives: exports_external.array(exports_external.string()).describe("Testing objectives for this target (e.g., 'Test for SQL injection on /api/users', 'Check IDOR on /api/orders/{id}')"),
|
|
118252
|
+
grpc: GrpcPentestContextSchema.optional().describe("gRPC method context for gRPC/Connect targets — pass through the `grpc` object from run_attack_surface so the agent runs the gRPC test battery instead of HTTP tests.")
|
|
117743
118253
|
})).describe("Array of targets with their testing objectives"),
|
|
117744
118254
|
toolCallDescription: exports_external.string().describe("A concise, human-readable description of what this tool call is doing")
|
|
117745
118255
|
}),
|
|
117746
118256
|
execute: async ({ targets }) => {
|
|
117747
|
-
const { runPentestSwarm, DEFAULT_CONCURRENCY: DEFAULT_CONCURRENCY2 } = await import("./pentest-
|
|
118257
|
+
const { runPentestSwarm, DEFAULT_CONCURRENCY: DEFAULT_CONCURRENCY2 } = await import("./pentest-1cb5t0dt.js");
|
|
117748
118258
|
if (!ctx.model) {
|
|
117749
118259
|
return {
|
|
117750
118260
|
success: false,
|
|
@@ -117768,6 +118278,7 @@ Pass every target you want tested — the swarm handles concurrency automaticall
|
|
|
117768
118278
|
eventBus: ctx.eventBus,
|
|
117769
118279
|
concurrency: DEFAULT_CONCURRENCY2,
|
|
117770
118280
|
enableThinking: ctx.enableThinking,
|
|
118281
|
+
thinkingEffort: ctx.thinkingEffort,
|
|
117771
118282
|
openAIReasoningEffort: ctx.openAIReasoningEffort,
|
|
117772
118283
|
display: ctx.display
|
|
117773
118284
|
});
|
|
@@ -119428,6 +119939,30 @@ var ALL_TOOL_NAMES = [
|
|
|
119428
119939
|
"submit_plan",
|
|
119429
119940
|
ASK_USER_QUESTIONS_TOOL_NAME
|
|
119430
119941
|
];
|
|
119942
|
+
var FAST_STRIKE_EXCLUDED_TOOL_NAMES = [
|
|
119943
|
+
"run_attack_surface",
|
|
119944
|
+
"spawn_pentest_swarm",
|
|
119945
|
+
"spawn_pentest_agent",
|
|
119946
|
+
"spawn_coding_agent",
|
|
119947
|
+
"run_pentest_workflow",
|
|
119948
|
+
"delegate_to_auth_subagent",
|
|
119949
|
+
"run_whitebox_scan",
|
|
119950
|
+
"create_whitebox_candidate",
|
|
119951
|
+
"update_whitebox_candidate",
|
|
119952
|
+
"list_whitebox_candidates",
|
|
119953
|
+
"start_whitebox_job",
|
|
119954
|
+
"poll_whitebox_job",
|
|
119955
|
+
"stop_whitebox_job",
|
|
119956
|
+
"read_whitebox_artifact",
|
|
119957
|
+
"write_plan",
|
|
119958
|
+
"submit_plan",
|
|
119959
|
+
"create_task",
|
|
119960
|
+
"update_task",
|
|
119961
|
+
"list_tasks",
|
|
119962
|
+
"create_attack_surface_report",
|
|
119963
|
+
"provide_comparison_results",
|
|
119964
|
+
ASK_USER_QUESTIONS_TOOL_NAME
|
|
119965
|
+
];
|
|
119431
119966
|
var PLAN_MODE_TOOL_NAMES = [
|
|
119432
119967
|
"browser_navigate",
|
|
119433
119968
|
"browser_snapshot",
|
|
@@ -119677,7 +120212,7 @@ init_dist();
|
|
|
119677
120212
|
init_ai();
|
|
119678
120213
|
import { existsSync as existsSync18, mkdirSync as mkdirSync14, readFileSync as readFileSync8 } from "node:fs";
|
|
119679
120214
|
import { writeFile as writeFile6 } from "node:fs/promises";
|
|
119680
|
-
import { join as
|
|
120215
|
+
import { join as join27 } from "node:path";
|
|
119681
120216
|
init_id();
|
|
119682
120217
|
init_structured();
|
|
119683
120218
|
init_observability();
|
|
@@ -119993,6 +120528,7 @@ class OffensiveSecurityAgent {
|
|
|
119993
120528
|
_drainRejection = new Promise(() => {});
|
|
119994
120529
|
drained = Promise.resolve();
|
|
119995
120530
|
subagentId;
|
|
120531
|
+
subagentName;
|
|
119996
120532
|
currentMessageId = null;
|
|
119997
120533
|
persistentShell;
|
|
119998
120534
|
browserSession;
|
|
@@ -120028,6 +120564,7 @@ class OffensiveSecurityAgent {
|
|
|
120028
120564
|
constructor(input) {
|
|
120029
120565
|
this._session = input.session;
|
|
120030
120566
|
this.subagentId = input.subagentId;
|
|
120567
|
+
this.subagentName = input.subagentName;
|
|
120031
120568
|
this.abortSignal = input.abortSignal;
|
|
120032
120569
|
this.userPrompt = input.prompt;
|
|
120033
120570
|
this.eventBus = input.eventBus ?? new AgentEventBus;
|
|
@@ -120049,23 +120586,33 @@ class OffensiveSecurityAgent {
|
|
|
120049
120586
|
extraHttpHeaders: stripBrowserManagedHeaders(sessionHeaders),
|
|
120050
120587
|
display: input.display
|
|
120051
120588
|
});
|
|
120589
|
+
if (this.ownsBrowserSession && this.abortSignal) {
|
|
120590
|
+
const onAbort = () => {
|
|
120591
|
+
this.disconnectOwnedBrowser();
|
|
120592
|
+
};
|
|
120593
|
+
if (this.abortSignal.aborted)
|
|
120594
|
+
onAbort();
|
|
120595
|
+
else
|
|
120596
|
+
this.abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
120597
|
+
}
|
|
120052
120598
|
} else {
|
|
120053
120599
|
this.ownsBrowserSession = false;
|
|
120054
120600
|
}
|
|
120055
|
-
const messagesDir = input.messagesDir ?? (input.subagentId ?
|
|
120056
|
-
const tracePath = input.subagentId ?
|
|
120601
|
+
const messagesDir = input.messagesDir ?? (input.subagentId ? join27(input.session.rootPath, "subagents", input.subagentId) : input.session.rootPath);
|
|
120602
|
+
const tracePath = input.subagentId ? join27(input.session.rootPath, "subagents", `${input.subagentId}.trace.jsonl`) : join27(messagesDir, "trace.jsonl");
|
|
120057
120603
|
const traceWriter = new StepTraceWriter({
|
|
120058
120604
|
tracePath,
|
|
120059
120605
|
agentId: input.subagentId ?? null,
|
|
120060
120606
|
eventBus: this.eventBus
|
|
120061
120607
|
});
|
|
120062
120608
|
const taskDriven = input.session.config?.taskDriven ?? false;
|
|
120063
|
-
const tasksDir = input.tasksDir ?? (taskDriven ? input.subagentId ?
|
|
120609
|
+
const tasksDir = input.tasksDir ?? (taskDriven ? input.subagentId ? join27(input.session.rootPath, "subagents", `${input.subagentId}-tasks`) : join27(input.session.rootPath, "tasks") : undefined);
|
|
120064
120610
|
const credentialManager = input.credentialManager ?? input.session.credentialManager;
|
|
120065
120611
|
const builtinTools = createAllTools({
|
|
120066
120612
|
session: input.session,
|
|
120067
120613
|
agentCwd,
|
|
120068
120614
|
target: input.target,
|
|
120615
|
+
grpc: input.grpc,
|
|
120069
120616
|
abortSignal: input.abortSignal,
|
|
120070
120617
|
model: input.model,
|
|
120071
120618
|
authConfig: input.authConfig,
|
|
@@ -120074,6 +120621,7 @@ class OffensiveSecurityAgent {
|
|
|
120074
120621
|
findingsRegistry: input.findingsRegistry,
|
|
120075
120622
|
attackSurfaceRegistry: input.attackSurfaceRegistry,
|
|
120076
120623
|
credentialManager,
|
|
120624
|
+
secretValues: input.secretValues,
|
|
120077
120625
|
persistentShell: this.persistentShell,
|
|
120078
120626
|
skillsRegistry: input.skillsRegistry,
|
|
120079
120627
|
promptInjectionLibrary: input.promptInjectionLibrary,
|
|
@@ -120081,6 +120629,7 @@ class OffensiveSecurityAgent {
|
|
|
120081
120629
|
traceWriter,
|
|
120082
120630
|
tasksDir,
|
|
120083
120631
|
enableThinking: input.enableThinking,
|
|
120632
|
+
thinkingEffort: input.thinkingEffort,
|
|
120084
120633
|
openAIReasoningEffort: input.openAIReasoningEffort,
|
|
120085
120634
|
surfaceIntegrationEnabled: input.surfaceIntegrationEnabled,
|
|
120086
120635
|
projectThreatModel: input.projectThreatModel,
|
|
@@ -120157,11 +120706,22 @@ class OffensiveSecurityAgent {
|
|
|
120157
120706
|
if (input.mode === "plan") {
|
|
120158
120707
|
const planSet = new Set(PLAN_MODE_TOOL_NAMES);
|
|
120159
120708
|
activeTools = activeTools.filter((t) => planSet.has(t));
|
|
120709
|
+
} else if (input.mode === "fast-strike") {
|
|
120710
|
+
const excluded = new Set(FAST_STRIKE_EXCLUDED_TOOL_NAMES);
|
|
120711
|
+
activeTools = Object.keys(tools).filter((t) => {
|
|
120712
|
+
if (excluded.has(t))
|
|
120713
|
+
return false;
|
|
120714
|
+
if (!emailToolSet.has(t))
|
|
120715
|
+
return true;
|
|
120716
|
+
if (t === SEND_EMAIL_TOOL_NAME)
|
|
120717
|
+
return hasSmtp;
|
|
120718
|
+
return hasEmail;
|
|
120719
|
+
});
|
|
120160
120720
|
}
|
|
120161
120721
|
if (!existsSync18(messagesDir)) {
|
|
120162
120722
|
mkdirSync14(messagesDir, { recursive: true });
|
|
120163
120723
|
}
|
|
120164
|
-
this.messagesPath =
|
|
120724
|
+
this.messagesPath = join27(messagesDir, "messages.json");
|
|
120165
120725
|
const messagesPath = this.messagesPath;
|
|
120166
120726
|
const initialMessagesRef = {
|
|
120167
120727
|
current: input.messages ? [...input.messages] : [
|
|
@@ -120212,7 +120772,7 @@ class OffensiveSecurityAgent {
|
|
|
120212
120772
|
activeTools,
|
|
120213
120773
|
stopWhen,
|
|
120214
120774
|
toolChoice: "auto",
|
|
120215
|
-
sessionPath:
|
|
120775
|
+
sessionPath: messagesDir,
|
|
120216
120776
|
sessionId: this.busSessionId,
|
|
120217
120777
|
onStepFinish: async (event) => {
|
|
120218
120778
|
this.latestMessages = [
|
|
@@ -120263,6 +120823,7 @@ class OffensiveSecurityAgent {
|
|
|
120263
120823
|
input.onCacheMetrics?.(metrics);
|
|
120264
120824
|
},
|
|
120265
120825
|
enableThinking: input.enableThinking,
|
|
120826
|
+
thinkingEffort: input.thinkingEffort,
|
|
120266
120827
|
openAIReasoningEffort: input.openAIReasoningEffort,
|
|
120267
120828
|
silent: true
|
|
120268
120829
|
});
|
|
@@ -120287,7 +120848,7 @@ class OffensiveSecurityAgent {
|
|
|
120287
120848
|
const runConsume = async () => {
|
|
120288
120849
|
const toolParts = new Map;
|
|
120289
120850
|
const ids = {
|
|
120290
|
-
subagentId: this.
|
|
120851
|
+
subagentId: this.subagentId,
|
|
120291
120852
|
sessionId: this.busSessionId,
|
|
120292
120853
|
messageId: undefined,
|
|
120293
120854
|
textPartId: undefined,
|
|
@@ -120514,10 +121075,11 @@ class OffensiveSecurityAgent {
|
|
|
120514
121075
|
}
|
|
120515
121076
|
return;
|
|
120516
121077
|
};
|
|
120517
|
-
const
|
|
121078
|
+
const spanLabel = this.subagentName ?? sid;
|
|
121079
|
+
const drain = !sid ? runConsume() : withSubagentSessionBaggage(sid, () => getApexTracer().startActiveSpan(`invoke_agent ${spanLabel}`, {
|
|
120518
121080
|
attributes: {
|
|
120519
121081
|
"gen_ai.operation.name": "invoke_agent",
|
|
120520
|
-
"gen_ai.agent.name":
|
|
121082
|
+
"gen_ai.agent.name": spanLabel
|
|
120521
121083
|
}
|
|
120522
121084
|
}, async (span) => {
|
|
120523
121085
|
try {
|
|
@@ -120528,7 +121090,7 @@ class OffensiveSecurityAgent {
|
|
|
120528
121090
|
} finally {
|
|
120529
121091
|
span.end();
|
|
120530
121092
|
}
|
|
120531
|
-
});
|
|
121093
|
+
}));
|
|
120532
121094
|
let rejectDrain;
|
|
120533
121095
|
this._drainRejection = new Promise((_, reject) => {
|
|
120534
121096
|
rejectDrain = reject;
|
|
@@ -120560,6 +121122,10 @@ class OffensiveSecurityAgent {
|
|
|
120560
121122
|
this.browserDisconnected = true;
|
|
120561
121123
|
await this.browserSession.disconnect().catch(() => {});
|
|
120562
121124
|
}
|
|
121125
|
+
async abortAndDrain() {
|
|
121126
|
+
await this.disconnectOwnedBrowser();
|
|
121127
|
+
await this.drained.catch(() => {});
|
|
121128
|
+
}
|
|
120563
121129
|
get response() {
|
|
120564
121130
|
return this.streamResult.response;
|
|
120565
121131
|
}
|
|
@@ -120698,4 +121264,4 @@ function wrapToolsWithApprovalGate(tools, gate, exemptToolNames) {
|
|
|
120698
121264
|
return wrapped;
|
|
120699
121265
|
}
|
|
120700
121266
|
|
|
120701
|
-
export { AgentEventBus, INTERNAL_ID_PATTERN, ApprovalGate, OPERATOR_MODES, OPERATOR_MODE_CYCLE, createInitialOperatorState, buildProvidedFilesSection, buildSessionWorkspaceSection, buildBaseSystemPrompt, BASE_SYSTEM_PROMPT, isMemoryEnabled, addMemory2 as addMemory, ASK_USER_QUESTIONS_TOOL_NAME, AskUserQuestionSchema, transformScriptToFunction, parseStorageStateResult, setHeadlessMode, setUserAgent, setViewportSize, PlaywrightMcpSession, createBrowserTools, ScopeViolationError, getAllowedHosts, isHostAllowed, extractHostname2 as extractHostname, assertUrlInScope, extractHostsFromCommand, assertCommandInScope, checkSandboxPlaywright, installSandboxPlaywright, ensureSandboxPlaywright, ensureSandboxBrowser, createSandboxBrowserTools, BROWSER_TOOL_NAMES, createBrowserToolset, checkpointState, completeAuthentication, crawlAuthenticated, createAttackSurfaceReport, createFile, createTask2 as createTask, delegateAuth, detectAuthScheme, documentApp, pLimit, documentEndpoint, CweEntrySchema, ValidatedCweEntrySchema, hasCanonicalName, documentVulnerability, createEmailToolset, EMAIL_TOOL_NAMES, SEND_EMAIL_TOOL_NAME, executeCommand, extractJsEndpoints, getMemory2 as getMemory, getPage, grep, httpRequest, listFiles, listMemories2 as listMemories, listTasksTool, readTempfileCapped, getApexTmpRoot, extractFallbackStdout, PersistentShell, probeAuthEndpoints, provideComparisonResults, readFile2 as readFile, readSkill, REPORT_ERROR_TOOL_NAME, ReportErrorReasonSchema, createReportErrorTool, PentestReportedError, RESPONSE_TOOL_NAME, createResponseTool, runAttackSurface, runPentestWorkflow, runWithBoundedConcurrency, spawnCodingAgent, FindingsRegistry, planFilePath, readPlan, hasPlan, spawnPentestAgent, spawnPentestSwarm, submitPlan, testEndpointVariations, updateFile, updateTask2 as updateTask, validateDiscovery, webSearch, writePlan, createAllTools, ALL_TOOL_NAMES, PLAN_MODE_TOOL_NAMES, SKILL_TOOL_NAMES, StepTraceWriter, OffensiveSecurityAgent };
|
|
121267
|
+
export { AgentEventBus, INTERNAL_ID_PATTERN, ApprovalGate, OPERATOR_MODES, OPERATOR_MODE_CYCLE, createInitialOperatorState, buildProvidedFilesSection, buildSessionWorkspaceSection, buildBaseSystemPrompt, BASE_SYSTEM_PROMPT, isMemoryEnabled, addMemory2 as addMemory, ASK_USER_QUESTIONS_TOOL_NAME, AskUserQuestionSchema, transformScriptToFunction, parseStorageStateResult, setHeadlessMode, setUserAgent, setViewportSize, PlaywrightMcpSession, createBrowserTools, ScopeViolationError, getAllowedHosts, isHostAllowed, extractHostname2 as extractHostname, assertUrlInScope, extractHostsFromCommand, assertCommandInScope, checkSandboxPlaywright, installSandboxPlaywright, ensureSandboxPlaywright, ensureSandboxBrowser, createSandboxBrowserTools, BROWSER_TOOL_NAMES, createBrowserToolset, checkpointState, completeAuthentication, crawlAuthenticated, createAttackSurfaceReport, createFile, createTask2 as createTask, delegateAuth, detectAuthScheme, documentApp, EndpointTransportEnum, GrpcEndpointMetadataSchema, toGrpcPentestContext, grpcAuthorityTarget, pLimit, documentEndpoint, CweEntrySchema, ValidatedCweEntrySchema, hasCanonicalName, documentVulnerability, createEmailToolset, EMAIL_TOOL_NAMES, SEND_EMAIL_TOOL_NAME, executeCommand, extractJsEndpoints, getMemory2 as getMemory, getPage, grep, httpRequest, listFiles, listMemories2 as listMemories, listTasksTool, readTempfileCapped, getApexTmpRoot, extractFallbackStdout, PersistentShell, probeAuthEndpoints, provideComparisonResults, readFile2 as readFile, readSkill, REPORT_ERROR_TOOL_NAME, ReportErrorReasonSchema, createReportErrorTool, PentestReportedError, RESPONSE_TOOL_NAME, createResponseTool, runAttackSurface, runPentestWorkflow, runWithBoundedConcurrency, spawnCodingAgent, FindingsRegistry, planFilePath, readPlan, hasPlan, spawnPentestAgent, spawnPentestSwarm, submitPlan, testEndpointVariations, updateFile, updateTask2 as updateTask, validateDiscovery, webSearch, writePlan, createAllTools, ALL_TOOL_NAMES, FAST_STRIKE_EXCLUDED_TOOL_NAMES, PLAN_MODE_TOOL_NAMES, SKILL_TOOL_NAMES, StepTraceWriter, OffensiveSecurityAgent };
|