pentesting 0.2.2 → 0.2.4
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 +144 -121
- package/dist/index.js +14 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,130 +1,120 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
```
|
|
2
|
+
╔═══════════════════════════════════════════════════════════════╗
|
|
3
|
+
║ ║
|
|
4
|
+
║ ██████╗ ███████╗███╗ ██╗████████╗███████╗███████╗████████╗║
|
|
5
|
+
║ ██╔══██╗██╔════╝████╗ ██║╚══██╔══╝██╔════╝██╔════╝╚══██╔══╝║
|
|
6
|
+
║ ██████╔╝█████╗ ██╔██╗ ██║ ██║ █████╗ ███████╗ ██║ ║
|
|
7
|
+
║ ██╔═══╝ ██╔══╝ ██║╚██╗██║ ██║ ██╔══╝ ╚════██║ ██║ ║
|
|
8
|
+
║ ██║ ███████╗██║ ╚████║ ██║ ███████╗███████║ ██║ ║
|
|
9
|
+
║ ╚═╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ╚══════╝╚══════╝ ╚═╝ ║
|
|
10
|
+
║ ║
|
|
11
|
+
║ 🎯 DEF CON-level Autonomous Pentesting Agent ║
|
|
12
|
+
║ ║
|
|
13
|
+
╚═══════════════════════════════════════════════════════════════╝
|
|
14
|
+
```
|
|
8
15
|
|
|
9
16
|
[](https://www.npmjs.com/package/pentesting)
|
|
10
17
|
[](https://hub.docker.com/r/agnusdei1207/pentesting-tools)
|
|
11
18
|
|
|
12
|
-
|
|
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
|
-
|
|
21
|
+
## 🚀 Quick Start
|
|
26
22
|
|
|
27
23
|
```bash
|
|
24
|
+
# Install
|
|
28
25
|
npm install -g pentesting
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
### Configure
|
|
32
26
|
|
|
33
|
-
|
|
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
|
-
|
|
31
|
+
|
|
32
|
+
# Run
|
|
33
|
+
pentesting
|
|
43
34
|
```
|
|
44
35
|
|
|
45
|
-
|
|
36
|
+
---
|
|
46
37
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
38
|
+
## ✨ Features
|
|
39
|
+
|
|
40
|
+
- **10-Phase Attack Workflow**: Recon → Scan → Enum → Vuln Analysis → Exploitation → PrivEsc → Pivot → Persist → Exfil → Report
|
|
41
|
+
- **9 Specialized Agents**: Built-in experts for each security domain
|
|
42
|
+
- **Ralph Loop**: Autonomous iteration until objective is achieved
|
|
43
|
+
- **Streaming Responses**: Real-time LLM output
|
|
44
|
+
- **Session Persistence**: Save/resume pentesting sessions
|
|
45
|
+
- **Tool Approval**: Manual confirmation for dangerous commands
|
|
46
|
+
- **MCP Integration**: Extend with Model Context Protocol tools
|
|
47
|
+
- **Docker Toolkit**: 50+ pre-installed pentesting tools
|
|
48
|
+
- **Provider Agnostic**: Works with any OpenAI-compatible API
|
|
49
|
+
|
|
50
|
+
---
|
|
51
51
|
|
|
52
|
-
## CLI Commands
|
|
52
|
+
## 📖 CLI Commands
|
|
53
53
|
|
|
54
54
|
```bash
|
|
55
|
+
# Target & Session
|
|
55
56
|
/target <ip> Set target
|
|
56
57
|
/start [objective] Start autonomous pentest
|
|
58
|
+
/sessions List saved sessions
|
|
59
|
+
/resume [id] Resume a session
|
|
60
|
+
|
|
61
|
+
# Scanning & Enumeration
|
|
57
62
|
/scan <target> Quick enumeration
|
|
63
|
+
/web <url> Web application testing
|
|
64
|
+
|
|
65
|
+
# Exploitation
|
|
58
66
|
/exploit <service> Search for exploits
|
|
59
67
|
/privesc [os] Check privilege escalation vectors
|
|
60
|
-
/web <url> Web application testing
|
|
61
|
-
/hash <hash> Identify and crack hashes
|
|
62
68
|
/attack <objective> Execute attack chain
|
|
69
|
+
/hash <hash> Identify and crack hashes
|
|
70
|
+
|
|
71
|
+
# Reporting
|
|
63
72
|
/report Generate pentest report
|
|
64
|
-
/
|
|
65
|
-
|
|
73
|
+
/findings Show findings
|
|
74
|
+
|
|
75
|
+
# Control
|
|
66
76
|
/yolo Toggle auto-approve mode
|
|
67
77
|
/approve /deny Approve/deny tool execution
|
|
68
|
-
/findings Show findings
|
|
69
78
|
/clear Clear screen
|
|
70
79
|
/exit Exit
|
|
71
80
|
```
|
|
72
81
|
|
|
73
|
-
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 🤖 Built-in Agents
|
|
74
85
|
|
|
75
86
|
| Agent | Specialty |
|
|
76
87
|
|-------|-----------|
|
|
77
|
-
|
|
|
78
|
-
|
|
|
79
|
-
|
|
|
80
|
-
|
|
|
81
|
-
|
|
|
82
|
-
|
|
|
83
|
-
|
|
|
84
|
-
|
|
|
85
|
-
|
|
|
86
|
-
|
|
87
|
-
## Architecture
|
|
88
|
+
| `target-explorer` | Network reconnaissance, service enumeration |
|
|
89
|
+
| `exploit-researcher` | CVE research, exploit development |
|
|
90
|
+
| `privesc-master` | Linux/Windows privilege escalation |
|
|
91
|
+
| `web-hacker` | OWASP Top 10, SQLi, XSS, SSRF |
|
|
92
|
+
| `crypto-solver` | Hash cracking, cipher analysis |
|
|
93
|
+
| `forensics-analyst` | Memory forensics, file carving |
|
|
94
|
+
| `reverse-engineer` | Binary analysis, exploit development |
|
|
95
|
+
| `attack-architect` | Attack strategy planning |
|
|
96
|
+
| `finding-reviewer` | Vulnerability validation |
|
|
88
97
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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
|
-
```
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## ⚙️ Configuration
|
|
101
|
+
|
|
102
|
+
### Environment Variables
|
|
103
|
+
|
|
104
|
+
| Variable | Description | Default |
|
|
105
|
+
|----------|-------------|---------|
|
|
106
|
+
| `PENTEST_API_KEY` | LLM API key | Required |
|
|
107
|
+
| `PENTEST_BASE_URL` | API endpoint URL | - |
|
|
108
|
+
| `PENTEST_MODEL` | Model name | claude-sonnet-4-20250514 |
|
|
109
|
+
| `PENTEST_MAX_TOKENS` | Max response tokens | 16384 |
|
|
110
|
+
| `PENTESTING_DOCKER` | Force Docker execution | 0 |
|
|
111
|
+
| `PENTESTING_CONTAINER` | Docker container name | pentesting-tools |
|
|
126
112
|
|
|
127
|
-
|
|
113
|
+
> **Note**: `ANTHROPIC_API_KEY` is also accepted as fallback for `PENTEST_API_KEY`.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## 💻 Programmatic Usage
|
|
128
118
|
|
|
129
119
|
```typescript
|
|
130
120
|
import { PentestingAgent, PENTEST_EVENT } from 'pentesting';
|
|
@@ -158,7 +148,9 @@ const scanResult = await agent.chat('/scan 10.10.10.1');
|
|
|
158
148
|
const exploitResult = await agent.chat('/exploit Apache 2.4.49');
|
|
159
149
|
```
|
|
160
150
|
|
|
161
|
-
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## 🐳 Docker Environment
|
|
162
154
|
|
|
163
155
|
```bash
|
|
164
156
|
# Pull pre-built toolkit (50+ tools)
|
|
@@ -173,7 +165,9 @@ docker run -d --name pentesting-tools --network host \
|
|
|
173
165
|
docker exec -it pentesting-tools nmap -sCV 10.0.0.1
|
|
174
166
|
```
|
|
175
167
|
|
|
176
|
-
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## 🔌 MCP Integration
|
|
177
171
|
|
|
178
172
|
Extend with additional MCP servers:
|
|
179
173
|
|
|
@@ -191,32 +185,50 @@ await agent.addMCPServer('security-tools', 'docker', [
|
|
|
191
185
|
]);
|
|
192
186
|
```
|
|
193
187
|
|
|
194
|
-
|
|
188
|
+
---
|
|
195
189
|
|
|
196
|
-
|
|
190
|
+
## 🏗️ Architecture
|
|
197
191
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
192
|
+
```
|
|
193
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
194
|
+
│ TUI (app.tsx) │
|
|
195
|
+
│ - Streaming text display │
|
|
196
|
+
│ - Tool approval prompts │
|
|
197
|
+
│ - Session management │
|
|
198
|
+
└──────────────────────────┬──────────────────────────────────┘
|
|
199
|
+
│ Wire Protocol
|
|
200
|
+
┌──────────────────────────▼──────────────────────────────────┐
|
|
201
|
+
│ PentestingAgent (Unified) │
|
|
202
|
+
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
|
|
203
|
+
│ │ RalphLoop │ │ Streaming │ │ Session │ │
|
|
204
|
+
│ │ (Auto-iter) │ │ Handler │ │ Manager │ │
|
|
205
|
+
│ └──────────────┘ └──────────────┘ └──────────────┘ │
|
|
206
|
+
│ │
|
|
207
|
+
│ ┌──────────────────────────────────────────────────┐ │
|
|
208
|
+
│ │ AutonomousHackingAgent (Core) │ │
|
|
209
|
+
│ │ ┌──────────────────────────────────────────┐ │ │
|
|
210
|
+
│ │ │ 9 Built-in Specialized Agents │ │ │
|
|
211
|
+
│ │ └──────────────────────────────────────────┘ │ │
|
|
212
|
+
│ └──────────────────────────────────────────────────┘ │
|
|
213
|
+
└──────────────────────────┬──────────────────────────────────┘
|
|
214
|
+
│
|
|
215
|
+
┌────────────────┼────────────────┐
|
|
216
|
+
┌────▼────┐ ┌────▼────┐ ┌────▼────┐
|
|
217
|
+
│ Tool │ │ Bash │ │ MCP │
|
|
218
|
+
│Executor │ │ Commands│ │ Servers │
|
|
219
|
+
└─────────┘ └─────────┘ └─────────┘
|
|
220
|
+
```
|
|
206
221
|
|
|
207
|
-
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## 📁 Project Structure
|
|
208
225
|
|
|
209
226
|
```
|
|
210
227
|
src/
|
|
211
228
|
├── index.tsx # CLI entry point
|
|
212
|
-
├── cli/
|
|
213
|
-
│ └── app.tsx # TUI with streaming, approval, sessions
|
|
229
|
+
├── cli/app.tsx # TUI with streaming, approval, sessions
|
|
214
230
|
├── core/
|
|
215
|
-
│ ├──
|
|
216
|
-
│ ├── agent/
|
|
217
|
-
│ │ ├── pentesting-agent.ts # Unified agent
|
|
218
|
-
│ │ ├── autonomous-agent.ts # Core agent logic
|
|
219
|
-
│ │ └── agent-orchestrator.ts # Parallel agent execution
|
|
231
|
+
│ ├── agent/ # Agent implementations
|
|
220
232
|
│ ├── approval/ # Tool approval system
|
|
221
233
|
│ ├── context/ # Conversation compaction
|
|
222
234
|
│ ├── hooks/ # Event hooks
|
|
@@ -225,17 +237,16 @@ src/
|
|
|
225
237
|
│ ├── streaming/ # Real-time streaming
|
|
226
238
|
│ ├── prompts/ # System prompts
|
|
227
239
|
│ └── tools/ # Tool definitions & executor
|
|
228
|
-
├── agents/
|
|
229
|
-
|
|
230
|
-
├──
|
|
231
|
-
│ └── index.ts # Built-in slash commands
|
|
232
|
-
├── wire/ # Agent-UI communication protocol
|
|
240
|
+
├── agents/index.ts # 9 built-in specialized agents
|
|
241
|
+
├── commands/index.ts # Built-in slash commands
|
|
242
|
+
├── wire/ # Agent-UI communication
|
|
233
243
|
├── mcp/ # MCP client integration
|
|
234
|
-
├── utils/ # Retry logic, utilities
|
|
235
244
|
└── config/ # Constants, theme
|
|
236
245
|
```
|
|
237
246
|
|
|
238
|
-
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## 🛠️ Development
|
|
239
250
|
|
|
240
251
|
```bash
|
|
241
252
|
# Clone
|
|
@@ -252,12 +263,24 @@ npm run build
|
|
|
252
263
|
npm run dev
|
|
253
264
|
```
|
|
254
265
|
|
|
255
|
-
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
## 📚 Documentation
|
|
269
|
+
|
|
270
|
+
- [Architecture](docs/architecture.md) - System design and components
|
|
271
|
+
- [API Reference](docs/api-reference.md) - Full API documentation
|
|
272
|
+
- [Troubleshooting](docs/troubleshooting.md) - Common issues
|
|
256
273
|
|
|
257
|
-
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
## ⚠️ Legal
|
|
277
|
+
|
|
278
|
+
**Only use on systems you own or have explicit permission to test.**
|
|
258
279
|
|
|
259
280
|
This tool is for authorized penetration testing and CTF competitions only. Unauthorized access to computer systems is illegal.
|
|
260
281
|
|
|
261
|
-
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## 📄 License
|
|
262
285
|
|
|
263
286
|
MIT
|
package/dist/index.js
CHANGED
|
@@ -1374,15 +1374,12 @@ const { chromium } = require('playwright');
|
|
|
1374
1374
|
}
|
|
1375
1375
|
|
|
1376
1376
|
// src/config/constants.ts
|
|
1377
|
-
var APP_VERSION = "0.2.
|
|
1377
|
+
var APP_VERSION = "0.2.4";
|
|
1378
1378
|
var APP_DESCRIPTION = "Autonomous Penetration Testing AI Agent";
|
|
1379
1379
|
var LLM_API_KEY = process.env.PENTEST_API_KEY || process.env.ANTHROPIC_API_KEY || "";
|
|
1380
|
-
var LLM_BASE_URL = process.env.PENTEST_BASE_URL ||
|
|
1380
|
+
var LLM_BASE_URL = process.env.PENTEST_BASE_URL || void 0;
|
|
1381
1381
|
var LLM_MODEL = process.env.PENTEST_MODEL || "claude-sonnet-4-20250514";
|
|
1382
1382
|
var LLM_MAX_TOKENS = parseInt(process.env.PENTEST_MAX_TOKENS || "16384", 10);
|
|
1383
|
-
var CLAUDE_MODEL = LLM_MODEL;
|
|
1384
|
-
var CLAUDE_MAX_TOKENS = LLM_MAX_TOKENS;
|
|
1385
|
-
var ANTHROPIC_BASE_URL = LLM_BASE_URL;
|
|
1386
1383
|
var AGENT_CONFIG = {
|
|
1387
1384
|
maxIterations: 200,
|
|
1388
1385
|
maxToolCallsPerIteration: 10,
|
|
@@ -1889,8 +1886,8 @@ async function compactHistory(client, messages, keepRecent = 4) {
|
|
|
1889
1886
|
return `[${msg.role.toUpperCase()}]: ${content}`;
|
|
1890
1887
|
}).join("\n\n");
|
|
1891
1888
|
const response = await client.messages.create({
|
|
1892
|
-
model:
|
|
1893
|
-
max_tokens:
|
|
1889
|
+
model: LLM_MODEL,
|
|
1890
|
+
max_tokens: LLM_MAX_TOKENS,
|
|
1894
1891
|
system: COMPACTION_PROMPT,
|
|
1895
1892
|
messages: [{
|
|
1896
1893
|
role: "user",
|
|
@@ -2983,8 +2980,8 @@ var AutonomousHackingAgent = class extends EventEmitter3 {
|
|
|
2983
2980
|
constructor(apiKey, config) {
|
|
2984
2981
|
super();
|
|
2985
2982
|
this.client = new Anthropic({
|
|
2986
|
-
apiKey: apiKey || LLM_API_KEY || process.env.
|
|
2987
|
-
baseURL:
|
|
2983
|
+
apiKey: apiKey || LLM_API_KEY || process.env.PENTEST_API_KEY,
|
|
2984
|
+
baseURL: LLM_BASE_URL
|
|
2988
2985
|
});
|
|
2989
2986
|
this.config = { ...AGENT_CONFIG, ...config };
|
|
2990
2987
|
this.tools = ALL_TOOLS;
|
|
@@ -3238,7 +3235,7 @@ Current situation:
|
|
|
3238
3235
|
What went wrong and what different approach should be tried?
|
|
3239
3236
|
`;
|
|
3240
3237
|
const response = await this.client.messages.create({
|
|
3241
|
-
model:
|
|
3238
|
+
model: LLM_MODEL,
|
|
3242
3239
|
max_tokens: 4096,
|
|
3243
3240
|
messages: [{ role: "user", content: reflectionPrompt }]
|
|
3244
3241
|
});
|
|
@@ -3386,8 +3383,8 @@ Goal: Deep penetration to obtain root/system privileges, extract internal data,
|
|
|
3386
3383
|
}
|
|
3387
3384
|
const response = await withRetry(
|
|
3388
3385
|
() => this.client.messages.create({
|
|
3389
|
-
model:
|
|
3390
|
-
max_tokens:
|
|
3386
|
+
model: LLM_MODEL,
|
|
3387
|
+
max_tokens: LLM_MAX_TOKENS,
|
|
3391
3388
|
system: systemPrompt,
|
|
3392
3389
|
tools: this.tools,
|
|
3393
3390
|
messages
|
|
@@ -3674,8 +3671,8 @@ ${this.state.findings.filter((f) => f.severity !== "info").map((f) => `- Address
|
|
|
3674
3671
|
try {
|
|
3675
3672
|
const systemPrompt = this.buildContextualPrompt();
|
|
3676
3673
|
const response = await this.client.messages.create({
|
|
3677
|
-
model:
|
|
3678
|
-
max_tokens:
|
|
3674
|
+
model: LLM_MODEL,
|
|
3675
|
+
max_tokens: LLM_MAX_TOKENS,
|
|
3679
3676
|
system: systemPrompt,
|
|
3680
3677
|
messages: this.state.history,
|
|
3681
3678
|
tools: this.tools
|
|
@@ -3707,8 +3704,8 @@ ${this.state.findings.filter((f) => f.severity !== "info").map((f) => `- Address
|
|
|
3707
3704
|
}
|
|
3708
3705
|
if (hasToolCalls && response.stop_reason === "tool_use") {
|
|
3709
3706
|
const followUp = await this.client.messages.create({
|
|
3710
|
-
model:
|
|
3711
|
-
max_tokens:
|
|
3707
|
+
model: LLM_MODEL,
|
|
3708
|
+
max_tokens: LLM_MAX_TOKENS,
|
|
3712
3709
|
system: systemPrompt,
|
|
3713
3710
|
messages: this.state.history,
|
|
3714
3711
|
tools: this.tools
|
|
@@ -4765,7 +4762,7 @@ ${chalk.hex(THEME.status.warning)("Examples:")}
|
|
|
4765
4762
|
|
|
4766
4763
|
${chalk.hex(THEME.status.warning)("Environment:")}
|
|
4767
4764
|
|
|
4768
|
-
${chalk.hex(THEME.text.accent)("
|
|
4765
|
+
${chalk.hex(THEME.text.accent)("PENTEST_API_KEY")} Required - LLM API key
|
|
4769
4766
|
${chalk.hex(THEME.text.accent)("PENTEST_MODEL")} Optional - Model override
|
|
4770
4767
|
|
|
4771
4768
|
${chalk.hex(THEME.text.muted)("For ethical hacking and authorized testing only.")}
|