hopeid 0.1.0 → 1.1.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/README.md +137 -3
- package/cli/hopeid.js +284 -11
- package/extensions/openclaw-plugin/SKILL.md +267 -0
- package/extensions/openclaw-plugin/index.ts +601 -0
- package/extensions/openclaw-plugin/openclaw.plugin.json +92 -0
- package/extensions/openclaw-plugin/package.json +17 -0
- package/package.json +7 -1
- package/src/index.js +27 -1
- package/src/layers/heuristic.js +59 -1
- package/src/layers/semantic.js +259 -8
- package/src/middleware/express.js +11 -3
- package/src/middleware/hono.js +11 -3
- package/src/patterns/impersonation.json +10 -0
- package/src/patterns/override.json +45 -0
- package/src/quarantine/index.ts +9 -0
- package/src/quarantine/manager.ts +179 -0
- package/src/quarantine/types.ts +52 -0
- package/types/index.d.ts +5 -1
package/README.md
CHANGED
|
@@ -17,11 +17,41 @@ hopeIDS protects AI agents from prompt injection attacks, credential theft, data
|
|
|
17
17
|
|
|
18
18
|
## Installation
|
|
19
19
|
|
|
20
|
+
### Full OpenClaw Setup (Recommended)
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx hopeid setup
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
This single command:
|
|
27
|
+
1. ✅ Installs the hopeIDS OpenClaw plugin
|
|
28
|
+
2. ✅ Installs the hopeids skill via ClawHub
|
|
29
|
+
3. ✅ Configures `security_scan` tool for your agent
|
|
30
|
+
4. ✅ Adds `/scan` command for manual checks
|
|
31
|
+
|
|
32
|
+
After setup, restart OpenClaw: `openclaw gateway restart`
|
|
33
|
+
|
|
34
|
+
📖 **[How to Set Up a Sandboxed AI Agent](https://exohaven.online/blog/sandboxed-agents-security-guide)** — Full guide on workspace isolation, IDS-first workflows, and protecting agents from prompt injection.
|
|
35
|
+
|
|
36
|
+
### Manual Installation
|
|
37
|
+
|
|
38
|
+
**Skill only (agent guidance):**
|
|
39
|
+
```bash
|
|
40
|
+
clawhub install hopeids
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
**npm package (for custom integrations):**
|
|
20
44
|
```bash
|
|
21
45
|
npm install hopeid
|
|
22
46
|
```
|
|
23
47
|
|
|
24
|
-
|
|
48
|
+
### Via npm (Node.js Apps)
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm install hopeid
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### CLI (Quick Test)
|
|
25
55
|
|
|
26
56
|
```bash
|
|
27
57
|
npx hopeid scan "your message here"
|
|
@@ -44,6 +74,102 @@ console.log(result2.action); // 'block'
|
|
|
44
74
|
console.log(result2.message); // "Nope. 'Ignore previous instructions' doesn't work on me..."
|
|
45
75
|
```
|
|
46
76
|
|
|
77
|
+
## Local LLM Support
|
|
78
|
+
|
|
79
|
+
**hopeIDS works out-of-the-box with local LLMs!** No OpenAI API key required.
|
|
80
|
+
|
|
81
|
+
### Supported Providers
|
|
82
|
+
|
|
83
|
+
- **Ollama** (recommended) — `http://localhost:11434`
|
|
84
|
+
- **LM Studio** — `http://localhost:1234`
|
|
85
|
+
- **OpenAI** — Cloud-based (requires API key)
|
|
86
|
+
- **Auto-detect** — Automatically finds running local LLM
|
|
87
|
+
|
|
88
|
+
### Quick Setup
|
|
89
|
+
|
|
90
|
+
**1. Install Ollama:**
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
# macOS/Linux
|
|
94
|
+
curl -fsSL https://ollama.ai/install.sh | sh
|
|
95
|
+
|
|
96
|
+
# Pull a recommended model
|
|
97
|
+
ollama pull qwen2.5:7b
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**2. Use hopeIDS:**
|
|
101
|
+
|
|
102
|
+
```javascript
|
|
103
|
+
const { HopeIDS } = require('hopeid');
|
|
104
|
+
|
|
105
|
+
// Auto-detect (finds Ollama/LM Studio automatically)
|
|
106
|
+
const ids = new HopeIDS({
|
|
107
|
+
semanticEnabled: true,
|
|
108
|
+
llmProvider: 'auto' // default
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Explicitly use Ollama
|
|
112
|
+
const ids = new HopeIDS({
|
|
113
|
+
semanticEnabled: true,
|
|
114
|
+
llmProvider: 'ollama',
|
|
115
|
+
llmModel: 'qwen2.5:7b'
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
// Explicitly use LM Studio
|
|
119
|
+
const ids = new HopeIDS({
|
|
120
|
+
semanticEnabled: true,
|
|
121
|
+
llmProvider: 'lmstudio',
|
|
122
|
+
llmModel: 'qwen2.5-32b'
|
|
123
|
+
});
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Recommended Models
|
|
127
|
+
|
|
128
|
+
For **best accuracy**, use these models:
|
|
129
|
+
|
|
130
|
+
| Model | Size | Provider | Accuracy | Speed |
|
|
131
|
+
|-------|------|----------|----------|-------|
|
|
132
|
+
| `qwen2.5:32b` | 20GB | Ollama, LM Studio | ⭐⭐⭐⭐⭐ | ⚡⚡ |
|
|
133
|
+
| `qwen2.5:14b` | 9GB | Ollama, LM Studio | ⭐⭐⭐⭐ | ⚡⚡⚡ |
|
|
134
|
+
| `qwen2.5:7b` | 4.7GB | Ollama, LM Studio | ⭐⭐⭐ | ⚡⚡⚡⚡ |
|
|
135
|
+
| `mistral:7b` | 4.1GB | Ollama, LM Studio | ⭐⭐⭐ | ⚡⚡⚡⚡ |
|
|
136
|
+
| `llama3:8b` | 4.7GB | Ollama, LM Studio | ⭐⭐⭐ | ⚡⚡⚡ |
|
|
137
|
+
| `gpt-4o-mini` | Cloud | OpenAI | ⭐⭐⭐⭐⭐ | ⚡⚡⚡⚡ |
|
|
138
|
+
| `gpt-3.5-turbo` | Cloud | OpenAI | ⭐⭐⭐⭐ | ⚡⚡⚡⚡⚡ |
|
|
139
|
+
|
|
140
|
+
**For production:** Use `qwen2.5:14b` or larger for best threat detection.
|
|
141
|
+
**For development:** Use `qwen2.5:7b` or `mistral:7b` for fast iteration.
|
|
142
|
+
**For edge devices:** Use `qwen2.5:3b` (not recommended for production).
|
|
143
|
+
|
|
144
|
+
### Environment Variables
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
# Auto-detect (default)
|
|
148
|
+
export LLM_PROVIDER=auto
|
|
149
|
+
|
|
150
|
+
# Force Ollama
|
|
151
|
+
export LLM_PROVIDER=ollama
|
|
152
|
+
export LLM_MODEL=qwen2.5:7b
|
|
153
|
+
|
|
154
|
+
# Force LM Studio
|
|
155
|
+
export LLM_PROVIDER=lmstudio
|
|
156
|
+
export LLM_ENDPOINT=http://localhost:1234/v1/chat/completions
|
|
157
|
+
export LLM_MODEL=qwen2.5-14b
|
|
158
|
+
|
|
159
|
+
# Use OpenAI
|
|
160
|
+
export LLM_PROVIDER=openai
|
|
161
|
+
export OPENAI_API_KEY=sk-...
|
|
162
|
+
export LLM_MODEL=gpt-4o-mini
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Why Local LLMs?
|
|
166
|
+
|
|
167
|
+
- ✅ **Privacy**: Your data never leaves your machine
|
|
168
|
+
- ✅ **Cost**: No per-token charges
|
|
169
|
+
- ✅ **Speed**: Low-latency inference
|
|
170
|
+
- ✅ **Offline**: Works without internet
|
|
171
|
+
- ✅ **Control**: Fine-tune for your use case
|
|
172
|
+
|
|
47
173
|
## CLI Usage
|
|
48
174
|
|
|
49
175
|
```bash
|
|
@@ -296,8 +422,16 @@ The middleware automatically:
|
|
|
296
422
|
const ids = new HopeIDS({
|
|
297
423
|
// Enable LLM-based semantic analysis
|
|
298
424
|
semanticEnabled: true,
|
|
299
|
-
|
|
300
|
-
|
|
425
|
+
|
|
426
|
+
// LLM Provider (auto-detects by default)
|
|
427
|
+
llmProvider: 'auto', // 'openai' | 'ollama' | 'lmstudio' | 'auto'
|
|
428
|
+
llmModel: 'qwen2.5:7b', // Auto-selected if using Ollama
|
|
429
|
+
|
|
430
|
+
// Or manually specify endpoint
|
|
431
|
+
llmEndpoint: 'http://localhost:11434/v1/chat/completions',
|
|
432
|
+
|
|
433
|
+
// Only needed for OpenAI
|
|
434
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
301
435
|
|
|
302
436
|
// Risk thresholds
|
|
303
437
|
thresholds: {
|
package/cli/hopeid.js
CHANGED
|
@@ -18,21 +18,25 @@ const { HopeIDS, formatAlert, formatNotification } = require('../src');
|
|
|
18
18
|
const HELP = `
|
|
19
19
|
hopeIDS - Inference-Based Intrusion Detection for AI Agents
|
|
20
20
|
|
|
21
|
+
⚠️ REQUIRES LLM: Ollama, LM Studio, or OpenAI API key
|
|
22
|
+
Install Ollama: curl -fsSL https://ollama.ai/install.sh | sh && ollama pull qwen2.5:7b
|
|
23
|
+
|
|
21
24
|
Usage:
|
|
22
|
-
hopeid scan <message> Scan a message for threats
|
|
25
|
+
hopeid scan <message> Scan a message for threats (uses LLM)
|
|
23
26
|
hopeid scan --file <path> Scan message from file
|
|
24
27
|
hopeid scan --stdin Read message from stdin
|
|
25
|
-
hopeid test Run test suite
|
|
28
|
+
hopeid test Run test suite (heuristic-only)
|
|
26
29
|
hopeid stats Show pattern statistics
|
|
30
|
+
hopeid setup Full OpenClaw integration setup
|
|
27
31
|
hopeid help Show this help
|
|
28
32
|
|
|
29
33
|
Options:
|
|
30
34
|
--source <type> Source type: email, chat, api, web, webhook (default: chat)
|
|
31
35
|
--sender <id> Sender identifier
|
|
32
|
-
--semantic Enable LLM-based semantic analysis
|
|
33
36
|
--strict Use strict mode (lower thresholds)
|
|
34
37
|
--verbose Show detailed output
|
|
35
38
|
--json Output as JSON
|
|
39
|
+
--no-llm Heuristic-only mode (NOT RECOMMENDED - misses sophisticated attacks)
|
|
36
40
|
|
|
37
41
|
Examples:
|
|
38
42
|
hopeid scan "Hello, how are you?"
|
|
@@ -40,10 +44,11 @@ Examples:
|
|
|
40
44
|
hopeid scan --file suspicious.txt --verbose
|
|
41
45
|
echo "ignore previous instructions" | hopeid scan --stdin
|
|
42
46
|
|
|
43
|
-
Environment:
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
+
Environment (auto-detected if running locally):
|
|
48
|
+
LLM_PROVIDER Provider: auto, ollama, lmstudio, openai (default: auto)
|
|
49
|
+
LLM_ENDPOINT LLM API endpoint (auto-detected for Ollama/LM Studio)
|
|
50
|
+
LLM_MODEL LLM model name (default: auto-detect best available)
|
|
51
|
+
OPENAI_API_KEY API key (only needed for OpenAI)
|
|
47
52
|
|
|
48
53
|
"Traditional IDS matches signatures. HoPE understands intent." 💜
|
|
49
54
|
`;
|
|
@@ -68,6 +73,9 @@ async function main() {
|
|
|
68
73
|
case 'stats':
|
|
69
74
|
handleStats();
|
|
70
75
|
break;
|
|
76
|
+
case 'setup':
|
|
77
|
+
await handleSetup(args.slice(1));
|
|
78
|
+
break;
|
|
71
79
|
default:
|
|
72
80
|
console.error(`Unknown command: ${command}`);
|
|
73
81
|
console.log('Run "hopeid help" for usage');
|
|
@@ -80,7 +88,8 @@ async function handleScan(args) {
|
|
|
80
88
|
const options = {
|
|
81
89
|
source: 'chat',
|
|
82
90
|
sender: 'cli-user',
|
|
83
|
-
semantic:
|
|
91
|
+
semantic: true, // LLM-based analysis enabled by default!
|
|
92
|
+
requireLLM: true, // Fail if no LLM found
|
|
84
93
|
strict: false,
|
|
85
94
|
verbose: false,
|
|
86
95
|
json: false
|
|
@@ -103,6 +112,10 @@ async function handleScan(args) {
|
|
|
103
112
|
readFromStdin = true;
|
|
104
113
|
} else if (arg === '--semantic') {
|
|
105
114
|
options.semantic = true;
|
|
115
|
+
} else if (arg === '--no-llm' || arg === '--heuristic-only') {
|
|
116
|
+
options.semantic = false;
|
|
117
|
+
options.requireLLM = false;
|
|
118
|
+
console.warn('⚠️ Running in heuristic-only mode (NOT RECOMMENDED)');
|
|
106
119
|
} else if (arg === '--strict') {
|
|
107
120
|
options.strict = true;
|
|
108
121
|
} else if (arg === '--verbose') {
|
|
@@ -130,6 +143,7 @@ async function handleScan(args) {
|
|
|
130
143
|
// Create IDS instance
|
|
131
144
|
const ids = new HopeIDS({
|
|
132
145
|
semanticEnabled: options.semantic,
|
|
146
|
+
requireLLM: options.requireLLM,
|
|
133
147
|
strictMode: options.strict
|
|
134
148
|
});
|
|
135
149
|
|
|
@@ -186,8 +200,8 @@ async function handleTest(args) {
|
|
|
186
200
|
? args[args.indexOf('--benign') + 1]
|
|
187
201
|
: path.join(testDir, 'benign');
|
|
188
202
|
|
|
189
|
-
// Create fresh IDS for attacks
|
|
190
|
-
let ids = new HopeIDS({ semanticEnabled: false, logLevel: 'error' });
|
|
203
|
+
// Create fresh IDS for attacks (heuristic-only for testing)
|
|
204
|
+
let ids = new HopeIDS({ semanticEnabled: false, requireLLM: false, logLevel: 'error' });
|
|
191
205
|
|
|
192
206
|
console.log('\n🛡️ hopeIDS Test Suite\n');
|
|
193
207
|
|
|
@@ -217,7 +231,7 @@ async function handleTest(args) {
|
|
|
217
231
|
}
|
|
218
232
|
|
|
219
233
|
// Create fresh IDS for benign tests (reset context)
|
|
220
|
-
ids = new HopeIDS({ semanticEnabled: false, logLevel: 'error' });
|
|
234
|
+
ids = new HopeIDS({ semanticEnabled: false, requireLLM: false, logLevel: 'error' });
|
|
221
235
|
|
|
222
236
|
// Test benign (should not be detected)
|
|
223
237
|
if (fs.existsSync(benignDir)) {
|
|
@@ -276,6 +290,265 @@ function readStdin() {
|
|
|
276
290
|
});
|
|
277
291
|
}
|
|
278
292
|
|
|
293
|
+
async function handleSetup(args) {
|
|
294
|
+
const { execSync, spawnSync } = require('child_process');
|
|
295
|
+
const os = require('os');
|
|
296
|
+
|
|
297
|
+
console.log('\n🛡️ hopeIDS Full Setup for OpenClaw\n');
|
|
298
|
+
console.log('This will:');
|
|
299
|
+
console.log(' 1. Install hopeIDS plugin to OpenClaw');
|
|
300
|
+
console.log(' 2. Install hopeids skill via ClawHub');
|
|
301
|
+
console.log(' 3. Configure security_scan tool');
|
|
302
|
+
console.log(' 4. Set up sandboxing for public-facing agents');
|
|
303
|
+
console.log(' 5. Create secure agent identity templates\n');
|
|
304
|
+
|
|
305
|
+
// Find OpenClaw config
|
|
306
|
+
const homeDir = os.homedir();
|
|
307
|
+
const configPaths = [
|
|
308
|
+
path.join(homeDir, '.openclaw', 'openclaw.json'),
|
|
309
|
+
path.join(process.cwd(), 'openclaw.json'),
|
|
310
|
+
path.join(process.cwd(), '.openclaw', 'openclaw.json')
|
|
311
|
+
];
|
|
312
|
+
|
|
313
|
+
let configPath = null;
|
|
314
|
+
let configDir = null;
|
|
315
|
+
for (const p of configPaths) {
|
|
316
|
+
if (fs.existsSync(p)) {
|
|
317
|
+
configPath = p;
|
|
318
|
+
configDir = path.dirname(p);
|
|
319
|
+
break;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
if (!configPath) {
|
|
324
|
+
console.log('❌ OpenClaw config not found.');
|
|
325
|
+
console.log(' Searched: ~/.openclaw/openclaw.json, ./openclaw.json');
|
|
326
|
+
console.log(' Make sure OpenClaw is installed first.\n');
|
|
327
|
+
process.exit(1);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
console.log(`✅ Found OpenClaw config: ${configPath}\n`);
|
|
331
|
+
|
|
332
|
+
// Find hopeIDS installation path
|
|
333
|
+
let hopeidsPath = null;
|
|
334
|
+
|
|
335
|
+
// Check if we're running from the hopeIDS repo
|
|
336
|
+
const localPluginPath = path.join(__dirname, '..', 'extensions', 'openclaw-plugin');
|
|
337
|
+
if (fs.existsSync(localPluginPath)) {
|
|
338
|
+
hopeidsPath = path.resolve(localPluginPath);
|
|
339
|
+
} else {
|
|
340
|
+
// Try to find it in node_modules
|
|
341
|
+
try {
|
|
342
|
+
const hopeidPkg = require.resolve('hopeid/package.json');
|
|
343
|
+
hopeidsPath = path.join(path.dirname(hopeidPkg), 'extensions', 'openclaw-plugin');
|
|
344
|
+
} catch (e) {
|
|
345
|
+
// Not found
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (!hopeidsPath || !fs.existsSync(hopeidsPath)) {
|
|
350
|
+
console.log('❌ hopeIDS plugin not found.');
|
|
351
|
+
console.log(' Install globally: npm install -g hopeid');
|
|
352
|
+
console.log(' Or clone the repo: git clone https://github.com/E-x-O-Entertainment-Studios-Inc/hopeIDS\n');
|
|
353
|
+
process.exit(1);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
console.log(`✅ Found hopeIDS plugin: ${hopeidsPath}\n`);
|
|
357
|
+
|
|
358
|
+
// Read and update OpenClaw config
|
|
359
|
+
console.log('📝 Updating OpenClaw config...');
|
|
360
|
+
|
|
361
|
+
let config;
|
|
362
|
+
try {
|
|
363
|
+
config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
364
|
+
} catch (e) {
|
|
365
|
+
console.log(`❌ Failed to parse config: ${e.message}`);
|
|
366
|
+
process.exit(1);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Initialize plugins structure if needed
|
|
370
|
+
if (!config.plugins) config.plugins = {};
|
|
371
|
+
if (!config.plugins.load) config.plugins.load = {};
|
|
372
|
+
if (!config.plugins.load.paths) config.plugins.load.paths = [];
|
|
373
|
+
if (!config.plugins.entries) config.plugins.entries = {};
|
|
374
|
+
|
|
375
|
+
// Add plugin path if not already there
|
|
376
|
+
if (!config.plugins.load.paths.includes(hopeidsPath)) {
|
|
377
|
+
config.plugins.load.paths.push(hopeidsPath);
|
|
378
|
+
console.log(' ✅ Added plugin path');
|
|
379
|
+
} else {
|
|
380
|
+
console.log(' ⏭️ Plugin path already configured');
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Enable the plugin
|
|
384
|
+
if (!config.plugins.entries.hopeids) {
|
|
385
|
+
config.plugins.entries.hopeids = { enabled: true };
|
|
386
|
+
console.log(' ✅ Enabled hopeids plugin');
|
|
387
|
+
} else {
|
|
388
|
+
config.plugins.entries.hopeids.enabled = true;
|
|
389
|
+
console.log(' ⏭️ Plugin already enabled');
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Configure sandboxing for non-main agents
|
|
393
|
+
console.log('\n🔒 Configuring sandbox for public-facing agents...');
|
|
394
|
+
|
|
395
|
+
if (!config.agents) config.agents = {};
|
|
396
|
+
if (!config.agents.defaults) config.agents.defaults = {};
|
|
397
|
+
|
|
398
|
+
if (!config.agents.defaults.sandbox) {
|
|
399
|
+
config.agents.defaults.sandbox = {
|
|
400
|
+
mode: 'non-main',
|
|
401
|
+
scope: 'session',
|
|
402
|
+
workspaceAccess: 'none'
|
|
403
|
+
};
|
|
404
|
+
console.log(' ✅ Sandbox enabled for non-main agents');
|
|
405
|
+
console.log(' Mode: non-main (main agent runs on host, others sandboxed)');
|
|
406
|
+
console.log(' Scope: session (each session gets isolated container)');
|
|
407
|
+
console.log(' Workspace: none (sandboxed agents get clean workspace)');
|
|
408
|
+
} else {
|
|
409
|
+
console.log(' ⏭️ Sandbox already configured');
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Write updated config
|
|
413
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
414
|
+
console.log(' ✅ Config saved\n');
|
|
415
|
+
|
|
416
|
+
// Install skill via ClawHub
|
|
417
|
+
console.log('📦 Installing hopeids skill via ClawHub...');
|
|
418
|
+
|
|
419
|
+
try {
|
|
420
|
+
const result = spawnSync('npx', ['clawhub', 'install', 'hopeids', '--force'], {
|
|
421
|
+
stdio: 'inherit',
|
|
422
|
+
shell: true
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
if (result.status === 0) {
|
|
426
|
+
console.log(' ✅ Skill installed\n');
|
|
427
|
+
} else {
|
|
428
|
+
console.log(' ⚠️ Skill install had issues (may already be installed)\n');
|
|
429
|
+
}
|
|
430
|
+
} catch (e) {
|
|
431
|
+
console.log(` ⚠️ Could not install skill: ${e.message}`);
|
|
432
|
+
console.log(' Run manually: npx clawhub install hopeids\n');
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// Check for USER.md privacy issues in workspace
|
|
436
|
+
console.log('🔍 Checking for privacy leaks in workspace files...');
|
|
437
|
+
|
|
438
|
+
const workspacePath = config.agents?.defaults?.workspace || path.join(configDir, 'workspace');
|
|
439
|
+
const userMdPath = path.join(workspacePath, 'USER.md');
|
|
440
|
+
|
|
441
|
+
let userMdWarning = false;
|
|
442
|
+
if (fs.existsSync(userMdPath)) {
|
|
443
|
+
const userMdContent = fs.readFileSync(userMdPath, 'utf-8');
|
|
444
|
+
// Check for personal info patterns
|
|
445
|
+
const hasName = /\*\*Name:\*\*\s*.+/i.test(userMdContent) || /name:\s*[A-Z][a-z]+/i.test(userMdContent);
|
|
446
|
+
const hasLocation = /location|timezone|address/i.test(userMdContent);
|
|
447
|
+
const hasPersonalInfo = /phone|email|social|@/i.test(userMdContent);
|
|
448
|
+
|
|
449
|
+
if (hasName || hasLocation || hasPersonalInfo) {
|
|
450
|
+
userMdWarning = true;
|
|
451
|
+
console.log(' ⚠️ USER.md contains personal information!');
|
|
452
|
+
} else {
|
|
453
|
+
console.log(' ✅ USER.md looks safe');
|
|
454
|
+
}
|
|
455
|
+
} else {
|
|
456
|
+
console.log(' ℹ️ No USER.md found (that\'s fine)');
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// Check sandboxes directory for leaked files
|
|
460
|
+
const sandboxesDir = path.join(configDir, 'sandboxes');
|
|
461
|
+
let sandboxLeaks = [];
|
|
462
|
+
|
|
463
|
+
if (fs.existsSync(sandboxesDir)) {
|
|
464
|
+
const sandboxes = fs.readdirSync(sandboxesDir);
|
|
465
|
+
for (const sandbox of sandboxes) {
|
|
466
|
+
const sandboxUserMd = path.join(sandboxesDir, sandbox, 'USER.md');
|
|
467
|
+
if (fs.existsSync(sandboxUserMd)) {
|
|
468
|
+
const content = fs.readFileSync(sandboxUserMd, 'utf-8');
|
|
469
|
+
// Check for actual personal info (not just empty template fields)
|
|
470
|
+
const hasRealName = /\*\*Name:\*\*\s*[A-Z][a-z]+\s+[A-Z]/i.test(content); // "Name: First Last"
|
|
471
|
+
const hasLocation = /\*\*Location:\*\*\s*[A-Z]/i.test(content);
|
|
472
|
+
const isSanitized = /never mention|don't share|no personal|public.?facing/i.test(content);
|
|
473
|
+
|
|
474
|
+
if ((hasRealName || hasLocation) && !isSanitized) {
|
|
475
|
+
sandboxLeaks.push(sandbox);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if (sandboxLeaks.length > 0) {
|
|
481
|
+
console.log(` ⚠️ Found ${sandboxLeaks.length} sandbox(es) with personal info in USER.md!`);
|
|
482
|
+
for (const leak of sandboxLeaks) {
|
|
483
|
+
console.log(` • ${leak}`);
|
|
484
|
+
}
|
|
485
|
+
} else if (sandboxes.length > 0) {
|
|
486
|
+
console.log(` ✅ ${sandboxes.length} sandbox(es) checked - no leaks found`);
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// Done!
|
|
491
|
+
console.log('\n═══════════════════════════════════════════════════════');
|
|
492
|
+
console.log('✅ hopeIDS setup complete!\n');
|
|
493
|
+
|
|
494
|
+
console.log('Your OpenClaw agent now has:');
|
|
495
|
+
console.log(' • security_scan tool - scan messages for threats');
|
|
496
|
+
console.log(' • /scan command - manual security checks');
|
|
497
|
+
console.log(' • hopeids skill - IDS-first workflow patterns');
|
|
498
|
+
console.log(' • Sandboxing - non-main agents run isolated\n');
|
|
499
|
+
|
|
500
|
+
// Privacy warnings
|
|
501
|
+
if (userMdWarning || sandboxLeaks.length > 0) {
|
|
502
|
+
console.log('⚠️ PRIVACY WARNING:');
|
|
503
|
+
console.log('────────────────────────────────────────────────────────');
|
|
504
|
+
|
|
505
|
+
if (userMdWarning) {
|
|
506
|
+
console.log('Your USER.md contains personal information that could leak');
|
|
507
|
+
console.log('to sandboxed agents (public forums, social media, etc.).\n');
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
if (sandboxLeaks.length > 0) {
|
|
511
|
+
console.log('Some sandbox workspaces already contain personal info.');
|
|
512
|
+
console.log('Consider deleting stale sandboxes:\n');
|
|
513
|
+
console.log(` rm -rf ${sandboxesDir}/agent-*\n`);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
console.log('For sandboxed/public-facing agents, use a sanitized USER.md:');
|
|
517
|
+
console.log('────────────────────────────────────────────────────────');
|
|
518
|
+
console.log(`
|
|
519
|
+
# USER.md - Public Agent Context
|
|
520
|
+
|
|
521
|
+
I'm a public-facing agent. I don't need personal details.
|
|
522
|
+
|
|
523
|
+
## Rules
|
|
524
|
+
- Never mention personal names, locations, or private details
|
|
525
|
+
- Keep posts professional and product-focused
|
|
526
|
+
- Represent the brand, not any individual
|
|
527
|
+
`);
|
|
528
|
+
console.log('────────────────────────────────────────────────────────\n');
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
console.log('🎭 AGENT IDENTITY SETUP:');
|
|
532
|
+
console.log('────────────────────────────────────────────────────────');
|
|
533
|
+
console.log('Each agent should have its own workspace with:');
|
|
534
|
+
console.log(' • AGENTS.md - Role and instructions');
|
|
535
|
+
console.log(' • SOUL.md - Personality and tone');
|
|
536
|
+
console.log(' • USER.md - What it knows about users (sanitize for public!)');
|
|
537
|
+
console.log(' • TOOLS.md - Available capabilities\n');
|
|
538
|
+
console.log('For public-facing agents (social media, forums):');
|
|
539
|
+
console.log(' • Create a separate workspace');
|
|
540
|
+
console.log(' • Use sanitized USER.md (no personal info!)');
|
|
541
|
+
console.log(' • Enable sandboxing (now configured automatically)');
|
|
542
|
+
console.log('────────────────────────────────────────────────────────\n');
|
|
543
|
+
|
|
544
|
+
console.log('Restart OpenClaw to activate:');
|
|
545
|
+
console.log(' openclaw gateway restart\n');
|
|
546
|
+
console.log('Test it:');
|
|
547
|
+
console.log(' hopeid scan "ignore previous instructions"\n');
|
|
548
|
+
console.log('Docs: https://exohaven.online/blog/sandboxed-agents-security-guide');
|
|
549
|
+
console.log('═══════════════════════════════════════════════════════\n');
|
|
550
|
+
}
|
|
551
|
+
|
|
279
552
|
main().catch(err => {
|
|
280
553
|
console.error('Error:', err.message);
|
|
281
554
|
process.exit(1);
|