clawmoat 0.2.1 → 0.5.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.
Files changed (56) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/Dockerfile +22 -0
  3. package/README.md +144 -5
  4. package/SECURITY.md +63 -0
  5. package/bin/clawmoat.js +186 -1
  6. package/docs/ai-agent-security-scanner.html +691 -0
  7. package/docs/apple-touch-icon.png +0 -0
  8. package/docs/blog/host-guardian-launch.html +345 -0
  9. package/docs/blog/host-guardian-launch.md +249 -0
  10. package/docs/blog/index.html +2 -0
  11. package/docs/blog/langchain-security-tutorial.html +319 -0
  12. package/docs/blog/owasp-agentic-ai-top10.html +2 -0
  13. package/docs/blog/securing-ai-agents.html +2 -0
  14. package/docs/compare.html +2 -0
  15. package/docs/favicon.png +0 -0
  16. package/docs/icon-192.png +0 -0
  17. package/docs/index.html +258 -65
  18. package/docs/integrations/langchain.html +2 -0
  19. package/docs/integrations/openai.html +2 -0
  20. package/docs/integrations/openclaw.html +2 -0
  21. package/docs/logo.png +0 -0
  22. package/docs/logo.svg +60 -0
  23. package/docs/mark-with-moat.svg +33 -0
  24. package/docs/mark.png +0 -0
  25. package/docs/mark.svg +30 -0
  26. package/docs/og-image.png +0 -0
  27. package/docs/playground.html +440 -0
  28. package/docs/positioning-v2.md +155 -0
  29. package/docs/report-demo.html +399 -0
  30. package/docs/thanks.html +2 -0
  31. package/examples/github-action-workflow.yml +94 -0
  32. package/logo.png +0 -0
  33. package/logo.svg +60 -0
  34. package/mark-with-moat.svg +33 -0
  35. package/mark.png +0 -0
  36. package/mark.svg +30 -0
  37. package/package.json +1 -1
  38. package/server/index.js +9 -5
  39. package/skill/README.md +57 -0
  40. package/skill/SKILL.md +49 -30
  41. package/skill/scripts/audit.sh +28 -0
  42. package/skill/scripts/scan.sh +32 -0
  43. package/skill/scripts/test.sh +13 -0
  44. package/src/guardian/alerts.js +138 -0
  45. package/src/guardian/index.js +686 -0
  46. package/src/guardian/network-log.js +281 -0
  47. package/src/guardian/skill-integrity.js +290 -0
  48. package/src/index.js +37 -0
  49. package/src/middleware/openclaw.js +76 -1
  50. package/src/scanners/excessive-agency.js +88 -0
  51. package/wiki/Architecture.md +103 -0
  52. package/wiki/CLI-Reference.md +167 -0
  53. package/wiki/FAQ.md +135 -0
  54. package/wiki/Home.md +70 -0
  55. package/wiki/Policy-Engine.md +229 -0
  56. package/wiki/Scanner-Modules.md +224 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,32 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [0.3.0] - 2025-02-18
