pentesting 0.2.3 → 0.2.5

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.
Files changed (3) hide show
  1. package/README.md +149 -121
  2. package/dist/index.js +235 -182
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,130 +1,125 @@
1
- # Pentesting
2
-
3
- > 🎯 DEF CON-level Autonomous Penetration Testing AI Agent
4
-
5
- <p align="center">
6
- <img src="assets/logo.png" alt="Pentesting Logo" width="200"/>
7
- </p>
1
+ ```
2
+ ╔═══════════════════════════════════════════════════════════════╗
3
+ ║ ║
4
+ ║ ██████╗ ███████╗███╗ ██╗████████╗███████╗███████╗████████╗║
5
+ ║ ██╔══██╗██╔════╝████╗ ██║╚══██╔══╝██╔════╝██╔════╝╚══██╔══╝║
6
+ ║ ██████╔╝█████╗ ██╔██╗ ██║ ██║ █████╗ ███████╗ ██║ ║
7
+ ║ ██╔═══╝ ██╔══╝ ██║╚██╗██║ ██║ ██╔══╝ ╚════██║ ██║ ║
8
+ ║ ██║ ███████╗██║ ╚████║ ██║ ███████╗███████║ ██║ ║
9
+ ║ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚══════╝╚══════╝ ╚═╝ ║
10
+ ║ ║
11
+ ║ 🎯 DEF CON-level Autonomous Pentesting Agent ║
12
+ ║ ║
13
+ ╚═══════════════════════════════════════════════════════════════╝
14
+ ```
8
15
 
