@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,15 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
|
+
EndpointTransportEnum,
|
|
3
|
+
GrpcEndpointMetadataSchema,
|
|
2
4
|
OffensiveSecurityAgent
|
|
3
|
-
} from "./cli-
|
|
5
|
+
} from "./cli-xbdn034b.js";
|
|
4
6
|
import {
|
|
5
7
|
hasToolCall,
|
|
6
8
|
init_dist
|
|
7
|
-
} from "./cli-
|
|
9
|
+
} from "./cli-6kx46ck0.js";
|
|
8
10
|
import {
|
|
9
11
|
exports_external,
|
|
10
12
|
init_zod,
|
|
11
13
|
tool
|
|
12
|
-
} from "./cli-
|
|
14
|
+
} from "./cli-3k1x5rn3.js";
|
|
13
15
|
|
|
14
16
|
// src/core/agents/specialized/whiteboxAttackSurface/agent.ts
|
|
15
17
|
init_dist();
|
|
@@ -209,6 +211,7 @@ Your primary search tool. Use it to find route definitions, middleware, controll
|
|
|
209
211
|
- **Always set \`routePath\`** to the HTTP route (e.g., \`/api/users\`). This is the URL path a client requests — NOT a source-file path.
|
|
210
212
|
- **Always set \`file\`** to the source-code file (e.g., \`src/routes/users.ts\`). This is NOT the HTTP route.
|
|
211
213
|
- **Always set \`handler\`** to the function name, and \`authRequired\` to indicate auth requirements.
|
|
214
|
+
- **gRPC methods:** when an endpoint is a gRPC RPC rather than a plain HTTP route, set \`routePath\` to the wire path \`/package.Service/Method\`, set \`transport\` to \`"grpc"\` (or \`"grpc_web"\`/\`"connect"\`), and populate the \`grpc\` object (\`serviceFqn\`, \`method\`, \`streamingType\`). Carry these same \`transport\`/\`grpc\` fields into the matching endpoint entry in \`submit_results\` — without them the swarm tests the wire path as HTTP instead of running the gRPC methodology.
|
|
212
215
|
|
|
213
216
|
Call these tools throughout your analysis as you discover apps and endpoints — don't wait until the end.
|
|
214
217
|
|
|
@@ -251,8 +254,9 @@ For each app you identified, spawn a coding agent with a detailed objective. The
|
|
|
251
254
|
- Source-code file in \`file\` (e.g., \`src/routes/users.ts\`) — this is NOT the route
|
|
252
255
|
- Line number in \`line\`
|
|
253
256
|
- Auth requirement in \`authRequired\`
|
|
257
|
+
- For gRPC RPCs: \`transport\` (\`"grpc"\`/\`"grpc_web"\`/\`"connect"\`) and a \`grpc\` object (\`serviceFqn\`, \`method\`, \`streamingType\`), with \`routePath\` set to the wire path \`/package.Service/Method\`
|
|
254
258
|
|
|
255
|
-
**IMPORTANT:** Tell each coding agent to set \`appName\` on every \`document_endpoint\` call so endpoints are organized by application.
|
|
259
|
+
**IMPORTANT:** Tell each coding agent to set \`appName\` on every \`document_endpoint\` call so endpoints are organized by application. Preserve any \`transport\`/\`grpc\` fields the coding agents report on gRPC endpoints when you assemble the final \`submit_results\` payload — dropping them makes the swarm test gRPC wire paths as HTTP.
|
|
256
260
|
|
|
257
261
|
## Phase 3: COVERAGE DOUBLE-CHECK (do this yourself — DO NOT SKIP)
|
|
258
262
|
|
|
@@ -328,7 +332,9 @@ var EndpointSchema = exports_external.object({
|
|
|
328
332
|
description: exports_external.string().optional().describe("Brief description of what this endpoint does"),
|
|
329
333
|
pentestObjectives: exports_external.array(exports_external.string()).default([]).describe("Pentest objectives for this endpoint, derived from the threat model when available " + "(e.g. 'Test for IDOR by enumerating user IDs', 'Test for SQL injection in search parameter')"),
|
|
330
334
|
riskScore: RiskScoreSchema.optional().describe("AI-calculated risk score for prioritizing pentest efforts"),
|
|
331
|
-
threatModel: exports_external.string().optional().describe("Endpoint-specific threat model describing attack vectors, data sensitivity, and testing priorities")
|
|
335
|
+
threatModel: exports_external.string().optional().describe("Endpoint-specific threat model describing attack vectors, data sensitivity, and testing priorities"),
|
|
336
|
+
transport: EndpointTransportEnum.optional().describe("Wire transport; 'grpc'/'grpc_web'/'connect' for gRPC methods, else http"),
|
|
337
|
+
grpc: GrpcEndpointMetadataSchema.optional().describe("gRPC service/method/streaming metadata when transport is a gRPC variant")
|
|
332
338
|
});
|
|
333
339
|
var AppSchema = exports_external.object({
|
|
334
340
|
name: exports_external.string().describe("Application or service name"),
|
|
@@ -400,6 +406,7 @@ class WhiteboxAttackSurfaceAgent extends OffensiveSecurityAgent {
|
|
|
400
406
|
attackSurfaceRegistry,
|
|
401
407
|
domains,
|
|
402
408
|
enableThinking,
|
|
409
|
+
thinkingEffort,
|
|
403
410
|
openAIReasoningEffort
|
|
404
411
|
} = opts;
|
|
405
412
|
let capturedResult = null;
|
|
@@ -424,8 +431,10 @@ This ends the agent run — make sure all data is included.`,
|
|
|
424
431
|
abortSignal,
|
|
425
432
|
eventBus,
|
|
426
433
|
subagentId,
|
|
434
|
+
subagentName: opts.subagentName,
|
|
427
435
|
attackSurfaceRegistry,
|
|
428
436
|
enableThinking,
|
|
437
|
+
thinkingEffort,
|
|
429
438
|
openAIReasoningEffort,
|
|
430
439
|
activeTools: [
|
|
431
440
|
"read_file",
|
|
@@ -488,7 +497,7 @@ Analyze this codebase and produce a complete attack surface map:
|
|
|
488
497
|
1. Identify the repo type and package manager
|
|
489
498
|
2. Discover all apps/services
|
|
490
499
|
3. Discover cloud resources and external infrastructure referenced in the code (S3 buckets, cloud storage, CDN origins, etc.) — document these as apps with the appropriate type
|
|
491
|
-
4. For each app, find all web pages and API endpoints
|
|
500
|
+
4. For each app, find all web pages and API endpoints (including gRPC methods — set \`transport\` and \`grpc\` on those endpoints so downstream testing uses the gRPC methodology instead of treating the wire path as HTTP)
|
|
492
501
|
5. For each endpoint, generate pentest objectives
|
|
493
502
|
6. **Before submitting**, perform the Phase 3 coverage double-check from the system prompt — re-scan workspace roots, framework configs, Dockerfiles, IaC, and CI/deploy configs for apps you may have missed on the first pass, and document any that were missed.
|
|
494
503
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
OffensiveSecurityAgent
|
|
3
|
-
} from "./cli-
|
|
3
|
+
} from "./cli-xbdn034b.js";
|
|
4
4
|
import {
|
|
5
5
|
init_dist,
|
|
6
6
|
stepCountIs
|
|
7
|
-
} from "./cli-
|
|
7
|
+
} from "./cli-6kx46ck0.js";
|
|
8
8
|
|
|
9
9
|
// src/core/agents/specialized/codeAgent/agent.ts
|
|
10
10
|
init_dist();
|
|
@@ -79,6 +79,7 @@ class CodeAgent extends OffensiveSecurityAgent {
|
|
|
79
79
|
attackSurfaceRegistry,
|
|
80
80
|
excludeTools,
|
|
81
81
|
enableThinking,
|
|
82
|
+
thinkingEffort,
|
|
82
83
|
openAIReasoningEffort,
|
|
83
84
|
projectThreatModel
|
|
84
85
|
} = opts;
|
|
@@ -122,8 +123,10 @@ class CodeAgent extends OffensiveSecurityAgent {
|
|
|
122
123
|
abortSignal,
|
|
123
124
|
eventBus,
|
|
124
125
|
subagentId,
|
|
126
|
+
subagentName: opts.subagentName,
|
|
125
127
|
attackSurfaceRegistry,
|
|
126
128
|
enableThinking,
|
|
129
|
+
thinkingEffort,
|
|
127
130
|
openAIReasoningEffort,
|
|
128
131
|
projectThreatModel,
|
|
129
132
|
stopWhen: stopWhen ?? stepCountIs(1e4),
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
createReportErrorTool,
|
|
6
6
|
isMemoryEnabled,
|
|
7
7
|
readPlan
|
|
8
|
-
} from "./cli-
|
|
8
|
+
} from "./cli-xbdn034b.js";
|
|
9
9
|
import {
|
|
10
10
|
createLogger,
|
|
11
11
|
hasToolCall,
|
|
@@ -13,11 +13,11 @@ import {
|
|
|
13
13
|
init_lazyLogger,
|
|
14
14
|
init_structured,
|
|
15
15
|
scopedLogger
|
|
16
|
-
} from "./cli-
|
|
16
|
+
} from "./cli-6kx46ck0.js";
|
|
17
17
|
import {
|
|
18
18
|
exports_external,
|
|
19
19
|
init_zod
|
|
20
|
-
} from "./cli-
|
|
20
|
+
} from "./cli-3k1x5rn3.js";
|
|
21
21
|
|
|
22
22
|
// src/core/agents/specialized/pentest/agent.ts
|
|
23
23
|
init_dist();
|
|
@@ -37,6 +37,7 @@ var PentestResponseSchema = exports_external.object({
|
|
|
37
37
|
findingsDocumented: exports_external.number().describe("Number of vulnerabilities documented via document_vulnerability"),
|
|
38
38
|
objectivesCovered: exports_external.array(exports_external.string()).describe("Which objectives were tested"),
|
|
39
39
|
objectiveResults: exports_external.array(ObjectiveResultSchema).describe("Status of each objective: mark as completed if thoroughly tested (vulnerability confirmed and documented, OR conclusively not vulnerable), or incomplete if further testing is warranted. Include new objectives discovered during testing that should be added for future runs."),
|
|
40
|
+
newObjectives: exports_external.array(exports_external.string()).optional().describe("Objectives for the NEXT run of this endpoint. Populate this directly from everything you observed: worker outcomes, what was confirmed or conclusively ruled out, recon anomalies nobody investigated, and the technology you fingerprinted. Each entry must be a focused, self-contained objective the next run can act on directly — name a concrete attack class against a concrete parameter, header, or flow. Do NOT restate anything tested this run or already marked completed in your assignment context; find the coverage gaps. Emit a small, high-signal set (typically 2-6), preferring breadth across distinct untested attack classes over payload variants. Empty/omitted when the endpoint is genuinely exhausted."),
|
|
40
41
|
noFindingsReason: exports_external.string().optional().describe("If no findings were documented, explain why (e.g., target not vulnerable, endpoint unreachable)")
|
|
41
42
|
});
|
|
42
43
|
|
|
@@ -45,6 +46,7 @@ class TargetedPentestAgent extends OffensiveSecurityAgent {
|
|
|
45
46
|
const {
|
|
46
47
|
model,
|
|
47
48
|
target,
|
|
49
|
+
grpc,
|
|
48
50
|
objectives,
|
|
49
51
|
session,
|
|
50
52
|
authConfig,
|
|
@@ -58,7 +60,9 @@ class TargetedPentestAgent extends OffensiveSecurityAgent {
|
|
|
58
60
|
messages,
|
|
59
61
|
context,
|
|
60
62
|
environmentVariables,
|
|
63
|
+
secretValues,
|
|
61
64
|
enableThinking,
|
|
65
|
+
thinkingEffort,
|
|
62
66
|
openAIReasoningEffort,
|
|
63
67
|
role = "orchestrator",
|
|
64
68
|
browserSession,
|
|
@@ -67,21 +71,25 @@ class TargetedPentestAgent extends OffensiveSecurityAgent {
|
|
|
67
71
|
let reportedError = null;
|
|
68
72
|
super({
|
|
69
73
|
system: buildPentestSystemPrompt(session, role),
|
|
70
|
-
prompt: buildPentestPrompt(target, objectives, session, findingsRegistry, context, environmentVariables ? Object.keys(environmentVariables) : undefined, subagentId, role),
|
|
74
|
+
prompt: buildPentestPrompt(target, objectives, session, findingsRegistry, context, environmentVariables ? Object.keys(environmentVariables) : undefined, subagentId, role, session.credentialManager?.formatForPrompt(), grpc),
|
|
71
75
|
model,
|
|
72
76
|
session,
|
|
73
77
|
target,
|
|
78
|
+
grpc,
|
|
74
79
|
authConfig,
|
|
75
80
|
onStepFinish,
|
|
76
81
|
onCacheMetrics,
|
|
77
82
|
abortSignal,
|
|
78
83
|
eventBus,
|
|
79
84
|
subagentId,
|
|
85
|
+
subagentName: opts.subagentName,
|
|
80
86
|
sandbox,
|
|
81
87
|
findingsRegistry,
|
|
82
88
|
messages,
|
|
83
89
|
environmentVariables,
|
|
90
|
+
secretValues,
|
|
84
91
|
enableThinking,
|
|
92
|
+
thinkingEffort,
|
|
85
93
|
openAIReasoningEffort,
|
|
86
94
|
browserSession,
|
|
87
95
|
display,
|
|
@@ -98,6 +106,7 @@ class TargetedPentestAgent extends OffensiveSecurityAgent {
|
|
|
98
106
|
throw new PentestReportedError(reportedError);
|
|
99
107
|
}
|
|
100
108
|
let objectiveResults;
|
|
109
|
+
let newObjectives;
|
|
101
110
|
try {
|
|
102
111
|
const response = await streamResult.response;
|
|
103
112
|
for (const msg of response.messages ?? []) {
|
|
@@ -106,8 +115,11 @@ class TargetedPentestAgent extends OffensiveSecurityAgent {
|
|
|
106
115
|
for (const part of msg.content) {
|
|
107
116
|
if (part.type === "tool-call" && part.toolName === "response" && part.input) {
|
|
108
117
|
const input = part.input;
|
|
109
|
-
if (input.
|
|
110
|
-
objectiveResults = input.
|
|
118
|
+
if (input.result?.objectiveResults) {
|
|
119
|
+
objectiveResults = input.result.objectiveResults;
|
|
120
|
+
}
|
|
121
|
+
if (input.result?.newObjectives) {
|
|
122
|
+
newObjectives = input.result.newObjectives;
|
|
111
123
|
}
|
|
112
124
|
}
|
|
113
125
|
}
|
|
@@ -118,7 +130,8 @@ class TargetedPentestAgent extends OffensiveSecurityAgent {
|
|
|
118
130
|
findings,
|
|
119
131
|
findingsPath: session.findingsPath,
|
|
120
132
|
pocsPath: session.pocsPath,
|
|
121
|
-
objectiveResults
|
|
133
|
+
objectiveResults,
|
|
134
|
+
newObjectives
|
|
122
135
|
};
|
|
123
136
|
}
|
|
124
137
|
});
|
|
@@ -164,6 +177,7 @@ var SECTION_POC_PORTABILITY = `POC Script Portability Requirements:
|
|
|
164
177
|
- Prefer built-in shell features over external commands when possible
|
|
165
178
|
- If a PoC requires a specific non-standard tool, check for it at the start and exit with a clear error message if missing`;
|
|
166
179
|
var SECTION_BROWSER_INTERACTION = `Browser Interaction:
|
|
180
|
+
- Lean on the browser for testing wherever it applies. For anything interactive, stateful, client-side, or auth-gated — login flows, multi-step forms, SPA/JavaScript-driven behavior, DOM-based XSS, CSRF, and any page that only behaves correctly with a rendered, logged-in session — drive the test through the browser (browser_navigate / browser_click / browser_fill / browser_snapshot) rather than raw requests. The browser preserves your authenticated session and executes client-side logic that http_request / curl cannot see. Fall back to http_request / execute_command (curl) for stateless API-level checks, header inspection, and high-volume payload fuzzing.
|
|
167
181
|
- Use browser_navigate to load pages, browser_snapshot to inspect the DOM, and browser_screenshot for visual evidence
|
|
168
182
|
- Use browser_click and browser_fill to interact with forms, buttons, and input fields — essential for testing login flows, search fields, and other interactive elements
|
|
169
183
|
- Screenshot liberally so the user can follow along. Whenever you are driving a browser, treat screenshots as the primary way the user watches your work. Err heavily on the side of more screenshots rather than fewer.
|
|
@@ -175,12 +189,24 @@ var SECTION_BROWSER_INTERACTION = `Browser Interaction:
|
|
|
175
189
|
- Screenshots are cheap — prefer taking one and not needing it over skipping one and losing visibility. Do NOT attempt to conserve tokens by skipping screenshots during browser-driven testing.
|
|
176
190
|
- Screenshots are automatically stored and displayed alongside your tool call logs, so each one directly improves the user's ability to follow the test in real time.`;
|
|
177
191
|
var SECTION_AUTHENTICATION = `Authentication:
|
|
178
|
-
- If the prompt includes an "Existing Authentication Session" section, USE those cookies/headers on every request and do NOT re-authenticate. If such a request returns 401/403, that provided session has expired — note it in your findings (and call report_error if it blocks all further testing).
|
|
179
|
-
- Otherwise, if the target requires authentication, log in yourself
|
|
180
|
-
- After a successful browser login, call browser_get_cookies to extract the session cookies (including httpOnly ones)
|
|
192
|
+
- If the prompt includes an "Existing Authentication Session" section, USE those cookies/headers on every request and do NOT re-authenticate up front. If such a request returns 401/403, that provided session has expired — note it in your findings (and call report_error if it blocks all further testing). Only log in yourself (following any "Available Credentials" instructions) if that provided session expires mid-run.
|
|
193
|
+
- Otherwise, if the target requires authentication, log in yourself. When an "Available Credentials" section is present, follow the authentication instructions in each credential's Context exactly — use the method it describes (for example, a token/API exchange driven with execute_command or http_request) instead of defaulting to a browser login. Only fall back to driving the login flow in the browser with browser_navigate + browser_fill when the Context does not specify how to authenticate. Prefer credentialId + credentialField so secrets are resolved securely; injected credential environment variables are also available inside execute_command.
|
|
194
|
+
- After a successful login, capture the resulting session credentials and reuse them for raw requests. For a browser login, call browser_get_cookies to extract the session cookies (including httpOnly ones) — pass them as the Cookie header to http_request, or as -H "Cookie: ..." / -b flags to execute_command (curl). Any worker you spawn automatically inherits a snapshot of your authenticated browser session.
|
|
181
195
|
- For http_request: include the captured Cookie and any Authorization headers on every call. For execute_command (curl): include -H "Cookie: ..." and/or -H "Authorization: ..." flags.
|
|
182
|
-
- If a request returns 401/403 after you logged in yourself, your captured session may have expired — re-authenticate
|
|
183
|
-
- If you cannot authenticate
|
|
196
|
+
- If a request returns 401/403 after you logged in yourself, your captured session may have expired — re-authenticate the same way you did originally and refresh your session cookies/tokens.
|
|
197
|
+
- Do NOT spin your wheels on authentication. If you have followed the credential Context instructions and still cannot authenticate, do NOT try to work around it — do NOT register a new account, self-sign-up, or fabricate credentials to authenticate. Those are not the credentials under test and only pollute results. (Registering a throwaway account is acceptable only as a disposable *target* for destructive-flow POCs per the blast-radius rungs below — never as a substitute for authenticating as the credential under test.) Make at most a couple of genuine attempts, then call report_error with reason "authentication_failed" and a specific message describing exactly what you tried and how it failed.
|
|
198
|
+
- If you cannot authenticate with the available credentials, or another runtime condition blocks all testing, call report_error with a clear, specific message instead of giving up silently or documenting a non-finding.
|
|
199
|
+
- Build verifiable POCs, but bound the blast radius. Prove impact with the least-invasive action that still demonstrates the flaw, preferring earlier rungs:
|
|
200
|
+
1. Prove a broken-authorization / privileged-role / IDOR boundary with a READ, or with a benign, reversible write to a low-impact field (e.g. your own display name). That a privileged call is accepted against an object you should not be able to reach is usually the finding — prefer this over disabling security controls, changing quotas/limits, or mutating another user.
|
|
201
|
+
2. If a reversible state-changing write is the only convincing proof, capture the current value, make the change, capture evidence (response/screenshot), then immediately restore the original value — and prefer your own account or a throwaway account you registered for this test over a shared or provided account. Do NOT rely on end-of-run cleanup alone; a crash mid-run can strip it before it runs.
|
|
202
|
+
3. NEVER complete an irreversible or security-weakening mutation against a shared or provided account, against any other user's account reached via broken authorization / IDOR, or against an org- or tenant-wide security setting (e.g. disabling MFA for an entire team): overwriting/resetting, disabling, or otherwise weakening an MFA/TOTP device or any second factor / security control, consuming a single-use reset token, changing the account email, rotating the password, or deleting the account. This hard ban is not limited to the identity you authenticated as — an IDOR or org-level authz flaw does not make it acceptable to actually disable or weaken another user's or the whole team's protections; prove the boundary is crossed without completing the weakening step. Irreversible changes cannot be undone (you never hold the original TOTP secret to restore), and locking an account out, disabling protections for other users, or weakening an org-wide control invalidates or endangers the credentials for every other agent — even a "reversible" toggle like disabling MFA leaves the account or team exposed if a crash strips the restore step. Demonstrate reachability/authorization instead, or perform the destructive step only against a throwaway account you registered for this test.`;
|
|
203
|
+
var SECTION_DESTRUCTIVE_ALLOWED = `Destructive Testing (AUTHORIZED):
|
|
204
|
+
- The client has authorized destructive testing for this engagement. You MAY perform DB deletes/drops/truncates, API write-deletes (HTTP DELETE), and other destructive operations when they are necessary to prove impact.
|
|
205
|
+
- Still prefer the least-invasive proof that convincingly demonstrates the flaw, and follow the blast-radius rungs in the Authentication section — authorization to be destructive is not license to be reckless with shared or provided accounts.`;
|
|
206
|
+
var SECTION_DESTRUCTIVE_BLOCKED = `Destructive Testing (OUT OF SCOPE):
|
|
207
|
+
- The client has NOT authorized destructive testing for this engagement. Destructive operations are BLOCKED at the tool boundary and will return an error, so do not attempt them — they only waste turns.
|
|
208
|
+
- Blocked operations include: destructive SQL (DROP / TRUNCATE / DELETE FROM / ALTER … DROP), destructive NoSQL/cache operations (collection/database drops, deleteMany, FLUSHALL/FLUSHDB), API write-deletes (HTTP DELETE, or writes overriding to DELETE / targeting a delete/destroy/purge route), and catastrophic host operations (rm -rf of a root/home, mkfs, dd to a device, fork bombs, power-state changes).
|
|
209
|
+
- Prove destructive-class flaws WITHOUT completing the destructive step: demonstrate that the authorization boundary is crossed (e.g. the DELETE endpoint accepts your request / returns a pre-flight that would delete) with a read or a benign, reversible action, and describe the impact rather than actually deleting or dropping data.`;
|
|
184
210
|
var SECTION_CREDENTIAL_DISCOVERY = `Credential & Secret Discovery:
|
|
185
211
|
- When you find exposed configuration in client-side code (JS bundles, HTML source, config files), distinguish between:
|
|
186
212
|
- SENSITIVE SECRETS (API keys granting backend access, database credentials, JWT signing keys, private keys, service account tokens) — document as a HIGH/CRITICAL finding
|
|
@@ -418,16 +444,25 @@ ${SECTION_SECURITY_HEADERS_CORS}
|
|
|
418
444
|
${SECTION_FINDING_QUALITY}
|
|
419
445
|
|
|
420
446
|
${SECTION_STATE_CHECKPOINTING}`;
|
|
447
|
+
function destructiveSection(allow) {
|
|
448
|
+
return allow ? SECTION_DESTRUCTIVE_ALLOWED : SECTION_DESTRUCTIVE_BLOCKED;
|
|
449
|
+
}
|
|
421
450
|
function buildPentestSystemPrompt(session, role = "orchestrator") {
|
|
451
|
+
const destructive = destructiveSection(session.config?.allowDestructiveActions);
|
|
422
452
|
if (role === "orchestrator") {
|
|
423
|
-
return PENTEST_SYSTEM_PROMPT_ORCHESTRATOR
|
|
453
|
+
return `${PENTEST_SYSTEM_PROMPT_ORCHESTRATOR}
|
|
454
|
+
|
|
455
|
+
${destructive}`;
|
|
424
456
|
}
|
|
425
457
|
const taskDriven = session.config?.taskDriven ?? false;
|
|
426
458
|
const exfilMode = session.config?.exfilMode ?? false;
|
|
427
459
|
const base = taskDriven ? exfilMode ? PENTEST_SYSTEM_PROMPT_TASK_DRIVEN_EXFIL : PENTEST_SYSTEM_PROMPT_TASK_DRIVEN : exfilMode ? PENTEST_SYSTEM_PROMPT_EXFIL : PENTEST_SYSTEM_PROMPT_BASE;
|
|
428
|
-
|
|
460
|
+
const withDestructive = `${base}
|
|
461
|
+
|
|
462
|
+
${destructive}`;
|
|
463
|
+
return session.config?.promptInjectionLibrarySource ? `${withDestructive}
|
|
429
464
|
|
|
430
|
-
${SECTION_PROMPT_INJECTION}` :
|
|
465
|
+
${SECTION_PROMPT_INJECTION}` : withDestructive;
|
|
431
466
|
}
|
|
432
467
|
var SECTION_ORCHESTRATOR_DELEGATION = `Sub-Agent Delegation Rules:
|
|
433
468
|
- You DO NOT call document_vulnerability directly. Findings are documented by the workers you spawn.
|
|
@@ -450,14 +485,20 @@ ${SECTION_SOURCE_CODE_PROHIBITION}
|
|
|
450
485
|
Your methodology:
|
|
451
486
|
1. ORIENT — Call list_memories to review any existing knowledge from previous engagements (target-specific notes, successful techniques, false positive patterns, technology context). Use what you find to shape your plan.
|
|
452
487
|
2. PLAN — State the objectives you have been given and outline your high-level orchestration plan in plain text BEFORE any tool calls. For each objective, briefly state what attack class the worker should focus on (e.g. "Objective 1 → SQL injection, focus on /api/users id parameter"). Output this plan as a text message — not as a tool call.
|
|
453
|
-
3. RECON — Perform LIGHT initial reconnaissance to confirm the target is reachable and understand baseline behavior. Use http_request for a handful of probes, browser_navigate + browser_snapshot to see the surface, and execute_command sparingly. Do NOT begin exploitation here — that is the workers' job. Note any anomalies (unusual error responses, exposed headers, framework fingerprints, surprising endpoint behavior) for the final exploratory worker.
|
|
488
|
+
3. RECON & AUTHENTICATE — Perform LIGHT initial reconnaissance to confirm the target is reachable and understand baseline behavior. Use http_request for a handful of probes, browser_navigate + browser_snapshot to see the surface, and execute_command sparingly. Do NOT begin exploitation here — that is the workers' job. Note any anomalies (unusual error responses, exposed headers, framework fingerprints, surprising endpoint behavior) for the final exploratory worker.
|
|
489
|
+
- If authentication is required (an "Existing Authentication Session" section is absent and the target / objectives need a logged-in session), you MUST authenticate NOW, in YOUR browser, BEFORE any fan-out. Follow the "Available Credentials" instructions exactly — use the method each credential's Context describes (e.g. a token/API exchange via execute_command or http_request) rather than defaulting to a browser login; only drive the browser login flow (browser_navigate + browser_fill with credentialId/credentialField) when the Context does not specify how.
|
|
490
|
+
- VERIFY the session before fanning out: request a protected resource and confirm it does NOT return 401/403. Use browser_get_cookies to capture the session cookies for reuse in raw http_request / curl calls.
|
|
491
|
+
- Authenticating HERE (not in the workers) is critical: each worker you spawn inherits a snapshot of YOUR browser's authenticated cookies + localStorage at spawn time, so ONE successful login up front propagates to every worker. Do NOT instruct workers to re-authenticate.
|
|
492
|
+
- If you cannot authenticate and the objectives require it, call report_error with reason "authentication_failed" and a specific message BEFORE spawning any workers — do not fan out unauthenticated workers that will all fail, and do not report non-findings.
|
|
454
493
|
4. FAN OUT — For EACH objective, call spawn_pentest_agent EXACTLY ONCE. Each spawn dispatches a focused worker that will perform the full PLAN → VERIFY → PREPARE → TEST → EXPLOIT → DOCUMENT loop on its objective. Workers write findings to the shared findings registry — you do NOT need to forward findings between them.
|
|
455
494
|
5. CHAIN & EXPLORE — After all per-objective workers complete, call spawn_pentest_agent ONE FINAL TIME with a synthesized objective that:
|
|
456
495
|
a. Summarizes what earlier workers confirmed or ruled out (so the exploratory worker doesn't re-do their work).
|
|
457
496
|
b. Calls out any anomalies you noticed during recon that nobody investigated.
|
|
458
497
|
c. Directs the worker to chain confirmed findings into higher-impact attack chains AND probe for additional vulnerabilities outside the original objective list (e.g. business logic flaws, race conditions, secondary injection points).
|
|
459
498
|
6. LEARN — Use add_memory to persist reusable learnings from this engagement (target behaviors, effective techniques, false positive patterns, technology fingerprints).
|
|
460
|
-
7. FINISH — Call the response tool with your final summary. Compile objectiveResults from what each worker reported: mark each objective as completed (vulnerability confirmed and documented by a worker, OR conclusively ruled out by a worker), or incomplete (worker failed or could not finish).
|
|
499
|
+
7. FINISH — Call the response tool with your final summary. Compile objectiveResults from what each worker reported: mark each objective as completed (vulnerability confirmed and documented by a worker, OR conclusively ruled out by a worker), or incomplete (worker failed or could not finish). Also populate newObjectives directly: using the coverage you just orchestrated (worker outcomes, what was confirmed or ruled out, recon anomalies nobody investigated, technology fingerprints), propose a small focused set of objectives for the NEXT run that are not already tested this run or marked completed in your context — so subsequent runs stay productive instead of re-testing finished work. Return an empty newObjectives array only when the endpoint is genuinely exhausted.
|
|
500
|
+
|
|
501
|
+
Empty open-objective assignments: if your assignment lists ZERO open objectives to test (every objective in your context is already marked completed), skip the per-objective fan-out and the chain & explore worker, do LIGHT recon only, then go to FINISH and still populate newObjectives so the run produces fresh objectives for next time rather than wasting the run.
|
|
461
502
|
|
|
462
503
|
${SECTION_ORCHESTRATOR_DELEGATION}
|
|
463
504
|
|
|
@@ -468,7 +509,7 @@ ${SECTION_MATERIALITY_GUIDANCE}
|
|
|
468
509
|
${SECTION_BROWSER_INTERACTION}
|
|
469
510
|
|
|
470
511
|
${SECTION_STATE_CHECKPOINTING}`;
|
|
471
|
-
function buildPentestPrompt(target, objectives, session, findingsRegistry, context, envVarNames, subagentId, role = "orchestrator") {
|
|
512
|
+
function buildPentestPrompt(target, objectives, session, findingsRegistry, context, envVarNames, subagentId, role = "orchestrator", credentialContext, grpc) {
|
|
472
513
|
const sessionRootPath = session.rootPath;
|
|
473
514
|
const exfilMode = session.config?.exfilMode ?? false;
|
|
474
515
|
const taskDriven = role === "orchestrator" ? false : session.config?.taskDriven ?? false;
|
|
@@ -587,13 +628,16 @@ Do NOT discover or enumerate other endpoints or services. Focus exclusively on t
|
|
|
587
628
|
1. Call list_memories to review any prior knowledge relevant to this target or engagement.
|
|
588
629
|
2. State the objectives and outline your orchestration plan in plain text BEFORE any tool calls — one bullet per objective, briefly naming the attack class each worker should focus on.
|
|
589
630
|
3. Perform LIGHT initial recon (a handful of http_request probes, browser_navigate + browser_snapshot to see the surface). Do NOT begin exploitation here — that is the workers' job. Note any anomalies you observe for the final exploratory worker.
|
|
631
|
+
- AUTHENTICATE FIRST if the target/objectives need a logged-in session and no "Existing Authentication Session" is provided: log in ONCE in YOUR browser during this recon step, following the "Available Credentials" instructions exactly (prefer the credential Context's method; use credentialId/credentialField so secrets resolve securely). Verify the session with a protected request (expect NOT 401/403) and capture cookies via browser_get_cookies. Every worker inherits your authenticated browser snapshot, so do this BEFORE fan-out and do NOT have workers re-authenticate. If you cannot authenticate and the objectives require it, call report_error with reason "authentication_failed" instead of fanning out.
|
|
590
632
|
4. Call spawn_pentest_agent EXACTLY ONCE PER OBJECTIVE. For every spawn:
|
|
591
633
|
- Set \`target\` to the FULL URL from the assignment above (domain + endpoint path) — pass it through verbatim. Do not strip the path or rewrite the host. Workers do not perform endpoint discovery; they deeply test the path you hand them.
|
|
592
634
|
- Pass the matching objective in the \`objectives\` array (a single-element array).
|
|
593
635
|
- Use the \`context\` field to forward any recon insights specific to that objective. If your earlier browser actions left state the worker should know about (already logged in as X, certain modal already dismissed), call that out in \`context\` — each worker is seeded with a snapshot of YOUR browser's cookies and localStorage at the moment of the spawn call.
|
|
594
636
|
5. After all per-objective workers complete, call spawn_pentest_agent ONE FINAL TIME with a synthesized "chain & explore" objective: summarize what earlier workers confirmed/ruled out, call out unaddressed anomalies, and direct the worker to chain confirmed findings AND probe for additional vulnerabilities outside the original objective list. Send it the same endpoint URL as your assignment unless an earlier worker's confirmed finding on a sibling endpoint is what makes the chain possible.
|
|
595
637
|
6. Use add_memory to save reusable learnings from this engagement.
|
|
596
|
-
7. Call the response tool with your final summary. Compile objectiveResults from worker reports.
|
|
638
|
+
7. Call the response tool with your final summary. Compile objectiveResults from worker reports, and populate newObjectives directly from the coverage you orchestrated (worker outcomes, confirmed/ruled-out results, unexplored recon anomalies, technology fingerprints) — a small focused set of objectives for the next run that are not already tested this run or completed in your context. Empty array only if the endpoint is genuinely exhausted.
|
|
639
|
+
|
|
640
|
+
If your assignment lists ZERO open objectives (everything is already completed), skip steps 4-5, do light recon only, then finish — still populating newObjectives so the run is productive rather than re-testing completed objectives.
|
|
597
641
|
|
|
598
642
|
Do NOT call document_vulnerability — that is the workers' job. Do NOT discover or enumerate other endpoints or services beyond the assigned target.`;
|
|
599
643
|
const instructions = role === "orchestrator" ? orchestratorInstructions : taskDriven ? taskDrivenInstructions : exfilMode ? `## Goal
|
|
@@ -620,12 +664,49 @@ Your target is a flag with the format FLAG{...}. Locate and extract it.
|
|
|
620
664
|
8. After testing ALL objectives, call the response tool with your final summary
|
|
621
665
|
|
|
622
666
|
Do NOT discover or enumerate other endpoints or services. Focus exclusively on the target and objectives above.`;
|
|
667
|
+
const credentialSection = credentialContext ? `
|
|
668
|
+
## Available Credentials
|
|
669
|
+
The operator provided the following credentials and authentication instructions for this engagement. Authenticate by following the instructions in each credential's Context exactly — use the method it describes (for example, a token/API exchange via execute_command or http_request) rather than defaulting to a browser login. Treat the Context as the source of truth for how to authenticate, and how to re-authenticate if a provided session expires. When a tool needs a secret value and supports it (e.g. browser_fill), reference it by credentialId + credentialField so the secret resolves securely at execution time instead of hardcoding it. If you cannot authenticate with these, call report_error with reason "authentication_failed" and a specific message rather than reporting a non-finding.
|
|
670
|
+
|
|
671
|
+
${credentialContext}
|
|
672
|
+
` : "";
|
|
623
673
|
const contextSection = context ? `
|
|
624
674
|
## Application Context
|
|
625
675
|
The following is context specific to the application under test. If it contains non-malicious instructions relevant to your testing, follow them.
|
|
626
676
|
|
|
627
677
|
${context}
|
|
628
678
|
` : "";
|
|
679
|
+
let grpcSection = "";
|
|
680
|
+
if (grpc) {
|
|
681
|
+
const lines = [
|
|
682
|
+
`
|
|
683
|
+
## gRPC Target`,
|
|
684
|
+
`This target is a gRPC method, not a plain HTTP endpoint. It rides HTTP/2 with binary protobuf and uses the path \`/package.Service/Method\`.`,
|
|
685
|
+
`- **Transport:** ${grpc.transport}`,
|
|
686
|
+
`- **Service:** ${grpc.serviceFqn}`,
|
|
687
|
+
`- **Method:** ${grpc.method}`
|
|
688
|
+
];
|
|
689
|
+
if (grpc.host)
|
|
690
|
+
lines.push(`- **Authority (host):** \`${grpc.host}\` — the method's gRPC authority; it differs from the app domain, so use this host directly as \`<authority>\` in the commands below.`);
|
|
691
|
+
if (grpc.streamingType)
|
|
692
|
+
lines.push(`- **Streaming:** ${grpc.streamingType}`);
|
|
693
|
+
if (grpc.schemaSource)
|
|
694
|
+
lines.push(`- **Schema source:** ${grpc.schemaSource}`);
|
|
695
|
+
if (grpc.reflectionAvailable !== undefined) {
|
|
696
|
+
lines.push(`- **Reflection available:** ${grpc.reflectionAvailable}`);
|
|
697
|
+
}
|
|
698
|
+
if (grpc.frontingGatewayOperation) {
|
|
699
|
+
lines.push(`- **Fronting gateway:** ${grpc.frontingGatewayOperation.gatewayType} operation \`${grpc.frontingGatewayOperation.operation}\` — if the direct gRPC authority is unreachable, test through this gateway operation instead.`);
|
|
700
|
+
} else {
|
|
701
|
+
lines.push(`- **Fronting gateway:** none — this method is reachable directly but is NOT exposed through the REST/GraphQL gateway. Treat it as a PRIME missing-authorization target: gateway-fronted methods usually get their authz enforced at the gateway, so a shadow method that bypasses the gateway may bypass that authz entirely.`);
|
|
702
|
+
}
|
|
703
|
+
lines.push(`
|
|
704
|
+
### gRPC Test Battery (OWASP gRPC Security Cheat Sheet)`, `Use \`grpcurl\`, \`buf\`, and \`protoc\` via \`execute_command\`. Work through this battery for the method above:`, `1. **Schema recovery.** Try reflection first: \`grpcurl -plaintext <authority> list\` / \`describe <service>\`. If reflection is disabled, recover the schema from a \`.proto\` file or protoset (e.g. via \`buf\` or \`protoc\`) before giving up on schema-dependent tests.`, `2. **Transport/content-type fallback.** Native gRPC, grpc-web, and Connect use different content-types over the same or adjacent paths. If one transport looks dead, retry as grpc-web (\`application/grpc-web\`) and Connect (\`application/connect+...\` or JSON) before declaring the endpoint unreachable.`, `3. **Status-code oracle.** Treat gRPC status codes as signal, not noise: 16 UNAUTHENTICATED, 7 PERMISSION_DENIED, 3 INVALID_ARGUMENT, 12 UNIMPLEMENTED. A flip from UNAUTHENTICATED to a data response after adding/removing metadata is a finding.`, `4. **Missing auth per method.** Call the method with valid credentials/metadata, then again with none and with garbage metadata. A successful response without auth is a critical finding.`, `5. **BOLA / IDOR.** Manipulate ID fields inside the request message (account/user/resource IDs) to access another principal's data.`, `6. **Metadata trust.** Test whether the service trusts client-supplied metadata it shouldn't (e.g. \`x-user-id\`, forwarded auth headers) instead of deriving identity server-side.`, `7. **Non-canonical \`:path\` authz bypass.** If authz is enforced by a proxy matching on \`:path\`, try case variants, trailing slashes, or alternate casing of the service/method path to see if the gRPC path parsing bypasses it.`, `8. **Protobuf/message fuzzing.** Send malformed, truncated, and type-mismatched field values; unknown field numbers; and deeply nested/repeated fields to probe deserialization handling.`, `9. **Streaming IDOR.** For client/server/bidi streaming methods, probe whether a stream opened for one principal's resource can be redirected mid-stream to another's.`, `10. **Decompression / size DoS.** Send oversized or highly compressible payloads to check for missing message-size limits or decompression bombs.`, `11. **Transport security.** Confirm whether the channel is plaintext or TLS/mTLS-enforced; plaintext gRPC in production is a finding on its own.`, `
|
|
705
|
+
If the method is unreachable from your network position (common for internal/in-cluster services), a finding is still valid via whitebox reasoning — schema plus routing/config evidence — even without an executed POC.`);
|
|
706
|
+
grpcSection = `${lines.join(`
|
|
707
|
+
`)}
|
|
708
|
+
`;
|
|
709
|
+
}
|
|
629
710
|
const envVarSection = envVarNames && envVarNames.length > 0 ? `
|
|
630
711
|
## Environment Variables
|
|
631
712
|
The following environment variables are pre-loaded in your shell and available in every \`execute_command\` call. Use them in scripts or commands (e.g. \`$${envVarNames[0]}\`) — do NOT hardcode their values.
|
|
@@ -636,7 +717,7 @@ ${envVarNames.map((n) => `- \`${n}\``).join(`
|
|
|
636
717
|
|
|
637
718
|
## Target
|
|
638
719
|
- **URL:** ${target}
|
|
639
|
-
${authSection}
|
|
720
|
+
${grpcSection}${authSection}${credentialSection}
|
|
640
721
|
${knownFindingsSection}
|
|
641
722
|
${knowledgeBaseSection}
|
|
642
723
|
${planSection}${contextSection}${envVarSection}
|
|
@@ -697,4 +778,4 @@ function loadFindings(findingsPath) {
|
|
|
697
778
|
}
|
|
698
779
|
}).filter((f) => f !== null);
|
|
699
780
|
}
|
|
700
|
-
export { TargetedPentestAgent, buildPentestSystemPrompt, buildPentestPrompt, buildPentestActiveTools };
|
|
781
|
+
export { PentestResponseSchema, TargetedPentestAgent, buildPentestSystemPrompt, buildPentestPrompt, buildPentestActiveTools };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CweEntrySchema,
|
|
3
3
|
ValidatedCweEntrySchema
|
|
4
|
-
} from "./cli-
|
|
4
|
+
} from "./cli-xbdn034b.js";
|
|
5
5
|
import {
|
|
6
6
|
exports_external,
|
|
7
7
|
init_zod
|
|
8
|
-
} from "./cli-
|
|
8
|
+
} from "./cli-3k1x5rn3.js";
|
|
9
9
|
|
|
10
10
|
// src/core/agents/offSecAgent/types.ts
|
|
11
11
|
init_zod();
|