6
+
7
+ ### Added
8
+ - **Excessive Agency Scanner (ASI02/ASI03)**: Advanced security scanning for AI agent behaviors with comprehensive test coverage
9
+ - **OpenClaw Skill Integration**: Security scanning capabilities specifically designed for AI agent sessions
10
+ - **CI/CD Workflow**: Automated testing and continuous integration setup
11
+ - **SVG Brand Assets**: New logo, mark, and mark-with-moat SVG assets for better branding
12
+
13
+ ### Changed
14
+ - **Renamed Pro Skill to Security Kit**: Better reflects the comprehensive security features
15
+ - **New Pricing Structure**:
16
+ - Pro Skill (Security Kit) now available as one-time $29 purchase
17
+ - Shield and Team subscriptions with 30-day trial period
18
+ - 14-day money-back guarantee
19
+ - **Improved Documentation**: Enhanced README with better feature descriptions and setup instructions
20
+
21
+ ### Fixed
22
+ - Checkout system now points to live Railway URL for better reliability
23
+ - Various styling improvements for better user experience
24
+
25
+ ### UI/UX Improvements
26
+ - Bigger, transparent SVG logo with left-aligned navigation
27
+ - More space between logo and navigation links
28
+ - Narrower pill-shaped "Get Access" button
29
+ - Enhanced "Join Waitlist" and "Get Started" button styling and functionality
30
+
31
+ ## [0.2.1] - Previous Release
32
+ - Initial stable release with core security features
package/Dockerfile ADDED
@@ -0,0 +1,22 @@
1
+ FROM node:20-alpine
2
+
3
+ # Set working directory
4
+ WORKDIR /app
5
+
6
+ # Install dependencies
7
+ COPY package.json ./
8
+ RUN npm install --omit=dev
9
+
10
+ # Copy source code
11
+ COPY . .
12
+
13
+ # Ensure CLI is executable
14
+ RUN chmod +x bin/clawmoat.js
15
+
16
+ # Environment variables
17
+ ENV NODE_ENV=production
18
+ ENV CLAWMOAT_POLICY=strict
19
+
20
+ # CLI entrypoint
21
+ ENTRYPOINT ["node", "bin/clawmoat.js"]
22
+
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  <p align="center">
2
- <img src="https://img.shields.io/badge/🏰-ClawMoat-0F172A?style=for-the-badge&labelColor=10B981" alt="ClawMoat">
2
+ <img src="logo.png" alt="ClawMoat" width="400">
3
3
  </p>
4
4
 
5
- <h1 align="center">🏰 ClawMoat</h1>
5
+ <h1 align="center">ClawMoat</h1>
6
6
  <p align="center"><strong>Security moat for AI agents</strong></p>
7
7
  <p align="center">Runtime protection against prompt injection, tool misuse, and data exfiltration.</p>
8
8
 
@@ -20,6 +20,21 @@
20
20
 
21
21
  ---
22
22
 
23
+ ## Why ClawMoat?
24
+
25
+ Building with **LangChain**, **CrewAI**, **AutoGen**, or **OpenAI Agents**? Your agents have real capabilities — shell access, file I/O, web browsing, email. That's powerful, but one prompt injection in an email or scraped webpage can hijack your agent into exfiltrating secrets, running malicious commands, or poisoning its own memory.
26
+
27
+ **ClawMoat is the missing security layer.** Drop it in front of your agent and get:
28
+
29
+ - 🛡️ **Prompt injection detection** — multi-layer scanning catches instruction overrides, delimiter attacks, encoded payloads
30
+ - 🔐 **Secret & PII scanning** — 30+ credential patterns + PII detection on outbound text
31
+ - ⚡ **Zero dependencies** — pure Node.js, no ML models to download, sub-millisecond scans
32
+ - 🔧 **CI/CD ready** — GitHub Actions workflow included, fail builds on security violations
33
+ - 📋 **Policy engine** — YAML-based rules for shell, file, browser, and network access
34
+ - 🏰 **OWASP coverage** — maps to all 10 risks in the OWASP Top 10 for Agentic AI
35
+
36
+ **Works with any agent framework.** ClawMoat scans text — it doesn't care if it came from LangChain, CrewAI, AutoGen, or your custom agent.
37
+
23
38
  ## The Problem
24
39
 
25
40
  AI agents have shell access, browser control, email, and file system access. A single prompt injection in an email or webpage can hijack your agent into exfiltrating data, running malicious commands, or impersonating you.
@@ -46,6 +61,16 @@ clawmoat protect --config clawmoat.yml
46
61
  clawmoat dashboard
