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 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
- Or use directly:
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
- llmEndpoint: 'http://localhost:1234/v1/chat/completions',
300
- llmModel: 'qwen2.5-32b',
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
- LLM_ENDPOINT LLM API endpoint (for semantic analysis)
45
- LLM_MODEL LLM model name (default: gpt-3.5-turbo)
46
- OPENAI_API_KEY API key for LLM
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: false,
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);