9
16
  [![npm version](https://badge.fury.io/js/pentesting.svg)](https://www.npmjs.com/package/pentesting)
10
17
  [![Docker](https://img.shields.io/badge/Docker-pentesting--tools-blue)](https://hub.docker.com/r/agnusdei1207/pentesting-tools)
11
18
 
12
- ## ✨ Features
13
-
14
- - **7-Phase Attack Workflow**: Recon → Scan → Enum → Vuln Analysis → Exploitation → PrivEsc → Reporting
15
- - **9 Specialized Agents**: Built-in experts for each security domain
16
- - **Ralph Loop**: Autonomous iteration until objective is achieved
17
- - **Streaming Responses**: Real-time output from Claude
18
- - **Session Persistence**: Save/resume pentesting sessions
19
- - **Tool Approval**: Manual confirmation for dangerous commands
20
- - **MCP Integration**: Extend with Model Context Protocol tools
21
- - **Docker Toolkit**: 50+ pre-installed pentesting tools
22
-
23
- ## Quick Start
19
+ ---
24
20
 
25
- ### Install
21
+ ## 🚀 Quick Start
26
22
 
27
23
  ```bash
24
+ # Install
28
25
  npm install -g pentesting
29
- ```
30
-
31
- ### Configure
32
26
 
33
- ```bash
34
- # Required: API Key (either works)
27
+ # Configure
35
28
  export PENTEST_API_KEY=your_api_key
36
- # or
37
- export ANTHROPIC_API_KEY=your_api_key
38
-
39
- # For other providers (GLM, OpenRouter, etc.)
40
29
  export PENTEST_BASE_URL=https://your-api-endpoint.com/v1
41
30
  export PENTEST_MODEL=your-model-name
42
- export PENTEST_MAX_TOKENS=16384
43
- ```
44
31
 
45
- ### Run
32
+ export PENTEST_API_KEY="key"
33
+ export PENTEST_BASE_URL="https://api.z.ai/api/anthropic"
34
+ export PENTEST_MODEL="glm-4.7"
46
35
 
47
- ```bash
48
- pentesting # Interactive mode
49
- pentesting --yolo # Auto-approve all tools (dangerous!)
36
+
37
+ # Run
38
+ pentesting
50
39
  ```
51
40
 
52
- ## CLI Commands
41
+ ---
42
+
43
+ ## ✨ Features
44
+
45
+ - **10-Phase Attack Workflow**: Recon → Scan → Enum → Vuln Analysis → Exploitation → PrivEsc → Pivot → Persist → Exfil → Report
46
+ - **9 Specialized Agents**: Built-in experts for each security domain
47
+ - **Ralph Loop**: Autonomous iteration until objective is achieved
48
+ - **Streaming Responses**: Real-time LLM output
49
+ - **Session Persistence**: Save/resume pentesting sessions
50
+ - **Tool Approval**: Manual confirmation for dangerous commands
51
+ - **MCP Integration**: Extend with Model Context Protocol tools
52
+ - **Docker Toolkit**: 50+ pre-installed pentesting tools
53
+ - **Provider Agnostic**: Works with any OpenAI-compatible API
54
+
55
+ ---
56
+
57
+ ## 📖 CLI Commands
53
58
 
54
59
  ```bash
60
+ # Target & Session
55
61
  /target <ip> Set target
56
62
  /start [objective] Start autonomous pentest
63
+ /sessions List saved sessions
64
+ /resume [id] Resume a session
65
+
66
+ # Scanning & Enumeration
57
67
  /scan <target> Quick enumeration
68
+ /web <url> Web application testing
69
+
70
+ # Exploitation
58
71
  /exploit <service> Search for exploits
59
72
  /privesc [os] Check privilege escalation vectors
60
- /web <url> Web application testing
61
- /hash <hash> Identify and crack hashes
62
73
  /attack <objective> Execute attack chain
74
+ /hash <hash> Identify and crack hashes
75
+
76
+ # Reporting
63
77
  /report Generate pentest report
64
- /sessions List saved sessions
65
- /resume [id] Resume a session
78
+ /findings Show findings
79
+
80
+ # Control
66
81
  /yolo Toggle auto-approve mode
67
82
  /approve /deny Approve/deny tool execution
68
- /findings Show findings
69
83
  /clear Clear screen
70
84
  /exit Exit
71
85
  ```
72
86
 
73
- ## Built-in Agents
87
+ ---
88
+
89
+ ## 🤖 Built-in Agents
74
90
 
75
91
  | Agent | Specialty |
76
92
  |-------|-----------|
77
- | **target-explorer** | Network reconnaissance, service enumeration |
78
- | **exploit-researcher** | CVE research, exploit development |
79
- | **privesc-master** | Linux/Windows privilege escalation |
80
- | **web-hacker** | OWASP Top 10, SQLi, XSS, SSRF |
81
- | **crypto-solver** | Hash cracking, cipher analysis |
82
- | **forensics-analyst** | Memory forensics, file carving |
83
- | **reverse-engineer** | Binary analysis, exploit development |
84
- | **attack-architect** | Attack strategy planning |
85
- | **finding-reviewer** | Vulnerability validation |
86
-
87
- ## Architecture
93
+ | `target-explorer` | Network reconnaissance, service enumeration |
94
+ | `exploit-researcher` | CVE research, exploit development |
95
+ | `privesc-master` | Linux/Windows privilege escalation |
96
+ | `web-hacker` | OWASP Top 10, SQLi, XSS, SSRF |
97
+ | `crypto-solver` | Hash cracking, cipher analysis |
98
+ | `forensics-analyst` | Memory forensics, file carving |
99
+ | `reverse-engineer` | Binary analysis, exploit development |
100
+ | `attack-architect` | Attack strategy planning |
101
+ | `finding-reviewer` | Vulnerability validation |
88
102
 
89
- ```
90
- ┌─────────────────────────────────────────────────────────────┐
91
- │ TUI (app.tsx) │
92
- │ - Streaming text display │
93
- │ - Tool approval prompts │
94
- │ - Session management │
95
- └──────────────────────────┬──────────────────────────────────┘
96
- │ Wire Protocol
97
- ┌──────────────────────────▼──────────────────────────────────┐
98
- │ PentestingAgent (Unified) │
99
- │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
100
- │ │ RalphLoop │ │ Streaming │ │ Session │ │
101
- │ │ (Auto-iter) │ │ Handler │ │ Manager │ │
102
- │ └──────────────┘ └──────────────┘ └──────────────┘ │
103
- │ │
104
- │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
105
- │ │ Context │ │ Retry │ │ Approval │ │
106
- │ │ Compaction │ │ Handler │ │ Manager │ │
107
- │ └──────────────┘ └──────────────┘ └──────────────┘ │
108
- │ │
109
- │ ┌──────────────────────────────────────────────────┐ │
110
- │ │ AutonomousHackingAgent (Core) │ │
111
- │ │ ┌──────────────────────────────────────────┐ │ │
112
- │ │ │ 9 Built-in Specialized Agents │ │ │
113
- │ │ │ (No plugins needed) │ │ │
114
- │ │ └──────────────────────────────────────────┘ │ │
115
- │ │ - Hook System │ │
116
- │ │ - MCP Client for Extended Tools │ │
117
- │ └──────────────────────────────────────────────────┘ │
118
- └──────────────────────────┬──────────────────────────────────┘
119
-
120
- ┌────────────────┼────────────────┐
121
- ┌────▼────┐ ┌────▼────┐ ┌────▼────┐
122
- │ Tool │ │ Bash │ │ MCP │
123
- │Executor │ │ Commands│ │ Servers │
124
- └─────────┘ └─────────┘ └─────────┘
125
- ```
103
+ ---
104
+
105
+ ## ⚙️ Configuration
126
106
 
127
- ## Programmatic Usage
107
+ ### Environment Variables
108
+
109
+ | Variable | Description | Default |
110
+ |----------|-------------|---------|
111
+ | `PENTEST_API_KEY` | LLM API key | Required |
112
+ | `PENTEST_BASE_URL` | API endpoint URL | - |
113
+ | `PENTEST_MODEL` | Model name | claude-sonnet-4-20250514 |
114
+ | `PENTEST_MAX_TOKENS` | Max response tokens | 16384 |
115
+ | `PENTESTING_DOCKER` | Force Docker execution | 0 |
116
+ | `PENTESTING_CONTAINER` | Docker container name | pentesting-tools |
117
+
118
+ > **Note**: `ANTHROPIC_API_KEY` is also accepted as fallback for `PENTEST_API_KEY`.
119
+
120
+ ---
121
+
122
+ ## 💻 Programmatic Usage
128
123
 
129
124
  ```typescript
130
125
  import { PentestingAgent, PENTEST_EVENT } from 'pentesting';
@@ -158,7 +153,9 @@ const scanResult = await agent.chat('/scan 10.10.10.1');
158
153
  const exploitResult = await agent.chat('/exploit Apache 2.4.49');
159
154
  ```
160
155
 
161
- ## Docker Environment
156
+ ---
157
+
158
+ ## 🐳 Docker Environment
162
159
 
163
160
  ```bash
164
161
  # Pull pre-built toolkit (50+ tools)
@@ -173,7 +170,9 @@ docker run -d --name pentesting-tools --network host \
173
170
  docker exec -it pentesting-tools nmap -sCV 10.0.0.1
174
171
  ```
175
172
 
176
- ## MCP Integration
173
+ ---
174
+
175
+ ## 🔌 MCP Integration
177
176
 
178
177
  Extend with additional MCP servers:
179
178
 
@@ -191,32 +190,50 @@ await agent.addMCPServer('security-tools', 'docker', [
191
190
  ]);
192
191
  ```
193
192
 
194
- ## Configuration
193
+ ---
195
194
 
196
- ### Environment Variables
195
+ ## 🏗️ Architecture
197
196
 
198
- | Variable | Description | Default |
199
- |----------|-------------|---------|
200
- | PENTEST_API_KEY | API key (alternative: ANTHROPIC_API_KEY) | Required |
201
- | PENTEST_BASE_URL | API endpoint URL (for GLM, etc.) | - |
202
- | PENTEST_MODEL | Model name | claude-sonnet-4-20250514 |
203
- | PENTEST_MAX_TOKENS | Max response tokens | 16384 |
204
- | PENTESTING_DOCKER | Force Docker execution | 0 |
205
- | PENTESTING_CONTAINER | Docker container name | pentesting-tools |
197
+ ```
198
+ ┌─────────────────────────────────────────────────────────────┐
199
+ │ TUI (app.tsx)
200
+ │ - Streaming text display │
201
+ │ - Tool approval prompts │
202
+ │ - Session management │
203
+ └──────────────────────────┬──────────────────────────────────┘
204
+ Wire Protocol
205
+ ┌──────────────────────────▼──────────────────────────────────┐
206
+ │ PentestingAgent (Unified) │
207
+ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
208
+ │ │ RalphLoop │ │ Streaming │ │ Session │ │
209
+ │ │ (Auto-iter) │ │ Handler │ │ Manager │ │
210
+ │ └──────────────┘ └──────────────┘ └──────────────┘ │
211
+ │ │
212
+ │ ┌──────────────────────────────────────────────────┐ │
213
+ │ │ AutonomousHackingAgent (Core) │ │
214
+ │ │ ┌──────────────────────────────────────────┐ │ │
215
+ │ │ │ 9 Built-in Specialized Agents │ │ │
216
+ │ │ └──────────────────────────────────────────┘ │ │
217
+ │ └──────────────────────────────────────────────────┘ │
218
+ └──────────────────────────┬──────────────────────────────────┘
219
+
220
+ ┌────────────────┼────────────────┐
221
+ ┌────▼────┐ ┌────▼────┐ ┌────▼────┐
222
+ │ Tool │ │ Bash │ │ MCP │
223
+ │Executor │ │ Commands│ │ Servers │
224
+ └─────────┘ └─────────┘ └─────────┘
225
+ ```
226
+
227
+ ---
206
228
 
207
- ## Project Structure
229
+ ## 📁 Project Structure
208
230
 
209
231
  ```
210
232
  src/
211
233
  ├── index.tsx # CLI entry point
212
- ├── cli/
213
- │ └── app.tsx # TUI with streaming, approval, sessions
234
+ ├── cli/app.tsx # TUI with streaming, approval, sessions
214
235
  ├── core/
215
- │ ├── index.ts # All core exports
216
- │ ├── agent/
217
- │ │ ├── pentesting-agent.ts # Unified agent
218
- │ │ ├── autonomous-agent.ts # Core agent logic
219
- │ │ └── agent-orchestrator.ts # Parallel agent execution
236
+ │ ├── agent/ # Agent implementations
220
237
  │ ├── approval/ # Tool approval system
221
238
  │ ├── context/ # Conversation compaction
222
239
  │ ├── hooks/ # Event hooks
@@ -225,17 +242,16 @@ src/
225
242
  │ ├── streaming/ # Real-time streaming
226
243
  │ ├── prompts/ # System prompts
227
244
  │ └── tools/ # Tool definitions & executor
228
- ├── agents/
229
- │ └── index.ts # 9 built-in specialized agents
230
- ├── commands/
231
- │ └── index.ts # Built-in slash commands
232
- ├── wire/ # Agent-UI communication protocol
245
+ ├── agents/index.ts # 9 built-in specialized agents
246
+ ├── commands/index.ts # Built-in slash commands
247
+ ├── wire/ # Agent-UI communication
233
248
  ├── mcp/ # MCP client integration
234
- ├── utils/ # Retry logic, utilities
235
249
  └── config/ # Constants, theme
236
250
  ```
237
251
 
238
- ## Development
252
+ ---
253
+
254
+ ## 🛠️ Development
239
255
 
240
256
  ```bash
241
257
  # Clone
@@ -252,12 +268,24 @@ npm run build
252
268
  npm run dev
253
269
  ```
254
270
 
255
- ## Legal
271
+ ---
272
+
273
+ ## 📚 Documentation
256
274
 
257
- ⚠️ **Only use on systems you own or have explicit permission to test.**
275
+ - [Architecture](docs/architecture.md) - System design and components
276
+ - [API Reference](docs/api-reference.md) - Full API documentation
277
+ - [Troubleshooting](docs/troubleshooting.md) - Common issues
278
+
279
+ ---
280
+
281
+ ## ⚠️ Legal
282
+
283
+ **Only use on systems you own or have explicit permission to test.**
258
284
 
259
285
  This tool is for authorized penetration testing and CTF competitions only. Unauthorized access to computer systems is illegal.
260
286
 
261
- ## License
287
+ ---
288
+
289
+ ## 📄 License
262
290
 
263
291
  MIT
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@ import Spinner from "ink-spinner";
12
12
 
13
13
  // src/core/agent/autonomous-agent.ts
14
14
  import Anthropic from "@anthropic-ai/sdk";
15
- import { EventEmitter as EventEmitter3 } from "events";
15
+ import { EventEmitter as EventEmitter4 } from "events";
16
16
 
17
17
  // src/core/prompts/autonomous-prompt.ts
18
18
  var AUTONOMOUS_HACKING_PROMPT = `You are Hacker-Code, an elite autonomous penetration testing AI designed for CTF competitions and professional security assessments. You operate with minimal human intervention, making intelligent decisions, adapting to obstacles, and persistently pursuing objectives until complete system compromise.
@@ -251,6 +251,8 @@ var AGENT_EVENT = {
251
251
  TOOL_CALL: "tool_call",
252
252
  TOOL_RESULT: "tool_result",
253
253
  COMMAND_EXECUTE: "command_execute",
254
+ APPROVAL_NEEDED: "approval_needed",
255
+ TOKEN_USAGE: "token_usage",
254
256
  // State changes
255
257
  TARGET_SET: "target_set",
256
258
  PHASE_CHANGE: "phase_change",
@@ -1374,7 +1376,7 @@ const { chromium } = require('playwright');
1374
1376
  }
1375
1377
 
1376
1378
  // src/config/constants.ts
1377
- var APP_VERSION = "0.2.3";
1379
+ var APP_VERSION = "0.2.5";
1378
1380
  var APP_DESCRIPTION = "Autonomous Penetration Testing AI Agent";
1379
1381
  var LLM_API_KEY = process.env.PENTEST_API_KEY || process.env.ANTHROPIC_API_KEY || "";
1380
1382
  var LLM_BASE_URL = process.env.PENTEST_BASE_URL || void 0;
@@ -1732,6 +1734,183 @@ function getMCPManager() {
1732
1734
  return mcpManager;
1733
1735
  }
1734
1736
 
1737
+ // src/core/approval/approval-manager.ts
1738
+ import { EventEmitter as EventEmitter3 } from "events";
1739
+ var APPROVAL_EVENT = {
1740
+ REQUEST: "approval_request",
1741
+ RESPONSE: "approval_response",
1742
+ TIMEOUT: "approval_timeout"
1743
+ };
1744
+ var CRITICAL_TOOLS = [
1745
+ "execute_command",
1746
+ "write_file",
1747
+ "delete_file",
1748
+ "modify_file",
1749
+ "send_request",
1750
+ "exploit_execute"
1751
+ ];
1752
+ var HIGH_RISK_PATTERNS = [
1753
+ /rm\s+-rf/i,
1754
+ /mkfs/i,
1755
+ /dd\s+if=/i,
1756
+ /format/i,
1757
+ /shutdown/i,
1758
+ /reboot/i,
1759
+ /kill\s+-9/i,
1760
+ /pkill/i,
1761
+ /iptables/i,
1762
+ /ufw/i,
1763
+ /firewall/i,
1764
+ /passwd/i,
1765
+ /useradd/i,
1766
+ /userdel/i,
1767
+ /chmod\s+777/i,
1768
+ /chown/i,
1769
+ /sudo/i,
1770
+ /su\s+-/i,
1771
+ /nc\s+-e/i,
1772
+ /bash\s+-i/i,
1773
+ /reverse.*shell/i,
1774
+ /bind.*shell/i,
1775
+ /meterpreter/i,
1776
+ /mimikatz/i
1777
+ ];
1778
+ function assessRisk(toolName, toolInput) {
1779
+ const inputStr = JSON.stringify(toolInput).toLowerCase();
1780
+ for (const pattern of HIGH_RISK_PATTERNS) {
1781
+ if (pattern.test(inputStr)) {
1782
+ return "critical";
1783
+ }
1784
+ }
1785
+ if (CRITICAL_TOOLS.includes(toolName)) {
1786
+ return "high";
1787
+ }
1788
+ if (toolName.includes("script") || toolName.includes("exec")) {
1789
+ return "medium";
1790
+ }
1791
+ if (toolName.includes("scan") || toolName.includes("request")) {
1792
+ return "medium";
1793
+ }
1794
+ return "low";
1795
+ }
1796
+ function generateRequestId() {
1797
+ return `approval_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
1798
+ }
1799
+ var ApprovalManager = class extends EventEmitter3 {
1800
+ pendingRequests = /* @__PURE__ */ new Map();
1801
+ autoApprovedTools = /* @__PURE__ */ new Set();
1802
+ autoDeniedTools = /* @__PURE__ */ new Set();
1803
+ yoloMode = false;
1804
+ defaultTimeout = 6e4;
1805
+ // 1 minute
1806
+ constructor(options) {
1807
+ super();
1808
+ this.yoloMode = options?.yoloMode ?? false;
1809
+ this.defaultTimeout = options?.timeout ?? 6e4;
1810
+ }
1811
+ /**
1812
+ * Enable/disable YOLO mode (auto-approve everything)
1813
+ */
1814
+ setYoloMode(enabled) {
1815
+ this.yoloMode = enabled;
1816
+ this.emit("yolo_mode_changed", enabled);
1817
+ }
1818
+ /**
1819
+ * Check if approval is required for a tool call
1820
+ */
1821
+ requiresApproval(toolName, toolInput) {
1822
+ if (this.yoloMode) return false;
1823
+ if (this.autoApprovedTools.has(toolName)) return false;
1824
+ if (this.autoDeniedTools.has(toolName)) return true;
1825
+ const risk = assessRisk(toolName, toolInput);
1826
+ if (risk === "low") return false;
1827
+ return true;
1828
+ }
1829
+ /**
1830
+ * Request approval for a tool call
1831
+ */
1832
+ async requestApproval(toolName, toolInput, reason) {
1833
+ if (this.autoDeniedTools.has(toolName)) {
1834
+ return "deny";
1835
+ }
1836
+ if (this.autoApprovedTools.has(toolName)) {
1837
+ return "approve";
1838
+ }
1839
+ const risk = assessRisk(toolName, toolInput);
1840
+ const request = {
1841
+ id: generateRequestId(),
1842
+ toolName,
1843
+ toolInput,
1844
+ reason: reason || `Tool "${toolName}" requires approval (${risk} risk)`,
1845
+ riskLevel: risk,
1846
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1847
+ };
1848
+ this.pendingRequests.set(request.id, request);
1849
+ this.emit(APPROVAL_EVENT.REQUEST, request);
1850
+ return new Promise((resolve) => {
1851
+ const timeout = setTimeout(() => {
1852
+ this.pendingRequests.delete(request.id);
1853
+ this.emit(APPROVAL_EVENT.TIMEOUT, request.id);
1854
+ resolve("deny");
1855
+ }, this.defaultTimeout);
1856
+ const responseHandler = (response) => {
1857
+ if (response.requestId === request.id) {
1858
+ clearTimeout(timeout);
1859
+ this.pendingRequests.delete(request.id);
1860
+ this.removeListener(APPROVAL_EVENT.RESPONSE, responseHandler);
1861
+ if (response.decision === "approve_always") {
1862
+ this.autoApprovedTools.add(toolName);
1863
+ resolve("approve");
1864
+ } else if (response.decision === "deny_always") {
1865
+ this.autoDeniedTools.add(toolName);
1866
+ resolve("deny");
1867
+ } else {
1868
+ resolve(response.decision);
1869
+ }
1870
+ }
1871
+ };
1872
+ this.on(APPROVAL_EVENT.RESPONSE, responseHandler);
1873
+ });
1874
+ }
1875
+ /**
1876
+ * Respond to an approval request (called by UI)
1877
+ */
1878
+ respond(requestId, decision) {
1879
+ const response = {
1880
+ requestId,
1881
+ decision,
1882
+ respondedAt: (/* @__PURE__ */ new Date()).toISOString()
1883
+ };
1884
+ this.emit(APPROVAL_EVENT.RESPONSE, response);
1885
+ }
1886
+ /**
1887
+ * Get pending requests
1888
+ */
1889
+ getPendingRequests() {
1890
+ return Array.from(this.pendingRequests.values());
1891
+ }
1892
+ /**
1893
+ * Get auto-approved tools
1894
+ */
1895
+ getAutoApprovedTools() {
1896
+ return Array.from(this.autoApprovedTools);
1897
+ }
1898
+ /**
1899
+ * Reset all auto decisions
1900
+ */
1901
+ resetAutoDecisions() {
1902
+ this.autoApprovedTools.clear();
1903
+ this.autoDeniedTools.clear();
1904
+ }
1905
+ };
1906
+ var approvalManager = null;
1907
+ function getApprovalManager(options) {
1908
+ if (!approvalManager) {
1909
+ approvalManager = new ApprovalManager(options);
1910
+ }
1911
+ return approvalManager;
1912
+ }
1913
+
1735
1914
  // src/core/tools/web-search.ts
1736
1915
  import { spawn as spawn4 } from "child_process";
1737
1916
  async function searchDuckDuckGo(query, options = {}) {
@@ -2959,7 +3138,7 @@ var DEFAULT_PHASES = [
2959
3138
  { id: PHASE_ID.EXFIL, name: "Data Exfiltration", shortName: "Exfil", status: PHASE_STATUS.PENDING, attempts: 0 },
2960
3139
  { id: PHASE_ID.REPORT, name: "Reporting", shortName: "Report", status: PHASE_STATUS.PENDING, attempts: 0 }
2961
3140
  ];
2962
- var AutonomousHackingAgent = class extends EventEmitter3 {
3141
+ var AutonomousHackingAgent = class extends EventEmitter4 {
2963
3142
  client;
2964
3143
  state;
2965
3144
  config;
@@ -2970,6 +3149,13 @@ var AutonomousHackingAgent = class extends EventEmitter3 {
2970
3149
  hookExecutor;
2971
3150
  mcpManager;
2972
3151
  contextManager;
3152
+ approvalManager;
3153
+ // Token usage tracking
3154
+ tokenUsage = {
3155
+ input: 0,
3156
+ output: 0,
3157
+ total: 0
3158
+ };
2973
3159
  // Rabbit hole detection settings
2974
3160
  STUCK_THRESHOLD = 5;
2975
3161
  // Same action repeat count
@@ -2988,6 +3174,7 @@ var AutonomousHackingAgent = class extends EventEmitter3 {
2988
3174
  this.hookExecutor = getHookExecutor();
2989
3175
  this.mcpManager = getMCPManager();
2990
3176
  this.contextManager = new ContextManager(this.client);
3177
+ this.approvalManager = getApprovalManager({ yoloMode: config?.autoApprove });
2991
3178
  this.state = this.createInitialState();
2992
3179
  this.initSystems();
2993
3180
  }
@@ -3399,6 +3586,12 @@ Goal: Deep penetration to obtain root/system privileges, extract internal data,
3399
3586
  }
3400
3587
  }
3401
3588
  );
3589
+ if (response.usage) {
3590
+ this.tokenUsage.input += response.usage.input_tokens;
3591
+ this.tokenUsage.output += response.usage.output_tokens;
3592
+ this.tokenUsage.total = this.tokenUsage.input + this.tokenUsage.output;
3593
+ this.emit(AGENT_EVENT.TOKEN_USAGE, this.tokenUsage);
3594
+ }
3402
3595
  return this.processResponse(response);
3403
3596
  }
3404
3597
  buildContextPrompt() {
@@ -3457,6 +3650,29 @@ Use report_finding tool for important discoveries.
3457
3650
  this.think(THOUGHT_TYPE.STUCK, `Tool blocked by hook: ${hookCheck.output}`);
3458
3651
  continue;
3459
3652
  }
3653
+ if (this.approvalManager.requiresApproval(toolName, toolInput)) {
3654
+ const risk = assessRisk(toolName, toolInput);
3655
+ this.emit(AGENT_EVENT.APPROVAL_NEEDED, {
3656
+ id: block.id,
3657
+ toolName,
3658
+ toolInput,
3659
+ riskLevel: risk
3660
+ });
3661
+ const decision = await this.approvalManager.requestApproval(
3662
+ toolName,
3663
+ toolInput,
3664
+ `Executing ${toolName} (${risk} risk)`
3665
+ );
3666
+ if (decision === "deny") {
3667
+ this.think(THOUGHT_TYPE.STUCK, `Tool denied by user: ${toolName}`);
3668
+ this.emit(AGENT_EVENT.TOOL_RESULT, {
3669
+ id: block.id,
3670
+ name: toolName,
3671
+ result: { success: false, output: "Denied by user" }
3672
+ });
3673
+ continue;
3674
+ }
3675
+ }
3460
3676
  const result = await executeToolCall(toolName, toolInput);
3461
3677
  await this.hookExecutor.runPostToolUse(toolName, result.output || "");
3462
3678
  const resultType = result.success ? "result" : "result";
@@ -3833,14 +4049,14 @@ Respond helpfully to the user's message. If they ask to perform security testing
3833
4049
  // src/core/session/session-manager.ts
3834
4050
  import * as fs3 from "fs/promises";
3835
4051
  import * as path3 from "path";
3836
- import { EventEmitter as EventEmitter4 } from "events";
4052
+ import { EventEmitter as EventEmitter5 } from "events";
3837
4053
  var SESSIONS_DIR = ".pentesting/sessions";
3838
4054
  function generateSessionId() {
3839
4055
  const timestamp = Date.now().toString(36);
3840
4056
  const random = Math.random().toString(36).substring(2, 8);
3841
4057
  return `session_${timestamp}_${random}`;
3842
4058
  }
3843
- var SessionManager = class extends EventEmitter4 {
4059
+ var SessionManager = class extends EventEmitter5 {
3844
4060
  sessionsDir;
3845
4061
  currentSession = null;
3846
4062
  constructor(baseDir) {
@@ -4015,183 +4231,6 @@ function getSessionManager() {
4015
4231
  return sessionManager;
4016
4232
  }
4017
4233
 
4018
- // src/core/approval/approval-manager.ts
4019
- import { EventEmitter as EventEmitter5 } from "events";
4020
- var APPROVAL_EVENT = {
4021
- REQUEST: "approval_request",
4022
- RESPONSE: "approval_response",
4023
- TIMEOUT: "approval_timeout"
4024
- };
4025
- var CRITICAL_TOOLS = [
4026
- "execute_command",
4027
- "write_file",
4028
- "delete_file",
4029
- "modify_file",
4030
- "send_request",
4031
- "exploit_execute"
4032
- ];
4033
- var HIGH_RISK_PATTERNS = [
4034
- /rm\s+-rf/i,
4035
- /mkfs/i,
4036
- /dd\s+if=/i,
4037
- /format/i,
4038
- /shutdown/i,
4039
- /reboot/i,
4040
- /kill\s+-9/i,
4041
- /pkill/i,
4042
- /iptables/i,
4043
- /ufw/i,
4044
- /firewall/i,
4045
- /passwd/i,
4046
- /useradd/i,
4047
- /userdel/i,
4048
- /chmod\s+777/i,
4049
- /chown/i,
4050
- /sudo/i,
4051
- /su\s+-/i,
4052
- /nc\s+-e/i,
4053
- /bash\s+-i/i,
4054
- /reverse.*shell/i,
4055
- /bind.*shell/i,
4056
- /meterpreter/i,
4057
- /mimikatz/i
4058
- ];
4059
- function assessRisk(toolName, toolInput) {
4060
- const inputStr = JSON.stringify(toolInput).toLowerCase();
4061
- for (const pattern of HIGH_RISK_PATTERNS) {
4062
- if (pattern.test(inputStr)) {
4063
- return "critical";
4064
- }
4065
- }
4066
- if (CRITICAL_TOOLS.includes(toolName)) {
4067
- return "high";
4068
- }
4069
- if (toolName.includes("script") || toolName.includes("exec")) {
4070
- return "medium";
4071
- }
4072
- if (toolName.includes("scan") || toolName.includes("request")) {
4073
- return "medium";
4074
- }
4075
- return "low";
4076
- }
4077
- function generateRequestId() {
4078
- return `approval_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
4079
- }
4080
- var ApprovalManager = class extends EventEmitter5 {
4081
- pendingRequests = /* @__PURE__ */ new Map();
4082
- autoApprovedTools = /* @__PURE__ */ new Set();
4083
- autoDeniedTools = /* @__PURE__ */ new Set();
4084
- yoloMode = false;
4085
- defaultTimeout = 6e4;
4086
- // 1 minute
4087
- constructor(options) {
4088
- super();
4089
- this.yoloMode = options?.yoloMode ?? false;
4090
- this.defaultTimeout = options?.timeout ?? 6e4;
4091
- }
4092
- /**
4093
- * Enable/disable YOLO mode (auto-approve everything)
4094
- */
4095
- setYoloMode(enabled) {
4096
- this.yoloMode = enabled;
4097
- this.emit("yolo_mode_changed", enabled);
4098
- }
4099
- /**
4100
- * Check if approval is required for a tool call
4101
- */
4102
- requiresApproval(toolName, toolInput) {
4103
- if (this.yoloMode) return false;
4104
- if (this.autoApprovedTools.has(toolName)) return false;
4105
- if (this.autoDeniedTools.has(toolName)) return true;
4106
- const risk = assessRisk(toolName, toolInput);
4107
- if (risk === "low") return false;
4108
- return true;
4109
- }
4110
- /**
4111
- * Request approval for a tool call
4112
- */
4113
- async requestApproval(toolName, toolInput, reason) {
4114
- if (this.autoDeniedTools.has(toolName)) {
4115
- return "deny";
4116
- }
4117
- if (this.autoApprovedTools.has(toolName)) {
4118
- return "approve";
4119
- }
4120
- const risk = assessRisk(toolName, toolInput);
4121
- const request = {
4122
- id: generateRequestId(),
4123
- toolName,
4124
- toolInput,
4125
- reason: reason || `Tool "${toolName}" requires approval (${risk} risk)`,
4126
- riskLevel: risk,
4127
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
4128
- };
4129
- this.pendingRequests.set(request.id, request);
4130
- this.emit(APPROVAL_EVENT.REQUEST, request);
4131
- return new Promise((resolve) => {
4132
- const timeout = setTimeout(() => {
4133
- this.pendingRequests.delete(request.id);
4134
- this.emit(APPROVAL_EVENT.TIMEOUT, request.id);
4135
- resolve("deny");
4136
- }, this.defaultTimeout);
4137
- const responseHandler = (response) => {
4138
- if (response.requestId === request.id) {
4139
- clearTimeout(timeout);
4140
- this.pendingRequests.delete(request.id);
4141
- this.removeListener(APPROVAL_EVENT.RESPONSE, responseHandler);
4142
- if (response.decision === "approve_always") {
4143
- this.autoApprovedTools.add(toolName);
4144
- resolve("approve");
4145
- } else if (response.decision === "deny_always") {
4146
- this.autoDeniedTools.add(toolName);
4147
- resolve("deny");
4148
- } else {
4149
- resolve(response.decision);
4150
- }
4151
- }
4152
- };
4153
- this.on(APPROVAL_EVENT.RESPONSE, responseHandler);
4154
- });
4155
- }
4156
- /**
4157
- * Respond to an approval request (called by UI)
4158
- */
4159
- respond(requestId, decision) {
4160
- const response = {
4161
- requestId,
4162
- decision,
4163
- respondedAt: (/* @__PURE__ */ new Date()).toISOString()
4164
- };
4165
- this.emit(APPROVAL_EVENT.RESPONSE, response);
4166
- }
4167
- /**
4168
- * Get pending requests
4169
- */
4170
- getPendingRequests() {
4171
- return Array.from(this.pendingRequests.values());
4172
- }
4173
- /**
4174
- * Get auto-approved tools
4175
- */
4176
- getAutoApprovedTools() {
4177
- return Array.from(this.autoApprovedTools);
4178
- }
4179
- /**
4180
- * Reset all auto decisions
4181
- */
4182
- resetAutoDecisions() {
4183
- this.autoApprovedTools.clear();
4184
- this.autoDeniedTools.clear();
4185
- }
4186
- };
4187
- var approvalManager = null;
4188
- function getApprovalManager(options) {
4189
- if (!approvalManager) {
4190
- approvalManager = new ApprovalManager(options);
4191
- }
4192
- return approvalManager;
4193
- }
4194
-
4195
4234
  // src/config/theme.ts
4196
4235
  var THEME = {
4197
4236
  // Primary backgrounds (dark purple tones)
@@ -4287,6 +4326,7 @@ var App = ({ autoApprove = false, target }) => {
4287
4326
  const [currentStatus, setCurrentStatus] = useState("");
4288
4327
  const [elapsedTime, setElapsedTime] = useState(0);
4289
4328
  const [pendingApproval, setPendingApproval] = useState(null);
4329
+ const [tokenUsage, setTokenUsage] = useState({ input: 0, output: 0, total: 0 });
4290
4330
  const [agent] = useState(() => new AutonomousHackingAgent(void 0, { autoApprove }));
4291
4331
  const sessionManager2 = getSessionManager();
4292
4332
  const approvalManager2 = getApprovalManager({ yoloMode: autoApprove });
@@ -4350,6 +4390,18 @@ var App = ({ autoApprove = false, target }) => {
4350
4390
  agent.on(AGENT_EVENT.CONTEXT_COMPACTED, () => {
4351
4391
  addMessage(MESSAGE_TYPE.SYSTEM, "\u{1F4BE} Context compacted to save tokens");
4352
4392
  });
4393
+ agent.on(AGENT_EVENT.TOKEN_USAGE, (usage) => {
4394
+ setTokenUsage(usage);
4395
+ });
4396
+ agent.on(AGENT_EVENT.APPROVAL_NEEDED, (data) => {
4397
+ setPendingApproval({
4398
+ id: data.id,
4399
+ toolName: data.toolName,
4400
+ riskLevel: data.riskLevel
4401
+ });
4402
+ addMessage(MESSAGE_TYPE.SYSTEM, `\u26A0\uFE0F APPROVAL NEEDED: ${data.toolName} (${data.riskLevel} risk)`);
4403
+ addMessage(MESSAGE_TYPE.SYSTEM, " Type /approve or /deny");
4404
+ });
4353
4405
  agent.on(AGENT_EVENT.COMPLETE, () => {
4354
4406
  const duration = stopTimer();
4355
4407
  addMessage(MESSAGE_TYPE.SYSTEM, `\u2713 Complete (${duration}s)`);
@@ -4622,6 +4674,7 @@ var App = ({ autoApprove = false, target }) => {
4622
4674
  " findings \u2502",
4623
4675
  state.credentials.length,
4624
4676
  " creds \u2502",
4677
+ tokenUsage.total > 0 && `${(tokenUsage.total / 1e3).toFixed(1)}k tokens \u2502`,
4625
4678
  state.currentPhase !== AGENT_STATUS.IDLE && ` ${state.currentPhase} \u2502`
4626
4679
  ] }),
4627
4680
  /* @__PURE__ */ jsxs(Text, { dimColor: true, children: [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pentesting",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "Autonomous Penetration Testing AI Agent",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",