pentesting 0.72.10 → 0.73.1
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/README.md +31 -4
- package/dist/agent-tool-COMG67ES.js +256 -0
- package/dist/chunk-EUWDAGHZ.js +11710 -0
- package/dist/{chunk-GHJPYI4S.js → chunk-YFDJI3GO.js} +11 -1
- package/dist/{chunk-SLDFXMHL.js → chunk-ZQAVMACI.js} +882 -139
- package/dist/main.js +1206 -13248
- package/dist/{persistence-7FTYXIZY.js → persistence-SNUMO4WG.js} +2 -2
- package/dist/{process-registry-CCAQVJ4Y.js → process-registry-GSHEX2LT.js} +3 -1
- package/dist/prompts/base.md +1 -0
- package/dist/prompts/llm/analyst-system.md +7 -0
- package/dist/prompts/{orchestrator.md → main-agent.md} +31 -1
- package/dist/prompts/strategist-system.md +27 -0
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
<img src="https://api.iconify.design/game-icons:fizzing-flask.svg?color=%
|
|
3
|
+
<img src="https://api.iconify.design/game-icons:fizzing-flask.svg?color=%23E63946" width="80" height="80" alt="Pentesting Agent" />
|
|
4
4
|
|
|
5
5
|
# pentesting
|
|
6
6
|
> **Autonomous Offensive Security AI Agent**
|
|
7
7
|
|
|
8
8
|
[](https://www.npmjs.org/package/pentesting)
|
|
9
|
-
[](https://hub.docker.com/r/agnusdei1207/pentesting)
|
|
10
10
|
|
|
11
11
|
</div>
|
|
12
12
|
|
|
@@ -57,6 +57,8 @@ docker run -it --rm \
|
|
|
57
57
|
agnusdei1207/pentesting
|
|
58
58
|
```
|
|
59
59
|
|
|
60
|
+
Enable container Tor mode by adding `-e PENTEST_TOR=true` to the same `docker run` command.
|
|
61
|
+
|
|
60
62
|
### External Search API (Optional)
|
|
61
63
|
|
|
62
64
|
For providers other than z.ai, or to use a dedicated search backend.
|
|
@@ -76,10 +78,35 @@ docker run -it --rm \
|
|
|
76
78
|
| Variable | Required | Description |
|
|
77
79
|
|----------|----------|-------------|
|
|
78
80
|
| `PENTEST_API_KEY` | ✅ | LLM API key |
|
|
79
|
-
| `PENTEST_BASE_URL` |
|
|
80
|
-
| `PENTEST_MODEL` |
|
|
81
|
+
| `PENTEST_BASE_URL` | ❌ | Custom API endpoint (web search auto-enabled when URL contains `z.ai`) |
|
|
82
|
+
| `PENTEST_MODEL` | ❌ | Model override (defaults depend on provider/runtime; examples use `glm-4.7`) |
|
|
81
83
|
| `SEARCH_API_KEY` | ❌ | External search API key (not needed with z.ai) |
|
|
82
84
|
| `SEARCH_API_URL` | ❌ | External search API URL (not needed with z.ai) |
|
|
85
|
+
| `PENTEST_SCOPE_MODE` | ❌ | Scope mode override: `advisory` or `enforce` |
|
|
86
|
+
| `PENTEST_APPROVAL_MODE` | ❌ | Approval mode override: `advisory` or `require_auto_approve` |
|
|
87
|
+
| `PENTEST_TOR` | ❌ | Container-only Tor mode. When `true`, the Docker entrypoint starts Tor and launches the agent through `proxychains4` |
|
|
88
|
+
|
|
89
|
+
Safety defaults:
|
|
90
|
+
|
|
91
|
+
- Containerized runtime defaults to `PENTEST_SCOPE_MODE=advisory` and `PENTEST_APPROVAL_MODE=advisory`.
|
|
92
|
+
- Non-container runtime defaults to `PENTEST_SCOPE_MODE=enforce` and `PENTEST_APPROVAL_MODE=require_auto_approve`.
|
|
93
|
+
- Explicit env vars override those defaults.
|
|
94
|
+
|
|
95
|
+
Tor notes:
|
|
96
|
+
|
|
97
|
+
- Tor is supported only in the containerized runtime.
|
|
98
|
+
- There is no in-app `/tor` toggle. Enable it at container startup with `-e PENTEST_TOR=true`.
|
|
99
|
+
- Non-container runs ignore `PENTEST_TOR`, so local host execution stays on direct networking.
|
|
100
|
+
|
|
101
|
+
### Developer Verification
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
npm run verify
|
|
105
|
+
npm run verify:docker
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
- `npm run check` runs the full non-destructive verification flow.
|
|
109
|
+
- `npm run check:clean` additionally performs `docker system prune -af --volumes` before the full check.
|
|
83
110
|
|
|
84
111
|
---
|
|
85
112
|
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CategorizedToolRegistry,
|
|
3
|
+
CoreAgent,
|
|
4
|
+
createContextExtractor,
|
|
5
|
+
getLLMClient
|
|
6
|
+
} from "./chunk-EUWDAGHZ.js";
|
|
7
|
+
import {
|
|
8
|
+
AGENT_ROLES,
|
|
9
|
+
EVENT_TYPES,
|
|
10
|
+
LLM_ROLES,
|
|
11
|
+
TOOL_NAMES
|
|
12
|
+
} from "./chunk-ZQAVMACI.js";
|
|
13
|
+
import {
|
|
14
|
+
getActiveProcessSummary
|
|
15
|
+
} from "./chunk-YFDJI3GO.js";
|
|
16
|
+
|
|
17
|
+
// src/engine/agent-tool/completion-box.ts
|
|
18
|
+
function createCompletionBox() {
|
|
19
|
+
return { done: false, result: null };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// src/engine/agent-tool/task-complete.ts
|
|
23
|
+
function createTaskCompleteTool(completion) {
|
|
24
|
+
return {
|
|
25
|
+
name: TOOL_NAMES.TASK_COMPLETE,
|
|
26
|
+
description: `Signal task completion. Call this when the delegated task is done.
|
|
27
|
+
Include all findings and loot discovered during the task.
|
|
28
|
+
Use status: 'success' if goal achieved, 'partial' if partially done, 'failed' if blocked.`,
|
|
29
|
+
parameters: {
|
|
30
|
+
status: {
|
|
31
|
+
type: "string",
|
|
32
|
+
enum: ["success", "partial", "failed"],
|
|
33
|
+
description: "Task completion status"
|
|
34
|
+
},
|
|
35
|
+
summary: {
|
|
36
|
+
type: "string",
|
|
37
|
+
description: "What was accomplished (or why it failed)"
|
|
38
|
+
},
|
|
39
|
+
tried: {
|
|
40
|
+
type: "array",
|
|
41
|
+
items: { type: "string" },
|
|
42
|
+
description: "Approaches attempted during the task"
|
|
43
|
+
},
|
|
44
|
+
findings: {
|
|
45
|
+
type: "array",
|
|
46
|
+
items: { type: "string" },
|
|
47
|
+
description: "Security findings discovered (summary for main loop)"
|
|
48
|
+
},
|
|
49
|
+
loot: {
|
|
50
|
+
type: "array",
|
|
51
|
+
items: { type: "string" },
|
|
52
|
+
description: "Credentials, flags, or sensitive data obtained"
|
|
53
|
+
},
|
|
54
|
+
sessions: {
|
|
55
|
+
type: "array",
|
|
56
|
+
items: { type: "string" },
|
|
57
|
+
description: "Active session IDs established during the task"
|
|
58
|
+
},
|
|
59
|
+
suggested_next: {
|
|
60
|
+
type: "string",
|
|
61
|
+
description: "Recommended next action for the main agent"
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
required: ["status", "summary"],
|
|
65
|
+
execute: async (params) => {
|
|
66
|
+
const result = {
|
|
67
|
+
status: params["status"] ?? "partial",
|
|
68
|
+
summary: params["summary"] ?? "",
|
|
69
|
+
tried: params["tried"] ?? [],
|
|
70
|
+
findings: params["findings"] ?? [],
|
|
71
|
+
loot: params["loot"] ?? [],
|
|
72
|
+
sessions: params["sessions"] ?? [],
|
|
73
|
+
suggestedNext: params["suggested_next"] ?? ""
|
|
74
|
+
};
|
|
75
|
+
completion.done = true;
|
|
76
|
+
completion.result = result;
|
|
77
|
+
return {
|
|
78
|
+
success: true,
|
|
79
|
+
output: [
|
|
80
|
+
"[TASK_COMPLETE]",
|
|
81
|
+
`[Status] ${result.status}`,
|
|
82
|
+
`[Summary] ${result.summary}`
|
|
83
|
+
].join("\n")
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// src/engine/agent-tool/agent-registry.ts
|
|
90
|
+
var AgentRegistry = class extends CategorizedToolRegistry {
|
|
91
|
+
constructor(state, scopeGuard, approvalGate, events, completion) {
|
|
92
|
+
super(state, scopeGuard, approvalGate, events);
|
|
93
|
+
const taskCompleteTool = createTaskCompleteTool(completion);
|
|
94
|
+
this.tools.set(taskCompleteTool.name, taskCompleteTool);
|
|
95
|
+
}
|
|
96
|
+
initializeRegistry() {
|
|
97
|
+
super.initializeRegistry();
|
|
98
|
+
this.tools.delete(TOOL_NAMES.RUN_TASK);
|
|
99
|
+
this.tools.delete(TOOL_NAMES.ASK_USER);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
// src/engine/agent-tool/agent-runner.ts
|
|
104
|
+
var MAX_AGENT_TOOL_ITERATIONS = 30;
|
|
105
|
+
var COMPRESS_EVERY_N_STEPS = 5;
|
|
106
|
+
var MAX_COMPRESS_FAILURES = 3;
|
|
107
|
+
var AgentRunner = class extends CoreAgent {
|
|
108
|
+
completion;
|
|
109
|
+
contextExtractor;
|
|
110
|
+
stepCount = 0;
|
|
111
|
+
consecutiveCompressFailures = 0;
|
|
112
|
+
constructor(state, events, registry, completion) {
|
|
113
|
+
super(AGENT_ROLES.AGENT_TOOL, state, events, registry, MAX_AGENT_TOOL_ITERATIONS);
|
|
114
|
+
this.completion = completion;
|
|
115
|
+
this.contextExtractor = createContextExtractor(getLLMClient());
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* CoreAgent.step() 오버라이드
|
|
119
|
+
*
|
|
120
|
+
* 추가 동작 (super.step() 이후):
|
|
121
|
+
* 1. completion.done 확인 → task_complete 호출됐으면 즉시 완료 신호
|
|
122
|
+
* 2. COMPRESS_EVERY_N_STEPS마다 ContextExtractor 호출
|
|
123
|
+
*/
|
|
124
|
+
async step(iteration, messages, systemPrompt, progress) {
|
|
125
|
+
const result = await super.step(iteration, messages, systemPrompt, progress);
|
|
126
|
+
if (this.completion.done) {
|
|
127
|
+
return {
|
|
128
|
+
output: JSON.stringify(this.completion.result),
|
|
129
|
+
toolsExecuted: result.toolsExecuted,
|
|
130
|
+
isCompleted: true
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
this.stepCount++;
|
|
134
|
+
if (this.stepCount % COMPRESS_EVERY_N_STEPS === 0) {
|
|
135
|
+
await this.compressContext(messages);
|
|
136
|
+
}
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* ContextExtractor를 사용해 messages[]를 1개 session-context로 압축.
|
|
141
|
+
*
|
|
142
|
+
* WHY: 실패 시 무시 (try/catch). CoreAgent의 trimMessagesIfNeeded(50)이
|
|
143
|
+
* 최후 안전망이므로 압축 실패가 치명적이지 않다.
|
|
144
|
+
* WHY (failure tracking): 연속 실패가 MAX_COMPRESS_FAILURES 초과 시 경고 emit.
|
|
145
|
+
* sub-agent가 초기 task를 잃어버릴 위험을 TUI에 노출해 사용자가 인지할 수 있게 한다.
|
|
146
|
+
*/
|
|
147
|
+
async compressContext(messages) {
|
|
148
|
+
try {
|
|
149
|
+
const result = await this.contextExtractor.execute({ messages });
|
|
150
|
+
if (result.success && result.extractedContext) {
|
|
151
|
+
messages.length = 0;
|
|
152
|
+
messages.push({
|
|
153
|
+
role: LLM_ROLES.USER,
|
|
154
|
+
content: `<session-context>
|
|
155
|
+
${result.extractedContext}
|
|
156
|
+
</session-context>`
|
|
157
|
+
});
|
|
158
|
+
this.consecutiveCompressFailures = 0;
|
|
159
|
+
}
|
|
160
|
+
} catch {
|
|
161
|
+
this.consecutiveCompressFailures++;
|
|
162
|
+
if (this.consecutiveCompressFailures === MAX_COMPRESS_FAILURES) {
|
|
163
|
+
this.events.emit({
|
|
164
|
+
type: EVENT_TYPES.NOTIFICATION,
|
|
165
|
+
timestamp: Date.now(),
|
|
166
|
+
data: {
|
|
167
|
+
title: "Sub-Agent Context Warning",
|
|
168
|
+
message: `Context compression failed ${this.consecutiveCompressFailures}x in a row. Sub-agent may lose task direction. Consider reducing task scope.`,
|
|
169
|
+
level: "warning"
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
// src/engine/agent-tool/agent-prompt.ts
|
|
178
|
+
function buildAgentPrompt(input) {
|
|
179
|
+
const parts = [
|
|
180
|
+
"You are an autonomous execution agent. Complete the delegated task using available tools.",
|
|
181
|
+
"",
|
|
182
|
+
`## Task
|
|
183
|
+
${input.task}`
|
|
184
|
+
];
|
|
185
|
+
if (input.target) {
|
|
186
|
+
parts.push(`
|
|
187
|
+
## Target
|
|
188
|
+
${input.target}`);
|
|
189
|
+
}
|
|
190
|
+
if (input.context) {
|
|
191
|
+
parts.push(`
|
|
192
|
+
## Context
|
|
193
|
+
${input.context}`);
|
|
194
|
+
}
|
|
195
|
+
const activeProcesses = getActiveProcessSummary();
|
|
196
|
+
if (activeProcesses) {
|
|
197
|
+
parts.push(`
|
|
198
|
+
## Active Background Processes
|
|
199
|
+
${activeProcesses}`);
|
|
200
|
+
}
|
|
201
|
+
parts.push(`
|
|
202
|
+
## Rules
|
|
203
|
+
- Do NOT call ask_user. You are autonomous. Make your best judgment.
|
|
204
|
+
- Call task_complete when the task is done (status: success, partial, or failed).
|
|
205
|
+
- Record findings with add_finding, loot with add_loot as you discover them.
|
|
206
|
+
- If you hit 3 consecutive failures on the same approach, switch vectors or declare failed.
|
|
207
|
+
- Be decisive \u2014 do not loop indefinitely on the same approach.`);
|
|
208
|
+
return parts.join("\n");
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// src/engine/agent-tool/agent-tool.ts
|
|
212
|
+
var TIMEOUT_RESULT = {
|
|
213
|
+
status: "failed",
|
|
214
|
+
summary: `Agent-tool timed out: max ${MAX_AGENT_TOOL_ITERATIONS} iterations reached without task_complete.`,
|
|
215
|
+
tried: [],
|
|
216
|
+
findings: [],
|
|
217
|
+
loot: [],
|
|
218
|
+
sessions: [],
|
|
219
|
+
suggestedNext: "Break the task into smaller sub-tasks and retry."
|
|
220
|
+
};
|
|
221
|
+
var AgentTool = class {
|
|
222
|
+
constructor(state, events, scopeGuard, approvalGate) {
|
|
223
|
+
this.state = state;
|
|
224
|
+
this.events = events;
|
|
225
|
+
this.scopeGuard = scopeGuard;
|
|
226
|
+
this.approvalGate = approvalGate;
|
|
227
|
+
}
|
|
228
|
+
async execute(input) {
|
|
229
|
+
const completion = createCompletionBox();
|
|
230
|
+
const registry = new AgentRegistry(
|
|
231
|
+
this.state,
|
|
232
|
+
this.scopeGuard,
|
|
233
|
+
this.approvalGate,
|
|
234
|
+
this.events,
|
|
235
|
+
completion
|
|
236
|
+
);
|
|
237
|
+
const runner = new AgentRunner(
|
|
238
|
+
this.state,
|
|
239
|
+
this.events,
|
|
240
|
+
registry,
|
|
241
|
+
completion
|
|
242
|
+
);
|
|
243
|
+
const prompt = buildAgentPrompt(input);
|
|
244
|
+
const loopResult = await runner.run(input.task, prompt);
|
|
245
|
+
if (completion.done && completion.result) {
|
|
246
|
+
return completion.result;
|
|
247
|
+
}
|
|
248
|
+
return {
|
|
249
|
+
...TIMEOUT_RESULT,
|
|
250
|
+
tried: [`Reached ${loopResult.iterations} iterations without calling task_complete`]
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
export {
|
|
255
|
+
AgentTool
|
|
256
|
+
};
|