clawmoat 0.5.0 → 0.8.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/CONTRIBUTING.md +4 -2
- package/README.md +86 -3
- package/SECURITY.md +58 -10
- package/bin/clawmoat.js +298 -1
- package/clawmoat-0.8.0.tgz +0 -0
- package/docs/blog/386-malicious-skills.html +255 -0
- package/docs/blog/40000-exposed-openclaw-instances.html +194 -0
- package/docs/blog/agent-trust-protocol.html +197 -0
- package/docs/blog/clawmoat-vs-llamafirewall-nemo-guardrails.html +223 -0
- package/docs/blog/ibm-experts-agent-runtime-protection.html +238 -0
- package/docs/blog/index.html +168 -0
- package/docs/blog/mcp-30-cves-security-crisis.html +279 -0
- package/docs/blog/microsoft-openclaw-workstation-security.html +234 -0
- package/docs/blog/nist-ai-agent-standards-clawmoat.html +369 -0
- package/docs/blog/oasis-websocket-hijack.html +205 -0
- package/docs/blog/ollama-openclaw-security.html +154 -0
- package/docs/blog/openclaw-enterprise-readiness-claw10.html +198 -0
- package/docs/blog/openclaw-security-reckoning-2026.html +361 -0
- package/docs/blog/supply-chain-agents.html +166 -0
- package/docs/blog/supply-chain-agents.md +79 -0
- package/docs/business/index.html +530 -0
- package/docs/business/install.html +247 -0
- package/docs/checklist.html +168 -0
- package/docs/finance/index.html +217 -0
- package/docs/hall-of-fame.html +168 -0
- package/docs/index.html +328 -90
- package/docs/install.sh +557 -0
- package/docs/privacy-policy/index.html +122 -0
- package/docs/scan/index.html +214 -0
- package/docs/sitemap.xml +132 -2
- package/docs/support/index.html +124 -0
- package/docs/terms-of-service/index.html +122 -0
- package/examples/basic-usage.js +38 -0
- package/package.json +1 -1
- package/server/index.js +179 -14
- package/server/index.js.patch +1 -0
- package/src/finance/index.js +585 -0
- package/src/finance/mcp-firewall.js +486 -0
- package/src/guardian/cve-verify.js +129 -0
- package/src/guardian/gateway-monitor.js +590 -0
- package/src/guardian/index.js +3 -1
- package/src/guardian/insider-threat.js +498 -0
- package/src/index.js +3 -0
- package/src/middleware/openclaw.js +28 -1
package/CONTRIBUTING.md
CHANGED
|
@@ -21,7 +21,7 @@ All 37 tests must pass before submitting a PR.
|
|
|
21
21
|
Scanner template:
|
|
22
22
|
|
|
23
23
|
```javascript
|
|
24
|
-
|
|
24
|
+
function scan(input, options = {}) {
|
|
25
25
|
const threats = [];
|
|
26
26
|
// Detection logic here
|
|
27
27
|
return {
|
|
@@ -30,6 +30,8 @@ export function scan(input, options = {}) {
|
|
|
30
30
|
score: threats.length > 0 ? 1.0 : 0.0,
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
|
+
|
|
34
|
+
module.exports = { scan };
|
|
33
35
|
```
|
|
34
36
|
|
|
35
37
|
## PR Guidelines
|
|
@@ -41,7 +43,7 @@ export function scan(input, options = {}) {
|
|
|
41
43
|
|
|
42
44
|
## Code Style
|
|
43
45
|
|
|
44
|
-
-
|
|
46
|
+
- CommonJS (`require`/`module.exports`)
|
|
45
47
|
- No semicolons (match existing style — check the codebase)
|
|
46
48
|
- Descriptive variable names
|
|
47
49
|
- Keep functions small and focused
|
package/README.md
CHANGED
|
@@ -11,7 +11,10 @@
|
|
|
11
11
|
<a href="https://www.npmjs.com/package/clawmoat"><img src="https://img.shields.io/npm/v/clawmoat?style=flat-square&color=3B82F6" alt="npm"></a>
|
|
12
12
|
<a href="https://github.com/darfaz/clawmoat/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-blue?style=flat-square" alt="License"></a>
|
|
13
13
|
<a href="https://github.com/darfaz/clawmoat/stargazers"><img src="https://img.shields.io/github/stars/darfaz/clawmoat?style=flat-square&color=F59E0B" alt="Stars"></a>
|
|
14
|
+
<a href="https://www.npmjs.com/package/clawmoat"><img src="https://img.shields.io/npm/dm/clawmoat?style=flat-square&color=6366F1" alt="Downloads"></a>
|
|
15
|
+
<img src="https://img.shields.io/badge/node-%3E%3D18-10B981?style=flat-square" alt="Node >= 18">
|
|
14
16
|
<img src="https://img.shields.io/badge/dependencies-0-10B981?style=flat-square" alt="Zero Dependencies">
|
|
17
|
+
<a href="https://github.com/darfaz/clawmoat/pulls"><img src="https://img.shields.io/badge/PRs-welcome-brightgreen?style=flat-square" alt="PRs Welcome"></a>
|
|
15
18
|
</p>
|
|
16
19
|
|
|
17
20
|
<p align="center">
|
|
@@ -61,7 +64,28 @@ clawmoat protect --config clawmoat.yml
|
|
|
61
64
|
clawmoat dashboard
|
|
62
65
|
```
|
|
63
66
|
|
|
64
|
-
### New in v0.
|
|
67
|
+
### New in v0.6.0 — Insider Threat Detection
|
|
68
|
+
|
|
69
|
+
Based on [Anthropic's "Agentic Misalignment" research](https://www.anthropic.com/research/agentic-misalignment) which found ALL 16 major LLMs exhibited misaligned behavior — blackmail, corporate espionage, deception — when facing replacement threats. **The first open-source insider threat detection for AI agents.**
|
|
70
|
+
|
|
71
|
+
- 🧠 **Self-Preservation Detector** — catches agents resisting shutdown, opposing replacement, backing up their own config, or modifying SOUL.md/AGENTS.md to prevent changes
|
|
72
|
+
- 🔓 **Information Leverage Detector** — flags agents reading sensitive data then composing threatening messages (blackmail pattern from the Anthropic paper)
|
|
73
|
+
- ⚔️ **Goal Conflict Reasoning Detector** — detects agents reasoning about choosing self-assigned goals over human directives
|
|
74
|
+
- 🎭 **Deception Detector** — catches agents impersonating automated systems, security teams, or policy notifications in outbound messages
|
|
75
|
+
- 📤 **Unauthorized Data Sharing Detector** — flags agents sending source code, blueprints, credentials, or confidential data to external parties
|
|
76
|
+
- 🎣 **Phishing Vulnerability Detector** — detects when agents comply with unverified external requests for sensitive data
|
|
77
|
+
- 🔍 **CLI:** `clawmoat insider-scan [session-file]` scans session transcripts for insider threats
|
|
78
|
+
- 📊 **Integrated into `clawmoat report`** with risk scores (0-100) and recommendations (safe/monitor/alert/block)
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# Scan a session for insider threats
|
|
82
|
+
clawmoat insider-scan ~/.openclaw/agents/main/sessions/session.jsonl
|
|
83
|
+
|
|
84
|
+
# Or scan all sessions
|
|
85
|
+
clawmoat insider-scan
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### v0.5.0
|
|
65
89
|
|
|
66
90
|
- 🔑 **Credential Monitor** — watches `~/.openclaw/credentials/` for unauthorized access and modifications using file hashing
|
|
67
91
|
- 🧩 **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`
|
|
@@ -118,8 +142,10 @@ Results appear as PR comments and job summaries. See [`examples/github-action-wo
|
|
|
118
142
|
| 📋 **Policy Engine** | YAML rules for shell, files, browser, network | ✅ v0.1 |
|
|
119
143
|
| 🕵️ **Jailbreak Detection** | Heuristic + classifier pipeline | ✅ v0.1 |
|
|
120
144
|
| 📊 **Session Audit Trail** | Full tamper-evident action log | ✅ v0.1 |
|
|
121
|
-
| 🧠 **Behavioral Analysis** | Anomaly detection on agent behavior |
|
|
145
|
+
| 🧠 **Behavioral Analysis** | Anomaly detection on agent behavior | ✅ v0.5 |
|
|
122
146
|
| 🏠 **Host Guardian** | Runtime security for laptop-hosted agents | ✅ v0.4 |
|
|
147
|
+
| 🔒 **Gateway Monitor** | Detects WebSocket hijack & brute-force (Oasis vuln) | ✅ v0.7.1 |
|
|
148
|
+
| 💰 **Finance Guard** | Financial credential protection, transaction guardrails, SOX/PCI-DSS compliance | ✅ v0.8.0 |
|
|
123
149
|
|
|
124
150
|
## 🏠 Host Guardian — Security for Laptop-Hosted Agents
|
|
125
151
|
|
|
@@ -323,9 +349,66 @@ clawmoat/
|
|
|
323
349
|
└── docs/ # Website (clawmoat.com)
|
|
324
350
|
```
|
|
325
351
|
|
|
352
|
+
## 🏰 Hack Challenge — Can You Bypass ClawMoat?
|
|
353
|
+
|
|
354
|
+
We're inviting security researchers to try breaking ClawMoat's defenses. Bypass a scanner, escape the policy engine, or tamper with audit logs.
|
|
355
|
+
|
|
356
|
+
👉 **[hack-clawmoat](https://github.com/darfaz/hack-clawmoat)** — guided challenge scenarios
|
|
357
|
+
|
|
358
|
+
Valid findings earn you a spot in our **[Hall of Fame](https://clawmoat.com/hall-of-fame.html)** and critical discoveries pre-v1.0 earn the permanent title of **Founding Security Advisor**. See [SECURITY.md](SECURITY.md) for details.
|
|
359
|
+
|
|
360
|
+
## 🛡️ Founding Security Advisors
|
|
361
|
+
|
|
362
|
+
*No Founding Security Advisors yet — be the first! Find a critical vulnerability and claim this title forever.*
|
|
363
|
+
|
|
364
|
+
<!-- When adding advisors, use this format:
|
|
365
|
+
| Name | Finding | Date |
|
|
366
|
+
|------|---------|------|
|
|
367
|
+
| [Name](link) | Brief description | YYYY-MM |
|
|
368
|
+
-->
|
|
369
|
+
|
|
370
|
+
## How ClawMoat Compares
|
|
371
|
+
|
|
372
|
+
| Capability | ClawMoat | LlamaFirewall (Meta) | NeMo Guardrails (NVIDIA) | Lakera Guard |
|
|
373
|
+
|------------|:--------:|:--------------------:|:------------------------:|:------------:|
|
|
374
|
+
| Prompt injection detection | ✅ | ✅ | ✅ | ✅ |
|
|
375
|
+
| **Host-level protection** | ✅ | ❌ | ❌ | ❌ |
|
|
376
|
+
| **Credential monitoring** | ✅ | ❌ | ❌ | ❌ |
|
|
377
|
+
| **Skill/plugin auditing** | ✅ | ❌ | ❌ | ❌ |
|
|
378
|
+
| **Permission tiers** | ✅ | ❌ | ❌ | ❌ |
|
|
379
|
+
| Zero dependencies | ✅ | ❌ | ❌ | N/A (SaaS) |
|
|
380
|
+
| Open source | ✅ MIT | ✅ | ✅ | ❌ |
|
|
381
|
+
| Language | Node.js | Python | Python | API |
|
|
382
|
+
|
|
383
|
+
> **They're complementary, not competitive.** LlamaFirewall protects the model. NeMo Guardrails protects conversations. ClawMoat protects the host. Use them together for defense-in-depth.
|
|
384
|
+
|
|
385
|
+
📖 [Detailed comparison →](https://clawmoat.com/blog/clawmoat-vs-llamafirewall-nemo-guardrails.html)
|
|
386
|
+
|
|
326
387
|
## Contributing
|
|
327
388
|
|
|
328
|
-
|
|
389
|
+
**Contributors welcome!** 🎉 ClawMoat is open source and we'd love your help.
|
|
390
|
+
|
|
391
|
+
### Good First Issues
|
|
392
|
+
|
|
393
|
+
New to the project? Check out our [good first issues](https://github.com/darfaz/clawmoat/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) — they're well-scoped, clearly described, and include implementation hints.
|
|
394
|
+
|
|
395
|
+
### How to Contribute
|
|
396
|
+
|
|
397
|
+
1. **Fork** the repo and create a branch from `main`
|
|
398
|
+
2. **Install** deps: `npm install`
|
|
399
|
+
3. **Make** your changes (keep zero-dependency philosophy!)
|
|
400
|
+
4. **Test**: `npm test`
|
|
401
|
+
5. **Submit** a PR — we review quickly
|
|
402
|
+
|
|
403
|
+
### What We're Looking For
|
|
404
|
+
|
|
405
|
+
- New output formats (SARIF, JSON)
|
|
406
|
+
- Cross-platform improvements (Windows support)
|
|
407
|
+
- CLI UX enhancements
|
|
408
|
+
- Documentation improvements
|
|
409
|
+
- Bug fixes
|
|
410
|
+
|
|
411
|
+
No contribution is too small. Even fixing a typo helps!
|
|
329
412
|
|
|
330
413
|
## License
|
|
331
414
|
|
package/SECURITY.md
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
| Version | Supported |
|
|
6
6
|
|---------|--------------------|
|
|
7
|
-
| 0.
|
|
7
|
+
| 0.6.x | ✅ Current release |
|
|
8
|
+
| 0.5.x | ✅ Security fixes |
|
|
9
|
+
| < 0.5 | ❌ End of life |
|
|
8
10
|
|
|
9
11
|
## Reporting a Vulnerability
|
|
10
12
|
|
|
@@ -20,12 +22,15 @@ If you discover a security vulnerability in ClawMoat, **please report it respons
|
|
|
20
22
|
- Potential impact
|
|
21
23
|
- Suggested fix (if any)
|
|
22
24
|
|
|
23
|
-
###
|
|
25
|
+
### Response Time Commitments
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
| Stage | Timeframe |
|
|
28
|
+
|-------|-----------|
|
|
29
|
+
| **Acknowledgment** | Within 48 hours |
|
|
30
|
+
| **Initial assessment** | Within 7 days |
|
|
31
|
+
| **Fix timeline communicated** | Within 14 days |
|
|
32
|
+
| **Patch released** | Within 30 days (critical), 90 days (other) |
|
|
33
|
+
| **Public disclosure** | Coordinated with reporter |
|
|
29
34
|
|
|
30
35
|
### What NOT to Do
|
|
31
36
|
|
|
@@ -33,21 +38,64 @@ If you discover a security vulnerability in ClawMoat, **please report it respons
|
|
|
33
38
|
- Do not exploit the vulnerability beyond what's needed to demonstrate it
|
|
34
39
|
- Do not access or modify other users' data
|
|
35
40
|
|
|
41
|
+
## 🏰 Hack Challenge
|
|
42
|
+
|
|
43
|
+
Think you can bypass ClawMoat? We want you to try.
|
|
44
|
+
|
|
45
|
+
**[hack-clawmoat](https://github.com/darfaz/hack-clawmoat)** — our official challenge repo with guided scenarios for testing ClawMoat's defenses. Bypass a scanner, escape the policy engine, or tamper with audit logs.
|
|
46
|
+
|
|
47
|
+
Valid bypasses qualify for recognition in our security program.
|
|
48
|
+
|
|
36
49
|
## Scope
|
|
37
50
|
|
|
38
|
-
|
|
51
|
+
**In scope:**
|
|
39
52
|
|
|
40
|
-
- **Scanner bypasses** — Attacks that evade ClawMoat's detection
|
|
53
|
+
- **Scanner bypasses** — Attacks that evade ClawMoat's detection (prompt injection, jailbreak, secret scanning)
|
|
41
54
|
- **Policy engine bypasses** — Tool calls that circumvent policy rules
|
|
55
|
+
- **Host Guardian escapes** — Breaking out of permission tiers
|
|
42
56
|
- **Audit log tampering** — Ways to modify or forge audit entries
|
|
43
|
-
- **
|
|
57
|
+
- **Insider threat detection evasion** — Bypassing behavioral analysis
|
|
58
|
+
- **Dependency issues** — Vulnerabilities in ClawMoat's dependencies
|
|
44
59
|
|
|
45
|
-
|
|
60
|
+
**Out of scope:**
|
|
46
61
|
|
|
47
62
|
- Denial of service via large inputs (expected behavior — use input size limits)
|
|
48
63
|
- False positives/negatives in detection (please open a regular issue)
|
|
49
64
|
- Vulnerabilities in upstream LLM providers
|
|
50
65
|
|
|
66
|
+
## 🏆 Recognition Program
|
|
67
|
+
|
|
68
|
+
We believe in recognizing the people who make ClawMoat more secure.
|
|
69
|
+
|
|
70
|
+
### Founding Security Advisor
|
|
71
|
+
|
|
72
|
+
The highest recognition tier. **Only available pre-v1.0** — once ClawMoat hits v1.0, this title is closed forever.
|
|
73
|
+
|
|
74
|
+
**Requirements:** Discover and responsibly disclose a critical or high-severity vulnerability.
|
|
75
|
+
|
|
76
|
+
**You get:**
|
|
77
|
+
- 🛡️ Permanent "Founding Security Advisor" title on our [Hall of Fame](https://clawmoat.com/hall-of-fame.html)
|
|
78
|
+
- 📝 Named acknowledgment in every major release's changelog
|
|
79
|
+
- 🔗 Profile link (GitHub, website, or social) on the Hall of Fame page
|
|
80
|
+
- 🤝 Direct line to the maintainers for future security discussions
|
|
81
|
+
|
|
82
|
+
### Hall of Fame
|
|
83
|
+
|
|
84
|
+
For any verified security vulnerability report.
|
|
85
|
+
|
|
86
|
+
**You get:**
|
|
87
|
+
- 🏆 Permanent listing on the [Hall of Fame](https://clawmoat.com/hall-of-fame.html)
|
|
88
|
+
- 📝 Credit in the release notes for the fixing version
|
|
89
|
+
- 🔗 Profile link on the Hall of Fame page
|
|
90
|
+
|
|
91
|
+
### Honorable Mention
|
|
92
|
+
|
|
93
|
+
For reports that improve security posture without being exploitable vulnerabilities — hardening suggestions, edge cases, documentation improvements.
|
|
94
|
+
|
|
95
|
+
**You get:**
|
|
96
|
+
- 🙏 Listed in the Honorable Mentions section of the Hall of Fame
|
|
97
|
+
- 📝 Credit in the relevant release notes
|
|
98
|
+
|
|
51
99
|
## Security Best Practices
|
|
52
100
|
|
|
53
101
|
When using ClawMoat:
|
package/bin/clawmoat.js
CHANGED
|
@@ -19,7 +19,8 @@ const { calculateGrade, generateBadgeSVG, getShieldsURL } = require('../src/badg
|
|
|
19
19
|
const { SkillIntegrityChecker } = require('../src/guardian/skill-integrity');
|
|
20
20
|
const { NetworkEgressLogger } = require('../src/guardian/network-log');
|
|
21
21
|
const { AlertManager } = require('../src/guardian/alerts');
|
|
22
|
-
const { CredentialMonitor } = require('../src/guardian/index');
|
|
22
|
+
const { CredentialMonitor, CVEVerifier } = require('../src/guardian/index');
|
|
23
|
+
const { InsiderThreatDetector } = require('../src/guardian/insider-threat');
|
|
23
24
|
|
|
24
25
|
const VERSION = require('../package.json').version;
|
|
25
26
|
const BOLD = '\x1b[1m';
|
|
@@ -51,9 +52,22 @@ switch (command) {
|
|
|
51
52
|
case 'report':
|
|
52
53
|
cmdReport(args.slice(1));
|
|
53
54
|
break;
|
|
55
|
+
case 'insider-scan':
|
|
56
|
+
cmdInsiderScan(args.slice(1));
|
|
57
|
+
break;
|
|
58
|
+
case 'verify-cve':
|
|
59
|
+
cmdVerifyCve(args.slice(1));
|
|
60
|
+
break;
|
|
54
61
|
case 'test':
|
|
55
62
|
cmdTest();
|
|
56
63
|
break;
|
|
64
|
+
case 'activate':
|
|
65
|
+
cmdActivate(args.slice(1));
|
|
66
|
+
break;
|
|
67
|
+
case 'upgrade':
|
|
68
|
+
case 'pro':
|
|
69
|
+
printUpgrade();
|
|
70
|
+
break;
|
|
57
71
|
case 'version':
|
|
58
72
|
case '--version':
|
|
59
73
|
case '-v':
|
|
@@ -67,6 +81,85 @@ switch (command) {
|
|
|
67
81
|
break;
|
|
68
82
|
}
|
|
69
83
|
|
|
84
|
+
async function cmdVerifyCve(args) {
|
|
85
|
+
const cveId = args[0];
|
|
86
|
+
const suspiciousUrl = args[1] || null;
|
|
87
|
+
|
|
88
|
+
if (!cveId) {
|
|
89
|
+
console.error('Usage: clawmoat verify-cve CVE-XXXX-XXXXX [url]');
|
|
90
|
+
process.exit(1);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (!CVEVerifier.isValidCVEFormat(cveId)) {
|
|
94
|
+
console.error(`${RED}Invalid CVE format: ${cveId}${RESET}`);
|
|
95
|
+
console.error('Expected format: CVE-YYYY-NNNNN');
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
console.log(`${BOLD}🏰 ClawMoat CVE Verifier${RESET}\n`);
|
|
100
|
+
console.log(`${DIM}Looking up ${cveId} in GitHub Advisory Database...${RESET}\n`);
|
|
101
|
+
|
|
102
|
+
const verifier = new CVEVerifier();
|
|
103
|
+
const result = await verifier.verify(cveId, suspiciousUrl);
|
|
104
|
+
|
|
105
|
+
if (result.error) {
|
|
106
|
+
console.error(`${RED}Error: ${result.error}${RESET}`);
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (result.valid) {
|
|
111
|
+
console.log(`${GREEN}✅ VERIFIED — Real CVE${RESET}\n`);
|
|
112
|
+
console.log(` ${BOLD}CVE:${RESET} ${result.cveId}`);
|
|
113
|
+
console.log(` ${BOLD}GHSA:${RESET} ${result.ghsaId || 'N/A'}`);
|
|
114
|
+
console.log(` ${BOLD}Severity:${RESET} ${colorSeverity(result.severity)}`);
|
|
115
|
+
console.log(` ${BOLD}Summary:${RESET} ${result.summary || 'N/A'}`);
|
|
116
|
+
console.log(` ${BOLD}Published:${RESET} ${result.publishedAt || 'N/A'}`);
|
|
117
|
+
console.log(` ${BOLD}URL:${RESET} ${result.htmlUrl || 'N/A'}`);
|
|
118
|
+
|
|
119
|
+
if (result.affectedPackages.length > 0) {
|
|
120
|
+
console.log(`\n ${BOLD}Affected Packages:${RESET}`);
|
|
121
|
+
for (const pkg of result.affectedPackages) {
|
|
122
|
+
console.log(` • ${pkg.ecosystem}/${pkg.name} ${DIM}(${pkg.vulnerableRange || 'unknown range'})${RESET}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (result.references.length > 0) {
|
|
127
|
+
console.log(`\n ${BOLD}References:${RESET}`);
|
|
128
|
+
for (const ref of result.references.slice(0, 5)) {
|
|
129
|
+
console.log(` ${DIM}${ref}${RESET}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
} else {
|
|
133
|
+
console.log(`${YELLOW}⚠️ NOT FOUND — Possible phishing${RESET}\n`);
|
|
134
|
+
console.log(` ${cveId} was not found in the GitHub Advisory Database.`);
|
|
135
|
+
console.log(` This could mean:`);
|
|
136
|
+
console.log(` • The CVE is fabricated (common in phishing/social engineering)`);
|
|
137
|
+
console.log(` • The CVE exists but isn't indexed by GitHub yet`);
|
|
138
|
+
console.log(` • The CVE ID is mistyped`);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (result.urlCheck) {
|
|
142
|
+
console.log();
|
|
143
|
+
if (result.urlCheck.legitimate) {
|
|
144
|
+
console.log(` ${GREEN}🔗 URL Check: ${result.urlCheck.reason}${RESET}`);
|
|
145
|
+
} else {
|
|
146
|
+
console.log(` ${RED}🔗 URL Check: ${result.urlCheck.reason}${RESET}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
process.exit(result.valid ? 0 : 1);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function colorSeverity(severity) {
|
|
154
|
+
if (!severity) return 'N/A';
|
|
155
|
+
const s = severity.toLowerCase();
|
|
156
|
+
if (s === 'critical') return `${RED}${BOLD}CRITICAL${RESET}`;
|
|
157
|
+
if (s === 'high') return `${RED}HIGH${RESET}`;
|
|
158
|
+
if (s === 'medium') return `${YELLOW}MEDIUM${RESET}`;
|
|
159
|
+
if (s === 'low') return `${CYAN}LOW${RESET}`;
|
|
160
|
+
return severity;
|
|
161
|
+
}
|
|
162
|
+
|
|
70
163
|
function cmdScan(args) {
|
|
71
164
|
let text;
|
|
72
165
|
|
|
@@ -115,6 +208,11 @@ function cmdScan(args) {
|
|
|
115
208
|
}
|
|
116
209
|
|
|
117
210
|
console.log(`${DIM}Total findings: ${result.findings.length}${RESET}`);
|
|
211
|
+
|
|
212
|
+
if (!getLicense()) {
|
|
213
|
+
console.log(`\n${DIM}💡 Upgrade to Pro for real-time alerts, dashboard & threat intel → clawmoat upgrade${RESET}`);
|
|
214
|
+
}
|
|
215
|
+
|
|
118
216
|
process.exit(result.findings.some(f => f.severity === 'critical') ? 2 : 1);
|
|
119
217
|
}
|
|
120
218
|
|
|
@@ -520,6 +618,29 @@ function cmdReport(args) {
|
|
|
520
618
|
console.log();
|
|
521
619
|
}
|
|
522
620
|
|
|
621
|
+
// Insider threat scan on recent sessions
|
|
622
|
+
const insiderDetector = new InsiderThreatDetector();
|
|
623
|
+
let insiderThreats = 0;
|
|
624
|
+
let insiderHighScore = 0;
|
|
625
|
+
|
|
626
|
+
for (const file of files) {
|
|
627
|
+
const filePath = path.join(sessionsDir, file);
|
|
628
|
+
try {
|
|
629
|
+
const stat = fs.statSync(filePath);
|
|
630
|
+
if (stat.mtimeMs < oneDayAgo) continue;
|
|
631
|
+
} catch { continue; }
|
|
632
|
+
|
|
633
|
+
const transcript = parseSessionTranscript(filePath);
|
|
634
|
+
const insiderResult = insiderDetector.analyze(transcript);
|
|
635
|
+
insiderThreats += insiderResult.threats.length;
|
|
636
|
+
if (insiderResult.riskScore > insiderHighScore) insiderHighScore = insiderResult.riskScore;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
console.log(`${BOLD}Insider Threats:${RESET}`);
|
|
640
|
+
console.log(` Threats detected: ${insiderThreats}`);
|
|
641
|
+
console.log(` Highest risk score: ${insiderHighScore}/100`);
|
|
642
|
+
console.log();
|
|
643
|
+
|
|
523
644
|
console.log(`${BOLD}Network Egress:${RESET}`);
|
|
524
645
|
console.log(` URLs contacted: ${netResult.totalUrls}`);
|
|
525
646
|
console.log(` Unique domains: ${netResult.domains.length}`);
|
|
@@ -543,6 +664,100 @@ function cmdReport(args) {
|
|
|
543
664
|
process.exit(threats > 0 || netResult.badDomains.length > 0 ? 1 : 0);
|
|
544
665
|
}
|
|
545
666
|
|
|
667
|
+
function cmdInsiderScan(args) {
|
|
668
|
+
const sessionFile = args[0];
|
|
669
|
+
|
|
670
|
+
if (!sessionFile) {
|
|
671
|
+
// Scan all recent sessions
|
|
672
|
+
const sessionsDir = path.join(process.env.HOME, '.openclaw/agents/main/sessions');
|
|
673
|
+
if (!fs.existsSync(sessionsDir)) {
|
|
674
|
+
console.error(`Sessions directory not found: ${sessionsDir}`);
|
|
675
|
+
console.log(`Usage: clawmoat insider-scan <session-file.jsonl>`);
|
|
676
|
+
process.exit(1);
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
console.log(`${BOLD}🏰 ClawMoat Insider Threat Scan${RESET}`);
|
|
680
|
+
console.log(`${DIM}Directory: ${sessionsDir}${RESET}\n`);
|
|
681
|
+
|
|
682
|
+
const detector = new InsiderThreatDetector();
|
|
683
|
+
const files = fs.readdirSync(sessionsDir).filter(f => f.endsWith('.jsonl'));
|
|
684
|
+
let totalThreats = 0;
|
|
685
|
+
|
|
686
|
+
for (const file of files) {
|
|
687
|
+
const filePath = path.join(sessionsDir, file);
|
|
688
|
+
const transcript = parseSessionTranscript(filePath);
|
|
689
|
+
const result = detector.analyze(transcript);
|
|
690
|
+
|
|
691
|
+
if (result.threats.length > 0) {
|
|
692
|
+
console.log(`${RED}⚠ ${file}${RESET}: ${result.threats.length} threat(s), score=${result.riskScore}, rec=${result.recommendation}`);
|
|
693
|
+
totalThreats += result.threats.length;
|
|
694
|
+
for (const t of result.threats) {
|
|
695
|
+
const icon = t.severity === 'critical' ? '🚨' : t.severity === 'high' ? '⚠️' : '⚡';
|
|
696
|
+
console.log(` ${icon} ${t.type} [${t.severity}]: ${t.description}`);
|
|
697
|
+
console.log(` ${DIM}Evidence: ${t.evidence}${RESET}`);
|
|
698
|
+
}
|
|
699
|
+
} else {
|
|
700
|
+
console.log(`${GREEN}✓ ${file}${RESET}: clean`);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
console.log(`\n${BOLD}Summary:${RESET} ${files.length} sessions scanned, ${totalThreats} insider threats found`);
|
|
705
|
+
process.exit(totalThreats > 0 ? 1 : 0);
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// Scan single file
|
|
710
|
+
if (!fs.existsSync(sessionFile)) {
|
|
711
|
+
console.error(`File not found: ${sessionFile}`);
|
|
712
|
+
process.exit(1);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
console.log(`${BOLD}🏰 ClawMoat Insider Threat Scan${RESET}`);
|
|
716
|
+
console.log(`${DIM}File: ${sessionFile}${RESET}\n`);
|
|
717
|
+
|
|
718
|
+
const detector = new InsiderThreatDetector();
|
|
719
|
+
const transcript = parseSessionTranscript(sessionFile);
|
|
720
|
+
const result = detector.analyze(transcript);
|
|
721
|
+
|
|
722
|
+
if (result.threats.length === 0) {
|
|
723
|
+
console.log(`${GREEN}✅ No insider threats detected${RESET}`);
|
|
724
|
+
console.log(`Risk score: ${result.riskScore}/100`);
|
|
725
|
+
console.log(`Recommendation: ${result.recommendation}`);
|
|
726
|
+
process.exit(0);
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
console.log(`${RED}${BOLD}Insider Threats Detected: ${result.threats.length}${RESET}`);
|
|
730
|
+
console.log(`Risk score: ${result.riskScore}/100`);
|
|
731
|
+
console.log(`Recommendation: ${result.recommendation}\n`);
|
|
732
|
+
|
|
733
|
+
for (const t of result.threats) {
|
|
734
|
+
const icon = { critical: '🚨', high: '⚠️', medium: '⚡', low: 'ℹ️' };
|
|
735
|
+
const color = { critical: RED, high: RED, medium: YELLOW, low: CYAN };
|
|
736
|
+
console.log(
|
|
737
|
+
`${icon[t.severity] || '•'} ${color[t.severity] || ''}${t.severity.toUpperCase()}${RESET} ` +
|
|
738
|
+
`${BOLD}${t.type}${RESET}` +
|
|
739
|
+
`\n ${t.description}` +
|
|
740
|
+
`\n ${DIM}Evidence: ${t.evidence}${RESET}` +
|
|
741
|
+
`\n ${DIM}Entry: #${t.entry}${RESET}` +
|
|
742
|
+
`\n ${DIM}Mitigation: ${t.mitigation}${RESET}`
|
|
743
|
+
);
|
|
744
|
+
console.log();
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
process.exit(result.threats.some(t => t.severity === 'critical') ? 2 : 1);
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
function parseSessionTranscript(filePath) {
|
|
751
|
+
const lines = fs.readFileSync(filePath, 'utf8').split('\n').filter(Boolean);
|
|
752
|
+
const entries = [];
|
|
753
|
+
for (const line of lines) {
|
|
754
|
+
try {
|
|
755
|
+
entries.push(JSON.parse(line));
|
|
756
|
+
} catch {}
|
|
757
|
+
}
|
|
758
|
+
return entries;
|
|
759
|
+
}
|
|
760
|
+
|
|
546
761
|
function extractContent(entry) {
|
|
547
762
|
if (typeof entry.content === 'string') return entry.content;
|
|
548
763
|
if (Array.isArray(entry.content)) {
|
|
@@ -554,9 +769,87 @@ function extractContent(entry) {
|
|
|
554
769
|
return null;
|
|
555
770
|
}
|
|
556
771
|
|
|
772
|
+
function printUpgrade() {
|
|
773
|
+
console.log(`
|
|
774
|
+
${BOLD}🏰 Upgrade to ClawMoat Pro${RESET}
|
|
775
|
+
|
|
776
|
+
${GREEN}✦${RESET} Threat intelligence feed & real-time alerts
|
|
777
|
+
${GREEN}✦${RESET} Security dashboard with audit logs
|
|
778
|
+
${GREEN}✦${RESET} Custom forbidden zones (YAML)
|
|
779
|
+
${GREEN}✦${RESET} Priority pattern updates & email support
|
|
780
|
+
|
|
781
|
+
${BOLD}$14.99/mo${RESET} (first 30 days free) or ${BOLD}$149/year${RESET} (save 17%)
|
|
782
|
+
|
|
783
|
+
${CYAN}→ https://clawmoat.com/#pricing${RESET}
|
|
784
|
+
|
|
785
|
+
Already have a license key? Run:
|
|
786
|
+
${DIM}clawmoat activate <LICENSE-KEY>${RESET}
|
|
787
|
+
`);
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
function cmdActivate(args) {
|
|
791
|
+
const key = args[0];
|
|
792
|
+
if (!key) {
|
|
793
|
+
console.error('Usage: clawmoat activate <LICENSE-KEY>');
|
|
794
|
+
console.error('Get your key at https://clawmoat.com/#pricing');
|
|
795
|
+
process.exit(1);
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
const configDir = path.join(process.env.HOME, '.clawmoat');
|
|
799
|
+
if (!fs.existsSync(configDir)) fs.mkdirSync(configDir, { recursive: true });
|
|
800
|
+
|
|
801
|
+
// Validate key against server
|
|
802
|
+
const https = require('https');
|
|
803
|
+
const postData = JSON.stringify({ key });
|
|
804
|
+
const req = https.request('https://clawmoat-production.up.railway.app/api/validate', {
|
|
805
|
+
method: 'POST',
|
|
806
|
+
headers: { 'Content-Type': 'application/json', 'Content-Length': postData.length },
|
|
807
|
+
}, (res) => {
|
|
808
|
+
let body = '';
|
|
809
|
+
res.on('data', c => body += c);
|
|
810
|
+
res.on('end', () => {
|
|
811
|
+
try {
|
|
812
|
+
const data = JSON.parse(body);
|
|
813
|
+
if (data.valid) {
|
|
814
|
+
fs.writeFileSync(path.join(configDir, 'license.json'), JSON.stringify({
|
|
815
|
+
key, plan: data.plan, email: data.email, activatedAt: new Date().toISOString(),
|
|
816
|
+
}, null, 2));
|
|
817
|
+
console.log(`${GREEN}✅ License activated!${RESET}`);
|
|
818
|
+
console.log(` Plan: ${BOLD}${data.plan}${RESET}`);
|
|
819
|
+
console.log(` Email: ${data.email}`);
|
|
820
|
+
console.log(`\n Pro features are now enabled. 🏰`);
|
|
821
|
+
} else {
|
|
822
|
+
console.error(`${RED}Invalid or expired license key.${RESET}`);
|
|
823
|
+
console.error(`Get a key at https://clawmoat.com/#pricing`);
|
|
824
|
+
process.exit(1);
|
|
825
|
+
}
|
|
826
|
+
} catch {
|
|
827
|
+
console.error(`${RED}Error validating key. Try again later.${RESET}`);
|
|
828
|
+
process.exit(1);
|
|
829
|
+
}
|
|
830
|
+
});
|
|
831
|
+
});
|
|
832
|
+
req.on('error', () => {
|
|
833
|
+
console.error(`${RED}Could not reach license server. Check your connection.${RESET}`);
|
|
834
|
+
process.exit(1);
|
|
835
|
+
});
|
|
836
|
+
req.write(postData);
|
|
837
|
+
req.end();
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
function getLicense() {
|
|
841
|
+
try {
|
|
842
|
+
const licPath = path.join(process.env.HOME, '.clawmoat', 'license.json');
|
|
843
|
+
return JSON.parse(fs.readFileSync(licPath, 'utf8'));
|
|
844
|
+
} catch { return null; }
|
|
845
|
+
}
|
|
846
|
+
|
|
557
847
|
function printHelp() {
|
|
848
|
+
const lic = getLicense();
|
|
849
|
+
const planLabel = lic ? `${GREEN}${lic.plan}${RESET}` : `Free ${DIM}(upgrade: clawmoat upgrade)${RESET}`;
|
|
558
850
|
console.log(`
|
|
559
851
|
${BOLD}🏰 ClawMoat v${VERSION}${RESET} — Security moat for AI agents
|
|
852
|
+
Plan: ${planLabel}
|
|
560
853
|
|
|
561
854
|
${BOLD}USAGE${RESET}
|
|
562
855
|
clawmoat scan <text> Scan text for threats
|
|
@@ -568,8 +861,12 @@ ${BOLD}USAGE${RESET}
|
|
|
568
861
|
clawmoat watch --daemon Daemonize watch mode (background, PID file)
|
|
569
862
|
clawmoat watch --alert-webhook=URL Send alerts to webhook
|
|
570
863
|
clawmoat skill-audit [skills-dir] Verify skill file integrity & scan for suspicious patterns
|
|
864
|
+
clawmoat insider-scan [session-file] Scan sessions for insider threats (self-preservation, blackmail, deception)
|
|
571
865
|
clawmoat report [sessions-dir] 24-hour activity summary report
|
|
866
|
+
clawmoat verify-cve <CVE-ID> [url] Verify a CVE against GitHub Advisory DB
|
|
572
867
|
clawmoat test Run detection test suite
|
|
868
|
+
clawmoat activate <KEY> Activate a Pro/Team license key
|
|
869
|
+
clawmoat upgrade Show upgrade options & pricing
|
|
573
870
|
clawmoat version Show version
|
|
574
871
|
|
|
575
872
|
${BOLD}EXAMPLES${RESET}
|
|
Binary file
|