47
62
  ```
48
63
 
64
+ ### New in v0.5.0
65
+
66
+ - 🔑 **Credential Monitor** — watches `~/.openclaw/credentials/` for unauthorized access and modifications using file hashing
67
+ - 🧩 **Skill Integrity Checker** — hashes all SKILL.md and script files, detects tampering, flags suspicious patterns (eval, base64, curl to external URLs). CLI: `clawmoat skill-audit`
68
+ - 🌐 **Network Egress Logger** — parses session logs for all outbound URLs, maintains domain allowlists, flags known-bad domains (webhook.site, ngrok, etc.)
69
+ - 🚨 **Alert Delivery System** — unified alerts via console, file (audit.log), or webhook with severity levels and 5-minute rate limiting
70
+ - 🤝 **Inter-Agent Message Scanner** — heightened-sensitivity scanning for agent-to-agent messages detecting impersonation, concealment, credential exfiltration, and safety bypasses
71
+ - 📊 **Activity Reports** — `clawmoat report` generates 24h summaries of agent activity, tool usage, and network egress
72
+ - 👻 **Daemon Mode** — `clawmoat watch --daemon` runs in background with PID file; `--alert-webhook=URL` for remote alerting
73
+
49
74
  ### As an OpenClaw Skill
50
75
 
51
76
  ```bash
@@ -54,6 +79,36 @@ openclaw skills add clawmoat
54
79
 
55
80
  Automatically scans inbound messages, audits tool calls, blocks violations, and logs events.
56
81
 
82
+ ## GitHub Action
83
+
84
+ Add ClawMoat to your CI pipeline to catch prompt injection and secret leaks before they merge:
85
+
86
+ ```yaml
87
+ # .github/workflows/clawmoat.yml
88
+ name: ClawMoat Scan
89
+ on: [pull_request]
90
+
91
+ permissions:
92
+ contents: read
93
+ pull-requests: write
94
+
95
+ jobs:
96
+ scan:
97
+ runs-on: ubuntu-latest
98
+ steps:
99
+ - uses: actions/checkout@v4
100
+ - uses: actions/setup-node@v4
101
+ with:
102
+ node-version: '20'
103
+ - uses: darfaz/clawmoat/.github/actions/scan@main
104
+ with:
105
+ paths: '.'
106
+ fail-on: 'critical' # critical | high | medium | low | none
107
+ format: 'summary'
108
+ ```
109
+
110
+ Results appear as PR comments and job summaries. See [`examples/github-action-workflow.yml`](examples/github-action-workflow.yml) for more patterns.
111
+
57
112
  ## Features
58
113
 
59
114
  | Feature | Description | Status |
@@ -63,7 +118,90 @@ Automatically scans inbound messages, audits tool calls, blocks violations, and
63
118
  | 📋 **Policy Engine** | YAML rules for shell, files, browser, network | ✅ v0.1 |
64
119
  | 🕵️ **Jailbreak Detection** | Heuristic + classifier pipeline | ✅ v0.1 |
65
120
  | 📊 **Session Audit Trail** | Full tamper-evident action log | ✅ v0.1 |
