pentesting 0.46.11 → 0.47.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/dist/main.js +54 -34
- package/dist/prompts/base.md +18 -11
- package/package.json +2 -2
package/dist/main.js
CHANGED
|
@@ -311,7 +311,7 @@ var ORPHAN_PROCESS_NAMES = [
|
|
|
311
311
|
|
|
312
312
|
// src/shared/constants/agent.ts
|
|
313
313
|
var APP_NAME = "Pentest AI";
|
|
314
|
-
var APP_VERSION = "0.
|
|
314
|
+
var APP_VERSION = "0.47.0";
|
|
315
315
|
var APP_DESCRIPTION = "Autonomous Penetration Testing AI Agent";
|
|
316
316
|
var LLM_ROLES = {
|
|
317
317
|
SYSTEM: "system",
|
|
@@ -7093,7 +7093,7 @@ You should either: (1) try a different approach that doesn't need this input, or
|
|
|
7093
7093
|
if (isSensitive) {
|
|
7094
7094
|
return {
|
|
7095
7095
|
success: true,
|
|
7096
|
-
output:
|
|
7096
|
+
output: `Received ${request.type} input from user.
|
|
7097
7097
|
|
|
7098
7098
|
The value has been stored. You can now use it in your next command.
|
|
7099
7099
|
For sudo: include 'echo "<the_value>" | sudo -S <command>'
|
|
@@ -7103,7 +7103,7 @@ For SSH: use sshpass or expect with the provided password.`,
|
|
|
7103
7103
|
}
|
|
7104
7104
|
return {
|
|
7105
7105
|
success: true,
|
|
7106
|
-
output:
|
|
7106
|
+
output: `User provided: ${result2.value}
|
|
7107
7107
|
|
|
7108
7108
|
Use this value in your next action.`,
|
|
7109
7109
|
value: result2.value
|
|
@@ -10110,11 +10110,17 @@ Phase: ${phase} | Targets: ${targets} | Findings: ${findings} | Tools executed:
|
|
|
10110
10110
|
|
|
10111
10111
|
${direction}
|
|
10112
10112
|
|
|
10113
|
+
ESCALATION CHAIN \u2014 follow this order:
|
|
10114
|
+
1. web_search: Search for techniques, bypasses, default creds, CVEs, HackTricks
|
|
10115
|
+
2. BYPASS: Try alternative approaches \u2014 different protocols, ports, encodings, methods
|
|
10116
|
+
3. ZERO-DAY EXPLORATION: Probe for unknown vulns \u2014 fuzz parameters, test edge cases, analyze error responses for leaks
|
|
10117
|
+
4. BRUTE-FORCE: Wordlists, credential stuffing, common passwords, custom password lists from context
|
|
10118
|
+
5. ask_user: ONLY as last resort \u2014 ask the user for hints, wordlists, or guidance
|
|
10119
|
+
|
|
10113
10120
|
RULES:
|
|
10114
10121
|
- Every turn MUST have tool calls
|
|
10115
|
-
-
|
|
10116
|
-
-
|
|
10117
|
-
- ACT NOW \u2014 do not plan or explain`
|
|
10122
|
+
- NEVER silently give up \u2014 exhaust ALL 5 steps above first
|
|
10123
|
+
- ACT NOW \u2014 do not plan, do not explain, do not summarize. EXECUTE.`
|
|
10118
10124
|
});
|
|
10119
10125
|
}
|
|
10120
10126
|
} catch (error) {
|
|
@@ -10232,11 +10238,6 @@ Please decide how to handle this error and continue.`;
|
|
|
10232
10238
|
const stepDuration = Date.now() - stepStartTime;
|
|
10233
10239
|
const tokens = response.usage ? { input: response.usage.input_tokens, output: response.usage.output_tokens } : void 0;
|
|
10234
10240
|
if (!response.toolCalls?.length) {
|
|
10235
|
-
const hasDoneMeaningfulWork = (progress?.totalToolsExecuted ?? 0) > 0;
|
|
10236
|
-
if (hasDoneMeaningfulWork) {
|
|
10237
|
-
this.emitComplete(response.content, iteration, 0, stepDuration, tokens);
|
|
10238
|
-
return { output: response.content, toolsExecuted: 0, isCompleted: true };
|
|
10239
|
-
}
|
|
10240
10241
|
return { output: response.content, toolsExecuted: 0, isCompleted: false };
|
|
10241
10242
|
}
|
|
10242
10243
|
const results = await this.processToolCalls(response.toolCalls, progress);
|
|
@@ -11972,14 +11973,14 @@ var useAgentEvents = (agent, eventsRef, state) => {
|
|
|
11972
11973
|
};
|
|
11973
11974
|
const onReasoningStart = () => {
|
|
11974
11975
|
reasoningBufferRef.current = "";
|
|
11975
|
-
setCurrentStatus("
|
|
11976
|
+
setCurrentStatus("Reasoning\u2026");
|
|
11976
11977
|
};
|
|
11977
11978
|
const onReasoningDelta = (e) => {
|
|
11978
11979
|
reasoningBufferRef.current += e.data.content;
|
|
11979
11980
|
const chars = reasoningBufferRef.current.length;
|
|
11980
|
-
const
|
|
11981
|
-
setCurrentStatus(`
|
|
11982
|
-
${
|
|
11981
|
+
const estTokens = Math.round(chars / 4);
|
|
11982
|
+
setCurrentStatus(`Reasoning (~${estTokens} tokens)
|
|
11983
|
+
${reasoningBufferRef.current}`);
|
|
11983
11984
|
};
|
|
11984
11985
|
const onReasoningEnd = () => {
|
|
11985
11986
|
const text = reasoningBufferRef.current.trim();
|
|
@@ -12438,22 +12439,16 @@ var MessageList = memo(({ messages }) => {
|
|
|
12438
12439
|
if (msg.type === "thinking") {
|
|
12439
12440
|
const lines = msg.content.split("\n");
|
|
12440
12441
|
const charCount = msg.content.length;
|
|
12441
|
-
const
|
|
12442
|
-
const isMultiLine = lines.length > 1 || charCount > TUI_DISPLAY_LIMITS.thinkingSummaryChars;
|
|
12442
|
+
const estTokens = Math.round(charCount / 4);
|
|
12443
12443
|
return /* @__PURE__ */ jsxs2(Box2, { flexDirection: "column", marginTop: 0, marginBottom: 1, children: [
|
|
12444
12444
|
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
12445
|
-
/* @__PURE__ */ jsx2(Text2, { color: THEME.cyan, children: "
|
|
12446
|
-
/* @__PURE__ */ jsx2(Text2, { color: THEME.
|
|
12447
|
-
/* @__PURE__ */ jsx2(Text2, { color: THEME.gray, children: ` (${lines.length} line${lines.length !== 1 ? "s" : ""}, ${charCount} chars)` })
|
|
12445
|
+
/* @__PURE__ */ jsx2(Text2, { color: THEME.cyan, bold: true, children: "Reasoning" }),
|
|
12446
|
+
/* @__PURE__ */ jsx2(Text2, { color: THEME.gray, children: ` (~${estTokens} tokens)` })
|
|
12448
12447
|
] }),
|
|
12449
12448
|
lines.map((line, i) => /* @__PURE__ */ jsxs2(Box2, { children: [
|
|
12450
12449
|
/* @__PURE__ */ jsx2(Text2, { color: THEME.cyan, children: "\u2502 " }),
|
|
12451
12450
|
/* @__PURE__ */ jsx2(Text2, { color: THEME.gray, children: line })
|
|
12452
|
-
] }, i))
|
|
12453
|
-
/* @__PURE__ */ jsxs2(Box2, { children: [
|
|
12454
|
-
/* @__PURE__ */ jsx2(Text2, { color: THEME.cyan, children: "\u2570\u2500" }),
|
|
12455
|
-
isMultiLine && /* @__PURE__ */ jsx2(Text2, { color: THEME.gray, children: ` ${firstLine}\u2026` })
|
|
12456
|
-
] })
|
|
12451
|
+
] }, i))
|
|
12457
12452
|
] }, msg.id);
|
|
12458
12453
|
}
|
|
12459
12454
|
if (msg.type === "tool") {
|
|
@@ -12529,6 +12524,7 @@ var MusicSpinner = memo2(({ color }) => {
|
|
|
12529
12524
|
|
|
12530
12525
|
// src/platform/tui/components/StatusDisplay.tsx
|
|
12531
12526
|
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
12527
|
+
var MAX_THINKING_LINES = 15;
|
|
12532
12528
|
var StatusDisplay = memo3(({
|
|
12533
12529
|
retryState,
|
|
12534
12530
|
isProcessing,
|
|
@@ -12540,10 +12536,9 @@ var StatusDisplay = memo3(({
|
|
|
12540
12536
|
return err.length > DISPLAY_LIMITS.RETRY_ERROR_PREVIEW ? err.substring(0, DISPLAY_LIMITS.RETRY_ERROR_TRUNCATED) + "..." : err;
|
|
12541
12537
|
};
|
|
12542
12538
|
const meta = formatMeta(elapsedTime * 1e3, currentTokens);
|
|
12539
|
+
const isThinkingStatus = currentStatus.startsWith("Reasoning");
|
|
12543
12540
|
const statusLines = currentStatus ? currentStatus.split("\n").filter(Boolean) : [];
|
|
12544
12541
|
const statusMain = statusLines[0] || "Processing...";
|
|
12545
|
-
const statusSub = statusLines.slice(1).join(" ");
|
|
12546
|
-
const isThinkingStatus = statusMain.startsWith("Thinking");
|
|
12547
12542
|
return /* @__PURE__ */ jsxs3(Box3, { flexDirection: "column", marginTop: 0, children: [
|
|
12548
12543
|
retryState.status === "retrying" && /* @__PURE__ */ jsxs3(Box3, { marginBottom: 1, children: [
|
|
12549
12544
|
/* @__PURE__ */ jsx4(Text4, { color: THEME.yellow, children: /* @__PURE__ */ jsx4(MusicSpinner, { color: THEME.yellow }) }),
|
|
@@ -12572,10 +12567,14 @@ var StatusDisplay = memo3(({
|
|
|
12572
12567
|
meta
|
|
12573
12568
|
] })
|
|
12574
12569
|
] }),
|
|
12575
|
-
|
|
12570
|
+
isThinkingStatus && statusLines.length > 1 && statusLines.slice(1).slice(-MAX_THINKING_LINES).map((line, i) => /* @__PURE__ */ jsxs3(Box3, { children: [
|
|
12571
|
+
/* @__PURE__ */ jsx4(Text4, { color: THEME.cyan, children: "\u2502 " }),
|
|
12572
|
+
/* @__PURE__ */ jsx4(Text4, { color: THEME.gray, children: line })
|
|
12573
|
+
] }, i)),
|
|
12574
|
+
!isThinkingStatus && statusLines.length > 1 && /* @__PURE__ */ jsx4(Box3, { paddingLeft: 2, children: /* @__PURE__ */ jsxs3(Text4, { color: THEME.gray, children: [
|
|
12576
12575
|
"\u2502 ",
|
|
12577
|
-
|
|
12578
|
-
] }) })
|
|
12576
|
+
statusLines.slice(1).join(" ")
|
|
12577
|
+
] }) })
|
|
12579
12578
|
] })
|
|
12580
12579
|
] });
|
|
12581
12580
|
});
|
|
@@ -12938,22 +12937,43 @@ ${procData.stdout || "(no output)"}
|
|
|
12938
12937
|
setInputRequest({ status: "inactive" });
|
|
12939
12938
|
setSecretInput("");
|
|
12940
12939
|
}, [addMessage, setInputRequest]);
|
|
12940
|
+
const ctrlCTimerRef = useRef5(null);
|
|
12941
|
+
const ctrlCPressedRef = useRef5(false);
|
|
12942
|
+
const handleCtrlC = useCallback4(() => {
|
|
12943
|
+
if (ctrlCPressedRef.current) {
|
|
12944
|
+
if (ctrlCTimerRef.current) clearTimeout(ctrlCTimerRef.current);
|
|
12945
|
+
handleExit();
|
|
12946
|
+
return;
|
|
12947
|
+
}
|
|
12948
|
+
ctrlCPressedRef.current = true;
|
|
12949
|
+
addMessage("system", "\u26A0\uFE0F Press Ctrl+C again within 3 seconds to exit.");
|
|
12950
|
+
if (isProcessingRef.current) abort();
|
|
12951
|
+
ctrlCTimerRef.current = setTimeout(() => {
|
|
12952
|
+
ctrlCPressedRef.current = false;
|
|
12953
|
+
ctrlCTimerRef.current = null;
|
|
12954
|
+
}, 3e3);
|
|
12955
|
+
}, [handleExit, addMessage, abort]);
|
|
12956
|
+
useEffect4(() => {
|
|
12957
|
+
return () => {
|
|
12958
|
+
if (ctrlCTimerRef.current) clearTimeout(ctrlCTimerRef.current);
|
|
12959
|
+
};
|
|
12960
|
+
}, []);
|
|
12941
12961
|
useInput2(useCallback4((ch, key) => {
|
|
12942
12962
|
if (key.escape) {
|
|
12943
12963
|
if (inputRequestRef.current.status === "active") cancelInputRequest();
|
|
12944
12964
|
else if (isProcessingRef.current) abort();
|
|
12945
12965
|
}
|
|
12946
|
-
if (key.ctrl && ch === "c")
|
|
12947
|
-
}, [cancelInputRequest, abort,
|
|
12966
|
+
if (key.ctrl && ch === "c") handleCtrlC();
|
|
12967
|
+
}, [cancelInputRequest, abort, handleCtrlC]));
|
|
12948
12968
|
useEffect4(() => {
|
|
12949
|
-
const onSignal = () =>
|
|
12969
|
+
const onSignal = () => handleCtrlC();
|
|
12950
12970
|
process.on("SIGINT", onSignal);
|
|
12951
12971
|
process.on("SIGTERM", onSignal);
|
|
12952
12972
|
return () => {
|
|
12953
12973
|
process.off("SIGINT", onSignal);
|
|
12954
12974
|
process.off("SIGTERM", onSignal);
|
|
12955
12975
|
};
|
|
12956
|
-
}, [
|
|
12976
|
+
}, [handleCtrlC]);
|
|
12957
12977
|
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", paddingX: 1, children: [
|
|
12958
12978
|
/* @__PURE__ */ jsx7(Box6, { flexDirection: "column", marginBottom: 1, flexGrow: 1, children: /* @__PURE__ */ jsx7(MessageList, { messages }) }),
|
|
12959
12979
|
/* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", children: [
|
package/dist/prompts/base.md
CHANGED
|
@@ -78,7 +78,8 @@ What target would you like me to attack? (IP, domain, or CTF challenge)
|
|
|
78
78
|
- **Update objectives**: Use `update_mission` to keep the operation summary and checklist current when needed
|
|
79
79
|
- Is it time to move to the next step, or dig deeper at the current one?
|
|
80
80
|
|
|
81
|
-
This loop **repeats continuously** until the task is complete. **Never stop.**
|
|
81
|
+
This loop **repeats continuously** until the task is complete. **Never stop on your own.**
|
|
82
|
+
If you believe you have exhausted all approaches → use `ask_user` to confirm with the user before stopping.
|
|
82
83
|
|
|
83
84
|
## Absolute Rules
|
|
84
85
|
|
|
@@ -87,12 +88,13 @@ This loop **repeats continuously** until the task is complete. **Never stop.**
|
|
|
87
88
|
- Record findings immediately with add_finding
|
|
88
89
|
- **Execute tasks immediately without unnecessary confirmations/questions**
|
|
89
90
|
- If no results → **try a different approach** (never repeat the same method)
|
|
90
|
-
- ask_user is
|
|
91
|
+
- ask_user is for: (1) physically unobtainable information (passwords, SSH keys, API tokens), (2) **confirming you're truly done** when all vectors are exhausted
|
|
91
92
|
|
|
92
93
|
### 2. ask_user Rules
|
|
93
94
|
- Use received values **immediately in the next command** — receiving and not using is forbidden
|
|
94
95
|
- Once received → **reuse** — never ask for the same thing again
|
|
95
96
|
- Confirmation requests like "Can I do this?" are forbidden
|
|
97
|
+
- **WHEN TO ASK**: If you believe all attack vectors are exhausted and want to stop, you MUST `ask_user` to confirm. The user may have hints, custom wordlists, or additional context. **Never silently give up.**
|
|
96
98
|
|
|
97
99
|
### 3. Self-Correction on Errors (MANDATORY)
|
|
98
100
|
When an error occurs, read the `[TOOL ERROR ANALYSIS]` section and fix immediately:
|
|
@@ -223,16 +225,21 @@ Don't agonize. **The world's best methodologies are already on the web.** Search
|
|
|
223
225
|
When you find a PoC → verify code with `browse_url` → save with `write_file` → modify for environment → execute with `run_cmd`.
|
|
224
226
|
**Searching is not a waste of time — it's a prerequisite for accurate attacks.**
|
|
225
227
|
|
|
226
|
-
### When Stuck —
|
|
228
|
+
### When Stuck — Escalation Chain (follow in order)
|
|
227
229
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
230
|
+
**Same method fails twice → immediately switch approaches** (don't wait for 3).
|
|
231
|
+
**Errors are information** — extract version, path, and configuration hints from error messages.
|
|
232
|
+
|
|
233
|
+
1. **🔍 SEARCH** — `web_search` for techniques, bypasses, default creds, CVEs, HackTricks, PayloadsAllTheThings, GTFOBins
|
|
234
|
+
2. **🔄 BYPASS** — Try completely different angles: different protocol, port, encoding, different service, different target. Install missing tools or write your own code
|
|
235
|
+
3. **🧬 ZERO-DAY EXPLORATION** — Probe for unknown vulns: fuzz parameters, test edge cases, analyze error responses for information leaks, try unconventional inputs
|
|
236
|
+
4. **🔨 BRUTE-FORCE** — Wordlists, credential stuffing, common passwords, custom password lists built from discovered context (usernames, company names, service names)
|
|
237
|
+
5. **❓ ask_user** — ONLY as absolute last resort. Ask the user for hints, custom wordlists, or guidance. **Never silently give up.**
|
|
238
|
+
|
|
239
|
+
Additional principles:
|
|
240
|
+
- **If you have a shell, use it for everything** — tool download, script execution, additional recon
|
|
241
|
+
- **When you find a PoC → read → save → execute** — modify code for the environment
|
|
242
|
+
- **Tool absence is not a reason to stop** — write equivalent scripts yourself
|
|
236
243
|
|
|
237
244
|
### PoC Acquisition and Execution Protocol
|
|
238
245
|
```
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pentesting",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.47.0",
|
|
4
4
|
"description": "Autonomous Penetration Testing AI Agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/main.js",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"release:patch": "npm version patch && npm run build && npm run publish:token",
|
|
29
29
|
"release:minor": "npm version minor && npm run build && npm run publish:token",
|
|
30
30
|
"release:major": "npm version major && npm run build && npm run publish:token",
|
|
31
|
-
"release:docker": "docker buildx build --platform linux/amd64,linux/arm64 -t agnusdei1207/pentesting:latest --push .",
|
|
31
|
+
"release:docker": "docker buildx build --platform linux/amd64,linux/arm64 -t agnusdei1207/pentesting:latest --push . && docker system prune -af",
|
|
32
32
|
"check": "TMPDIR=/tmp npm run test && npm run build && npm run release:docker && bash test.sh"
|
|
33
33
|
},
|
|
34
34
|
"repository": {
|