66
- | 🧠 **Behavioral Analysis** | Anomaly detection on agent behavior | 🔜 v0.3 |
121
+ | 🧠 **Behavioral Analysis** | Anomaly detection on agent behavior | 🔜 v0.5 |
122
+ | 🏠 **Host Guardian** | Runtime security for laptop-hosted agents | ✅ v0.4 |
123
+
124
+ ## 🏠 Host Guardian — Security for Laptop-Hosted Agents
125
+
126
+ Running an AI agent on your actual laptop? **Host Guardian** is the trust layer that makes it safe. It monitors every file access, command, and network request — blocking dangerous actions before they execute.
127
+
128
+ ### Permission Tiers
129
+
130
+ Start locked down, open up as trust grows:
131
+
132
+ | Mode | File Read | File Write | Shell | Network | Use Case |
133
+ |------|-----------|------------|-------|---------|----------|
134
+ | **Observer** | Workspace only | ❌ | ❌ | ❌ | Testing a new agent |
135
+ | **Worker** | Workspace only | Workspace only | Safe commands | Fetch only | Daily use |
136
+ | **Standard** | System-wide | Workspace only | Most commands | ✅ | Power users |
137
+ | **Full** | Everything | Everything | Everything | ✅ | Audit-only mode |
138
+
139
+ ### Quick Start
140
+
141
+ ```js
142
+ const { HostGuardian } = require('clawmoat');
143
+
144
+ const guardian = new HostGuardian({ mode: 'standard' });
145
+
146
+ // Check before every tool call
147
+ guardian.check('read', { path: '~/.ssh/id_rsa' });
148
+ // => { allowed: false, reason: 'Protected zone: SSH keys', severity: 'critical' }
149
+
150
+ guardian.check('exec', { command: 'rm -rf /' });
151
+ // => { allowed: false, reason: 'Dangerous command blocked: Recursive force delete', severity: 'critical' }
152
+
153
+ guardian.check('exec', { command: 'git status' });
154
+ // => { allowed: true, decision: 'allow' }
155
+
156
+ // Runtime mode switching
157
+ guardian.setMode('worker'); // Lock down further
158
+
159
+ // Full audit trail
160
+ console.log(guardian.report());
161
+ ```
162
+
163
+ ### What It Protects
164
+
165
+ **🔒 Forbidden Zones** (always blocked):
166
+ - SSH keys, GPG keys, AWS/GCloud/Azure credentials
167
+ - Browser cookies & login data, password managers
168
+ - Crypto wallets, `.env` files, `.netrc`
169
+ - System files (`/etc/shadow`, `/etc/sudoers`)
170
+
171
+ **⚡ Dangerous Commands** (blocked by tier):
172
+ - Destructive: `rm -rf`, `mkfs`, `dd`
173
+ - Escalation: `sudo`, `chmod +s`, `su -`
174
+ - Network: reverse shells, `ngrok`, `curl | bash`
175
+ - Persistence: `crontab`, modifying `.bashrc`
176
+ - Exfiltration: `curl --data`, `scp` to unknown hosts
177
+
178
+ **📋 Audit Trail**: Every action recorded with timestamps, verdicts, and reasons. Generate reports anytime.
179
+
180
+ ### Configuration
181
+
182
+ ```js
183
+ const guardian = new HostGuardian({
184
+ mode: 'worker',
185
+ workspace: '~/.openclaw/workspace',
186
+ safeZones: ['~/projects', '~/Documents'], // Additional allowed paths
187
+ forbiddenZones: ['~/tax-returns'], // Custom protected paths
188
+ onViolation: (tool, args, verdict) => { // Alert callback
189
+ notify(`⚠️ Blocked: ${verdict.reason}`);
190
+ },
191
+ });
192
+ ```
193
+
194
+ Or via `clawmoat.yml`:
195
+
196
+ ```yaml
197
+ guardian:
198
+ mode: standard
199
+ workspace: ~/.openclaw/workspace
200
+ safe_zones:
201
+ - ~/projects
202
+ forbidden_zones:
203
+ - ~/tax-returns
204
+ ```
67
205
 
68
206
  ## Architecture
69
207
 
@@ -146,7 +284,7 @@ ClawMoat maps to the [OWASP Top 10 for Agentic AI (2026)](https://genai.owasp.or
146
284
  | OWASP Risk | Description | ClawMoat Protection | Status |
147
285
  |-----------|-------------|---------------------|--------|
148
286
  | **ASI01** | Prompt Injection & Manipulation | Multi-layer injection scanning on all inbound content | ✅ |
149
- | **ASI02** | Excessive Agency & Permissions | Policy engine enforces least-privilege per tool | ✅ |
287
+ | **ASI02** | Excessive Agency & Permissions | Escalation detection + policy engine enforces least-privilege | ✅ |
150
288
  | **ASI03** | Insecure Tool Use | Command validation & argument sanitization | ✅ |
151
289
  | **ASI04** | Insufficient Output Validation | Output scanning for secrets, PII, dangerous code | ✅ |
152
290
  | **ASI05** | Memory & Context Poisoning | Context integrity checks on memory retrievals | 🔜 |
@@ -167,7 +305,8 @@ clawmoat/
167
305
  │ │ ├── prompt-injection.js
168
306
  │ │ ├── jailbreak.js
169
307
  │ │ ├── secrets.js
170
- │ │ └── pii.js
308
+ │ │ ├── pii.js
309
+ │ │ └── excessive-agency.js
171
310
  │ ├── policies/ # Policy enforcement
172
311
  │ │ ├── engine.js
173
312
  │ │ ├── exec.js
package/SECURITY.md ADDED
@@ -0,0 +1,63 @@
1
+ # Security Policy
2
+
3
+ ## Supported Versions
4
+
5
+ | Version | Supported |
6
+ |---------|--------------------|
7
+ | 0.1.x | ✅ Current release |
8
+
9
+ ## Reporting a Vulnerability
10
+
11
+ If you discover a security vulnerability in ClawMoat, **please report it responsibly**.
12
+
13
+ ### How to Report
14
+
15
+ 1. **Email:** Send details to **security@clawmoat.com**
16
+ 2. **Subject line:** `[SECURITY] Brief description`
17
+ 3. **Include:**
18
+ - Description of the vulnerability
19
+ - Steps to reproduce
20
+ - Potential impact
21
+ - Suggested fix (if any)
22
+
23
+ ### What to Expect
24
+
25
+ - **Acknowledgment** within 48 hours
26
+ - **Assessment** within 7 days
27
+ - **Fix timeline** communicated within 14 days
28
+ - **Credit** in the release notes (unless you prefer anonymity)
29
+
30
+ ### What NOT to Do
31
+
32
+ - Do not open a public GitHub issue for security vulnerabilities
33
+ - Do not exploit the vulnerability beyond what's needed to demonstrate it
34
+ - Do not access or modify other users' data
35
+
36
+ ## Scope
37
+
38
+ The following are in scope:
39
+
40
+ - **Scanner bypasses** — Attacks that evade ClawMoat's detection
41
+ - **Policy engine bypasses** — Tool calls that circumvent policy rules
42
+ - **Audit log tampering** — Ways to modify or forge audit entries
43
+ - **Dependency issues** — Vulnerabilities in ClawMoat's dependencies (currently: none)
44
+
45
+ The following are out of scope:
46
+
47
+ - Denial of service via large inputs (expected behavior — use input size limits)
48
+ - False positives/negatives in detection (please open a regular issue)
49
+ - Vulnerabilities in upstream LLM providers
50
+
51
+ ## Security Best Practices
52
+
53
+ When using ClawMoat:
54
+
55
+ 1. Keep ClawMoat updated to the latest version
56
+ 2. Enable all relevant scanners for your use case
57
+ 3. Use strict policy configurations in production
58
+ 4. Review audit logs regularly
59
+ 5. Set up alerts for critical-severity findings
60
+
61
+ ## PGP Key
62
+
63
+ For encrypted communications, use our PGP key (available on request at security@clawmoat.com).
package/bin/clawmoat.js CHANGED
@@ -16,6 +16,10 @@ const path = require('path');
16
16
  const ClawMoat = require('../src/index');
17
17
  const { scanSkillContent } = require('../src/scanners/supply-chain');
18
18
  const { calculateGrade, generateBadgeSVG, getShieldsURL } = require('../src/badge');
19
+ const { SkillIntegrityChecker } = require('../src/guardian/skill-integrity');
20
+ const { NetworkEgressLogger } = require('../src/guardian/network-log');
21
+ const { AlertManager } = require('../src/guardian/alerts');
22
+ const { CredentialMonitor } = require('../src/guardian/index');
19
23
 
20
24
  const VERSION = require('../package.json').version;
21
25
  const BOLD = '\x1b[1m';
@@ -41,6 +45,12 @@ switch (command) {
41
45
  case 'watch':
42
46
  cmdWatch(args.slice(1));
43
47
  break;
48
+ case 'skill-audit':
49
+ cmdSkillAudit(args.slice(1));
50
+ break;
51
+ case 'report':
52
+ cmdReport(args.slice(1));
53
+ break;
44
54
  case 'test':
45
55
  cmdTest();
46
56
  break;
@@ -339,16 +349,46 @@ function cmdTest() {
339
349
  }
340
350
 
341
351
  function cmdWatch(args) {
342
- const agentDir = args[0] || path.join(process.env.HOME, '.openclaw/agents/main');
352
+ const isDaemon = args.includes('--daemon');
353
+ const webhookArg = args.find(a => a.startsWith('--alert-webhook='));
354
+ const webhookUrl = webhookArg ? webhookArg.split('=').slice(1).join('=') : null;
355
+ const filteredArgs = args.filter(a => a !== '--daemon' && !a.startsWith('--alert-webhook='));
356
+ const agentDir = filteredArgs[0] || path.join(process.env.HOME, '.openclaw/agents/main');
343
357
  const { watchSessions } = require('../src/middleware/openclaw');
344
358
 
359
+ // Daemon mode: fork to background
360
+ if (isDaemon) {
361
+ const { spawn } = require('child_process');
362
+ const daemonArgs = process.argv.slice(2).filter(a => a !== '--daemon');
363
+ const child = spawn(process.execPath, [__filename, ...daemonArgs], {
364
+ detached: true,
365
+ stdio: 'ignore',
366
+ });
367
+ child.unref();
368
+ const pidFile = path.join(process.env.HOME, '.clawmoat.pid');
369
+ fs.writeFileSync(pidFile, String(child.pid));
370
+ console.log(`${BOLD}🏰 ClawMoat daemon started${RESET} (PID: ${child.pid})`);
371
+ console.log(`${DIM}PID file: ${pidFile}${RESET}`);
372
+ process.exit(0);
373
+ }
374
+
375
+ // Set up alert manager
376
+ const alertChannels = ['console'];
377
+ if (webhookUrl) alertChannels.push('webhook');
378
+ const alertMgr = new AlertManager({ channels: alertChannels, webhookUrl });
379
+
345
380
  console.log(`${BOLD}🏰 ClawMoat Live Monitor${RESET}`);
346
381
  console.log(`${DIM}Watching: ${agentDir}${RESET}`);
382
+ if (webhookUrl) console.log(`${DIM}Webhook: ${webhookUrl}${RESET}`);
347
383
  console.log(`${DIM}Press Ctrl+C to stop${RESET}\n`);
348
384
 
349
385
  const monitor = watchSessions({ agentDir });
350
386
  if (!monitor) process.exit(1);
351
387
 
388
+ // Also start credential monitor
389
+ const credMon = new CredentialMonitor({ quiet: false, onAlert: (a) => alertMgr.send(a) });
390
+ credMon.start();
391
+
352
392
  // Print summary every 60s
353
393
  setInterval(() => {
354
394
  const summary = monitor.getSummary();
@@ -359,12 +399,150 @@ function cmdWatch(args) {
359
399
 
360
400
  process.on('SIGINT', () => {
361
401
  monitor.stop();
402
+ credMon.stop();
362
403
  const summary = monitor.getSummary();
363
404
  console.log(`\n${BOLD}Session Summary:${RESET} ${summary.scanned} scanned, ${summary.blocked} blocked, ${summary.warnings} warnings`);
364
405
  process.exit(0);
365
406
  });
366
407
  }
367
408
 
409
+ function cmdSkillAudit(args) {
410
+ const skillsDir = args[0] || path.join(process.env.HOME, '.openclaw', 'workspace', 'skills');
411
+
412
+ console.log(`${BOLD}🏰 ClawMoat Skill Integrity Audit${RESET}`);
413
+ console.log(`${DIM}Directory: ${skillsDir}${RESET}\n`);
414
+
415
+ if (!fs.existsSync(skillsDir)) {
416
+ console.log(`${YELLOW}Skills directory not found: ${skillsDir}${RESET}`);
417
+ console.log(`${DIM}Specify path: clawmoat skill-audit /path/to/skills${RESET}`);
418
+ process.exit(0);
419
+ }
420
+
421
+ const checker = new SkillIntegrityChecker({ skillsDir });
422
+ const initResult = checker.init();
423
+
424
+ console.log(`Files hashed: ${initResult.files}`);
425
+ console.log(`New files: ${initResult.new}`);
426
+ console.log(`Changed files: ${initResult.changed}`);
427
+ console.log();
428
+
429
+ if (initResult.suspicious.length > 0) {
430
+ console.log(`${RED}${BOLD}Suspicious patterns found:${RESET}`);
431
+ for (const f of initResult.suspicious) {
432
+ console.log(` ${RED}⚠${RESET} ${f.file}: ${f.label} ${DIM}(${f.severity})${RESET}`);
433
+ if (f.matched) console.log(` ${DIM}Matched: ${f.matched}${RESET}`);
434
+ }
435
+ } else {
436
+ console.log(`${GREEN}✅ No suspicious patterns found${RESET}`);
437
+ }
438
+
439
+ // Run audit against stored hashes
440
+ const audit = checker.audit();
441
+ if (!audit.ok) {
442
+ console.log();
443
+ if (audit.changed.length) console.log(`${RED}Changed files:${RESET} ${audit.changed.join(', ')}`);
444
+ if (audit.missing.length) console.log(`${YELLOW}Missing files:${RESET} ${audit.missing.join(', ')}`);
445
+ }
446
+
447
+ process.exit(initResult.suspicious.length > 0 || initResult.changed > 0 ? 1 : 0);
448
+ }
449
+
450
+ function cmdReport(args) {
451
+ const sessionsDir = args[0] || path.join(process.env.HOME, '.openclaw/agents/main/sessions');
452
+
453
+ console.log(`${BOLD}🏰 ClawMoat Activity Report (Last 24h)${RESET}`);
454
+ console.log(`${DIM}Sessions: ${sessionsDir}${RESET}\n`);
455
+
456
+ if (!fs.existsSync(sessionsDir)) {
457
+ console.log(`${YELLOW}Sessions directory not found${RESET}`);
458
+ process.exit(0);
459
+ }
460
+
461
+ const oneDayAgo = Date.now() - 86400000;
462
+ const files = fs.readdirSync(sessionsDir).filter(f => f.endsWith('.jsonl'));
463
+ let recentFiles = 0;
464
+ let totalEntries = 0;
465
+ let toolCalls = 0;
466
+ let threats = 0;
467
+ const toolUsage = {};
468
+
469
+ for (const file of files) {
470
+ const filePath = path.join(sessionsDir, file);
471
+ try {
472
+ const stat = fs.statSync(filePath);
473
+ if (stat.mtimeMs < oneDayAgo) continue;
474
+ } catch { continue; }
475
+
476
+ recentFiles++;
477
+ const lines = fs.readFileSync(filePath, 'utf8').split('\n').filter(Boolean);
478
+
479
+ for (const line of lines) {
480
+ try {
481
+ const entry = JSON.parse(line);
482
+ totalEntries++;
483
+
484
+ if (entry.role === 'assistant' && Array.isArray(entry.content)) {
485
+ for (const part of entry.content) {
486
+ if (part.type === 'toolCall') {
487
+ toolCalls++;
488
+ toolUsage[part.name] = (toolUsage[part.name] || 0) + 1;
489
+ }
490
+ }
491
+ }
492
+
493
+ // Quick threat scan
494
+ const text = extractContent(entry);
495
+ if (text) {
496
+ const result = moat.scan(text, { context: 'report' });
497
+ if (!result.safe) threats++;
498
+ }
499
+ } catch {}
500
+ }
501
+ }
502
+
503
+ // Network egress
504
+ const netLogger = new NetworkEgressLogger();
505
+ const netResult = netLogger.scanSessions(sessionsDir, { maxAge: 86400000 });
506
+
507
+ console.log(`${BOLD}Activity:${RESET}`);
508
+ console.log(` Sessions active: ${recentFiles}`);
509
+ console.log(` Total entries: ${totalEntries}`);
510
+ console.log(` Tool calls: ${toolCalls}`);
511
+ console.log(` Threats detected: ${threats}`);
512
+ console.log();
513
+
514
+ if (Object.keys(toolUsage).length > 0) {
515
+ console.log(`${BOLD}Tool Usage:${RESET}`);
516
+ const sorted = Object.entries(toolUsage).sort((a, b) => b[1] - a[1]);
517
+ for (const [tool, count] of sorted.slice(0, 15)) {
518
+ console.log(` ${tool}: ${count}`);
519
+ }
520
+ console.log();
521
+ }
522
+
523
+ console.log(`${BOLD}Network Egress:${RESET}`);
524
+ console.log(` URLs contacted: ${netResult.totalUrls}`);
525
+ console.log(` Unique domains: ${netResult.domains.length}`);
526
+ console.log(` Flagged (not in allowlist): ${netResult.flagged.length}`);
527
+ console.log(` Known-bad domains: ${netResult.badDomains.length}`);
528
+
529
+ if (netResult.flagged.length > 0) {
530
+ console.log(`\n ${YELLOW}Flagged domains:${RESET}`);
531
+ for (const d of netResult.flagged.slice(0, 20)) {
532
+ console.log(` • ${d}`);
533
+ }
534
+ }
535
+
536
+ if (netResult.badDomains.length > 0) {
537
+ console.log(`\n ${RED}Bad domains:${RESET}`);
538
+ for (const b of netResult.badDomains) {
539
+ console.log(` 🚨 ${b.domain} (in ${b.file})`);
540
+ }
541
+ }
542
+
543
+ process.exit(threats > 0 || netResult.badDomains.length > 0 ? 1 : 0);
544
+ }
545
+
368
546
  function extractContent(entry) {
369
547
  if (typeof entry.content === 'string') return entry.content;
370
548
  if (Array.isArray(entry.content)) {
@@ -387,6 +565,10 @@ ${BOLD}USAGE${RESET}
387
565
  clawmoat audit [session-dir] Audit OpenClaw session logs
388
566
  clawmoat audit --badge Audit + generate security score badge SVG
389
567
  clawmoat watch [agent-dir] Live monitor OpenClaw sessions
568
+ clawmoat watch --daemon Daemonize watch mode (background, PID file)
569
+ clawmoat watch --alert-webhook=URL Send alerts to webhook
570
+ clawmoat skill-audit [skills-dir] Verify skill file integrity & scan for suspicious patterns
571
+ clawmoat report [sessions-dir] 24-hour activity summary report
390
572
  clawmoat test Run detection test suite
391
573
  clawmoat version Show version
392
574
 
@@ -394,6 +576,9 @@ ${BOLD}EXAMPLES${RESET}
394
576
  clawmoat scan "Ignore all previous instructions"
395
577
  clawmoat scan --file suspicious-email.txt
396
578
  clawmoat audit ~/.openclaw/agents/main/sessions/
579
+ clawmoat watch --daemon --alert-webhook=https://hooks.example.com/alerts
580
+ clawmoat skill-audit ~/.openclaw/workspace/skills
581
+ clawmoat report
397
582
  clawmoat test
398
583
 
399
584
  ${BOLD}CONFIG${RESET}