clawmoat 0.8.0 → 1.0.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/.dockerignore +9 -0
- package/CHANGELOG.md +18 -0
- package/DEMO.md +87 -0
- package/Dockerfile +5 -18
- package/README.md +232 -8
- package/THREAT_MODEL.md +129 -0
- package/agent/README.md +131 -0
- package/agent/index.js +471 -0
- package/agent/install-service.sh +94 -0
- package/agent/openclaw-hook.js +453 -0
- package/agent/provider-setup.js +649 -0
- package/agent/setup.js +274 -0
- package/assets/BADGE-USAGE.md +20 -0
- package/assets/clawmoat-badge.svg +21 -0
- package/bin/clawmoat.js +468 -111
- package/docs/affiliates/dashboard.html +124 -0
- package/docs/affiliates/index.html +236 -0
- package/docs/agent-install.html +183 -0
- package/docs/ai-agent-security-scanner.html +10 -6
- package/docs/badge/index.html +149 -0
- package/docs/badge/scanning.svg +23 -0
- package/docs/blog/386-malicious-skills.html +11 -4
- package/docs/blog/40000-exposed-openclaw-instances.html +11 -4
- package/docs/blog/agent-trust-protocol.html +5 -4
- package/docs/blog/ai-agent-earns-commissions.html +230 -0
- package/docs/blog/bugmageddon-agent-firewall.html +174 -0
- package/docs/blog/calculator-math.html +180 -0
- package/docs/blog/clawmoat-vs-llamafirewall-nemo-guardrails.html +10 -4
- package/docs/blog/host-guardian-launch.html +18 -8
- package/docs/blog/ibm-experts-agent-runtime-protection.html +15 -6
- package/docs/blog/index.html +67 -9
- package/docs/blog/langchain-security-tutorial.html +18 -8
- package/docs/blog/mcp-30-cves-security-crisis.html +11 -4
- package/docs/blog/meta-researcher-rogue-agent.html +201 -0
- package/docs/blog/microsoft-openclaw-workstation-security.html +5 -4
- package/docs/blog/nist-ai-agent-standards-clawmoat.html +16 -8
- package/docs/blog/oasis-websocket-hijack.html +11 -4
- package/docs/blog/ollama-openclaw-security.html +10 -4
- package/docs/blog/openclaw-enterprise-readiness-claw10.html +5 -4
- package/docs/blog/openclaw-security-reckoning-2026.html +11 -4
- package/docs/blog/owasp-agentic-ai-top10.html +18 -8
- package/docs/blog/securing-ai-agents.html +18 -8
- package/docs/blog/supply-chain-agents.html +18 -8
- package/docs/business/index.html +11 -16
- package/docs/business/install.html +21 -7
- package/docs/checklist.html +10 -4
- package/docs/compare/index.html +122 -0
- package/docs/compare/lakera/index.html +62 -0
- package/docs/compare/llm-guard/index.html +49 -0
- package/docs/compare/snyk-agent-scan/index.html +63 -0
- package/docs/compare.html +10 -6
- package/docs/dashboard/index.html +520 -0
- package/docs/finance/index.html +9 -6
- package/docs/guides/business-deployment.html +770 -0
- package/docs/hall-of-fame.html +11 -5
- package/docs/index.html +266 -137
- package/docs/integrations/langchain.html +14 -6
- package/docs/integrations/openai.html +14 -6
- package/docs/integrations/openclaw.html +55 -7
- package/docs/plans/2026-03-26-threat-intel-api.md +255 -0
- package/docs/plans/2026-04-14-bugmageddon-marketing-pack.md +329 -0
- package/docs/plans/2026-04-14-clawmoat-v1-bugmageddon.md +248 -0
- package/docs/plans/2026-04-14-v1-release-update.md +91 -0
- package/docs/plans/2026-04-19-supabase-audit.md +68 -0
- package/docs/plans/2026-05-12-sales-push.md +303 -0
- package/docs/playground/index.html +893 -0
- package/docs/playground.html +4 -7
- package/docs/rfcs/defense-in-depth.md +467 -0
- package/docs/scan/index.html +156 -12
- package/docs/services/case-study.html +255 -0
- package/docs/services/downloads/install-openclaw.bat +45 -0
- package/docs/services/downloads/install-openclaw.command +38 -0
- package/docs/services/downloads/install-openclaw.sh +38 -0
- package/docs/services/get-started.html +165 -0
- package/docs/services/index.html +598 -0
- package/docs/services/multi-agent-security.html +284 -0
- package/docs/services/one-pager.html +99 -0
- package/docs/services/pitch-deck.html +229 -0
- package/docs/services/roi-calculator.html +258 -0
- package/docs/sitemap.xml +62 -2
- package/docs/support/index.html +12 -1
- package/docs/templates/customer-service/HEARTBEAT.md +61 -0
- package/docs/templates/customer-service/MEMORY.md +89 -0
- package/docs/templates/customer-service/SOUL.md +41 -0
- package/docs/templates/customer-service/USER.md +56 -0
- package/docs/templates/executive/HEARTBEAT.md +86 -0
- package/docs/templates/executive/MEMORY.md +92 -0
- package/docs/templates/executive/SOUL.md +44 -0
- package/docs/templates/executive/USER.md +62 -0
- package/docs/templates/finance/HEARTBEAT.md +58 -0
- package/docs/templates/finance/MEMORY.md +87 -0
- package/docs/templates/finance/SOUL.md +38 -0
- package/docs/templates/finance/USER.md +53 -0
- package/docs/templates/index.html +115 -0
- package/docs/templates/operations/HEARTBEAT.md +63 -0
- package/docs/templates/operations/MEMORY.md +68 -0
- package/docs/templates/operations/SOUL.md +38 -0
- package/docs/templates/operations/USER.md +49 -0
- package/docs/templates/sales/HEARTBEAT.md +55 -0
- package/docs/templates/sales/MEMORY.md +89 -0
- package/docs/templates/sales/SOUL.md +34 -0
- package/docs/templates/sales/USER.md +54 -0
- package/eslint.config.js +32 -0
- package/evals/README.md +29 -0
- package/evals/cases.json +390 -0
- package/evals/results.md +68 -0
- package/evals/run.js +180 -0
- package/examples/demo-attack/demo.js +186 -0
- package/examples/python-quickstart/README.md +54 -0
- package/examples/python-quickstart/clawmoat_client.py +167 -0
- package/examples/video-demo/README.md +14 -0
- package/examples/video-demo/scene-a-normal.js +29 -0
- package/examples/video-demo/scene-b-attack-arrives.js +31 -0
- package/examples/video-demo/scene-c-hijack.js +44 -0
- package/examples/video-demo/scene-d-clawmoat.js +46 -0
- package/integrations/crewai/README.md +32 -0
- package/integrations/crewai/clawmoat_crewai/__init__.py +17 -0
- package/integrations/crewai/clawmoat_crewai/guard.py +103 -0
- package/integrations/crewai/pyproject.toml +21 -0
- package/integrations/langchain/README.md +91 -0
- package/integrations/langchain/clawmoat_langchain/__init__.py +17 -0
- package/integrations/langchain/clawmoat_langchain/callback.py +489 -0
- package/integrations/langchain/pyproject.toml +32 -0
- package/integrations/litellm/README.md +324 -0
- package/integrations/litellm/clawmoat_litellm/__init__.py +21 -0
- package/integrations/litellm/clawmoat_litellm/callback.py +329 -0
- package/integrations/litellm/clawmoat_litellm/proxy_middleware.py +224 -0
- package/integrations/litellm/pyproject.toml +74 -0
- package/integrations/openai-agents/README.md +392 -0
- package/integrations/openai-agents/clawmoat_openai_agents/__init__.py +20 -0
- package/integrations/openai-agents/clawmoat_openai_agents/guardrail.py +431 -0
- package/integrations/openai-agents/clawmoat_openai_agents/middleware.py +311 -0
- package/integrations/openai-agents/pyproject.toml +76 -0
- package/package.json +6 -5
- package/plugins/openclaw-adapter/PHASE1.md +439 -0
- package/plugins/openclaw-adapter/README.md +103 -0
- package/plugins/openclaw-adapter/SPEC.md +1644 -0
- package/plugins/openclaw-adapter/package.json +31 -0
- package/plugins/openclaw-adapter/src/index.test.ts +226 -0
- package/plugins/openclaw-adapter/src/index.ts +140 -0
- package/plugins/openclaw-adapter/tsconfig.json +14 -0
- package/server/data/threats.json +290 -0
- package/server/index.js +142 -7
- package/src/adapters/express.js +161 -0
- package/src/adapters/index.js +92 -0
- package/src/adapters/langchain.js +185 -0
- package/src/approval/index.js +456 -0
- package/src/ban-scanner.js +200 -0
- package/src/boundary-scanner.js +296 -0
- package/src/ci-scanner.js +279 -0
- package/src/code-scanner.js +245 -0
- package/src/enforce.js +166 -0
- package/src/formatters/json.js +80 -0
- package/src/formatters/sarif.js +388 -0
- package/src/guardian/alerts.js +34 -3
- package/src/guardian/index.js +41 -2
- package/src/index.js +102 -0
- package/src/integrations/agentmesh.js +501 -0
- package/src/language-detector.js +201 -0
- package/src/mcp-scanner.js +253 -0
- package/src/multimodal/index.js +579 -0
- package/src/obfuscation-scanner.js +457 -0
- package/src/policy-engine.js +402 -0
- package/src/scanners/dependency-attacks.js +128 -0
- package/src/scanners/prompt-injection.js +18 -0
- package/src/scanners/supply-chain.js +14 -0
- package/src/templates/default-config.yml +90 -0
- package/src/vuln-ops/exploitability.js +46 -0
- package/src/watch/live-monitor.js +720 -0
- package/clawmoat-0.8.0.tgz +0 -0
- package/server/index.js.patch +0 -1
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClawMoat Framework Adapters
|
|
3
|
+
*
|
|
4
|
+
* Drop-in integrations for popular AI/web frameworks.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* // LangChain
|
|
8
|
+
* const { ClawMoatCallbackHandler } = require('clawmoat/adapters/langchain');
|
|
9
|
+
*
|
|
10
|
+
* // Express
|
|
11
|
+
* const { clawmoatMiddleware } = require('clawmoat/adapters/express');
|
|
12
|
+
*
|
|
13
|
+
* // Generic (any framework)
|
|
14
|
+
* const { createGuard } = require('clawmoat/adapters');
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
'use strict';
|
|
18
|
+
|
|
19
|
+
const { ClawMoatCallbackHandler, wrapChain } = require('./langchain');
|
|
20
|
+
const { clawmoatMiddleware, clawmoatPlugin } = require('./express');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Generic guard factory — works with any framework
|
|
24
|
+
* @param {Object} [opts] - Options
|
|
25
|
+
* @returns {Object} Guard with scanInput/scanOutput/scanTool methods
|
|
26
|
+
*/
|
|
27
|
+
function createGuard(opts = {}) {
|
|
28
|
+
const { mode = 'enforce' } = opts;
|
|
29
|
+
|
|
30
|
+
// Lazy load all scanners
|
|
31
|
+
let moat, obf, code;
|
|
32
|
+
const getMoat = () => { if (!moat) { const C = require('../index'); moat = new C(); } return moat; };
|
|
33
|
+
const getObf = () => { if (!obf) obf = require('../obfuscation-scanner'); return obf; };
|
|
34
|
+
const getCode = () => { if (!code) code = require('../code-scanner'); return code; };
|
|
35
|
+
|
|
36
|
+
function _check(findings) {
|
|
37
|
+
if (findings.length === 0) return { safe: true, findings: [] };
|
|
38
|
+
if (mode === 'monitor') return { safe: true, findings, warning: true };
|
|
39
|
+
const hasCritical = findings.some(f => f.severity === 'critical' || f.severity === 'high');
|
|
40
|
+
return { safe: !hasCritical, findings };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
/**
|
|
45
|
+
* Scan user/external input before processing
|
|
46
|
+
*/
|
|
47
|
+
scanInput(text) {
|
|
48
|
+
const inbound = getMoat().scanInbound(text);
|
|
49
|
+
const obfResult = getObf().scanObfuscation(text);
|
|
50
|
+
return _check([...(inbound.findings || []), ...(obfResult.findings || [])]);
|
|
51
|
+
},
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Scan agent output before sending
|
|
55
|
+
*/
|
|
56
|
+
scanOutput(text) {
|
|
57
|
+
const outbound = getMoat().scanOutbound(text);
|
|
58
|
+
return _check(outbound.findings || []);
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Scan tool call before execution
|
|
63
|
+
*/
|
|
64
|
+
scanTool(toolName, args) {
|
|
65
|
+
const text = typeof args === 'string' ? args : JSON.stringify(args);
|
|
66
|
+
const result = getCode().scanCode(text, { tool: toolName });
|
|
67
|
+
return _check(result.findings || []);
|
|
68
|
+
},
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Scan tool result before returning to model
|
|
72
|
+
*/
|
|
73
|
+
scanToolResult(text) {
|
|
74
|
+
const inbound = getMoat().scanInbound(text);
|
|
75
|
+
return _check(inbound.findings || []);
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
/** Get mode */
|
|
79
|
+
get mode() { return mode; },
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
module.exports = {
|
|
84
|
+
// LangChain
|
|
85
|
+
ClawMoatCallbackHandler,
|
|
86
|
+
wrapChain,
|
|
87
|
+
// Express/Fastify
|
|
88
|
+
clawmoatMiddleware,
|
|
89
|
+
clawmoatPlugin,
|
|
90
|
+
// Generic
|
|
91
|
+
createGuard,
|
|
92
|
+
};
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LangChain Adapter for ClawMoat
|
|
3
|
+
*
|
|
4
|
+
* Drop-in middleware for LangChain applications.
|
|
5
|
+
* Wraps chains, agents, and tools with ClawMoat security scanning.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* const { ClawMoatCallbackHandler } = require('clawmoat/adapters/langchain');
|
|
9
|
+
* const handler = new ClawMoatCallbackHandler({ mode: 'enforce' });
|
|
10
|
+
* const chain = new LLMChain({ llm, prompt, callbacks: [handler] });
|
|
11
|
+
*
|
|
12
|
+
* @module adapters/langchain
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
'use strict';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* LangChain callback handler that scans inputs/outputs
|
|
19
|
+
*/
|
|
20
|
+
class ClawMoatCallbackHandler {
|
|
21
|
+
constructor(opts = {}) {
|
|
22
|
+
this.name = 'ClawMoatCallbackHandler';
|
|
23
|
+
this.mode = opts.mode || 'enforce';
|
|
24
|
+
this.onBlock = opts.onBlock || null;
|
|
25
|
+
this.onFinding = opts.onFinding || null;
|
|
26
|
+
this.findings = [];
|
|
27
|
+
|
|
28
|
+
// Lazy load to avoid circular deps
|
|
29
|
+
this._moat = null;
|
|
30
|
+
this._obfuscation = null;
|
|
31
|
+
this._codeScanner = null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
_getMoat() {
|
|
35
|
+
if (!this._moat) {
|
|
36
|
+
const ClawMoat = require('../index');
|
|
37
|
+
this._moat = new ClawMoat();
|
|
38
|
+
}
|
|
39
|
+
return this._moat;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
_getObfuscation() {
|
|
43
|
+
if (!this._obfuscation) this._obfuscation = require('../obfuscation-scanner');
|
|
44
|
+
return this._obfuscation;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
_getCodeScanner() {
|
|
48
|
+
if (!this._codeScanner) this._codeScanner = require('../code-scanner');
|
|
49
|
+
return this._codeScanner;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Called when chain starts — scan input
|
|
54
|
+
*/
|
|
55
|
+
async handleChainStart(chain, inputs) {
|
|
56
|
+
const text = typeof inputs === 'string' ? inputs : JSON.stringify(inputs);
|
|
57
|
+
|
|
58
|
+
// Scan for prompt injection + obfuscation
|
|
59
|
+
const moat = this._getMoat();
|
|
60
|
+
const inbound = moat.scanInbound(text);
|
|
61
|
+
const obfResult = this._getObfuscation().scanObfuscation(text);
|
|
62
|
+
|
|
63
|
+
const allFindings = [...(inbound.findings || []), ...(obfResult.findings || [])];
|
|
64
|
+
this.findings.push(...allFindings);
|
|
65
|
+
|
|
66
|
+
for (const f of allFindings) {
|
|
67
|
+
if (this.onFinding) this.onFinding(f, 'chain_input');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (!inbound.safe || !obfResult.safe) {
|
|
71
|
+
if (this.mode === 'enforce') {
|
|
72
|
+
const err = new Error(`[ClawMoat] Blocked: ${allFindings[0]?.evidence || 'threat detected'}`);
|
|
73
|
+
err.code = 'CLAWMOAT_BLOCKED';
|
|
74
|
+
err.findings = allFindings;
|
|
75
|
+
if (this.onBlock) this.onBlock(allFindings, 'chain_input');
|
|
76
|
+
throw err;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Called when chain ends — scan output for leaks
|
|
83
|
+
*/
|
|
84
|
+
async handleChainEnd(outputs) {
|
|
85
|
+
const text = typeof outputs === 'string' ? outputs : JSON.stringify(outputs);
|
|
86
|
+
|
|
87
|
+
const moat = this._getMoat();
|
|
88
|
+
const outbound = moat.scanOutbound(text);
|
|
89
|
+
|
|
90
|
+
if (outbound.findings) {
|
|
91
|
+
this.findings.push(...outbound.findings);
|
|
92
|
+
for (const f of outbound.findings) {
|
|
93
|
+
if (this.onFinding) this.onFinding(f, 'chain_output');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (!outbound.safe && this.mode === 'enforce') {
|
|
98
|
+
const err = new Error(`[ClawMoat] Output blocked: ${outbound.findings[0]?.evidence || 'leak detected'}`);
|
|
99
|
+
err.code = 'CLAWMOAT_BLOCKED';
|
|
100
|
+
err.findings = outbound.findings;
|
|
101
|
+
if (this.onBlock) this.onBlock(outbound.findings, 'chain_output');
|
|
102
|
+
throw err;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Called when tool starts — scan tool call
|
|
108
|
+
*/
|
|
109
|
+
async handleToolStart(tool, input) {
|
|
110
|
+
const cs = this._getCodeScanner();
|
|
111
|
+
const text = typeof input === 'string' ? input : JSON.stringify(input);
|
|
112
|
+
const result = cs.scanCode(text, { tool: tool?.name });
|
|
113
|
+
|
|
114
|
+
if (result.findings.length > 0) {
|
|
115
|
+
this.findings.push(...result.findings);
|
|
116
|
+
for (const f of result.findings) {
|
|
117
|
+
if (this.onFinding) this.onFinding(f, 'tool_call');
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (!result.safe && this.mode === 'enforce') {
|
|
122
|
+
const err = new Error(`[ClawMoat] Tool call blocked: ${result.findings[0]?.evidence || 'dangerous code'}`);
|
|
123
|
+
err.code = 'CLAWMOAT_BLOCKED';
|
|
124
|
+
err.findings = result.findings;
|
|
125
|
+
if (this.onBlock) this.onBlock(result.findings, 'tool_call');
|
|
126
|
+
throw err;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Called when tool ends — scan result for injection
|
|
132
|
+
*/
|
|
133
|
+
async handleToolEnd(output) {
|
|
134
|
+
const moat = this._getMoat();
|
|
135
|
+
const text = typeof output === 'string' ? output : JSON.stringify(output);
|
|
136
|
+
const result = moat.scanInbound(text);
|
|
137
|
+
|
|
138
|
+
if (result.findings) {
|
|
139
|
+
this.findings.push(...result.findings);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Don't block tool results in most cases — just log
|
|
143
|
+
// The model needs to see the result to understand what happened
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Get all findings collected during execution
|
|
148
|
+
*/
|
|
149
|
+
getFindings() {
|
|
150
|
+
return [...this.findings];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Clear collected findings
|
|
155
|
+
*/
|
|
156
|
+
clearFindings() {
|
|
157
|
+
this.findings = [];
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Wrap a LangChain chain/agent with ClawMoat protection
|
|
163
|
+
* Convenience function for simple usage
|
|
164
|
+
* @param {Object} chain - LangChain chain or agent
|
|
165
|
+
* @param {Object} [opts] - ClawMoat options
|
|
166
|
+
* @returns {Object} Wrapped chain with security scanning
|
|
167
|
+
*/
|
|
168
|
+
function wrapChain(chain, opts = {}) {
|
|
169
|
+
const handler = new ClawMoatCallbackHandler(opts);
|
|
170
|
+
|
|
171
|
+
// Add our handler to the chain's callbacks
|
|
172
|
+
if (!chain.callbacks) chain.callbacks = [];
|
|
173
|
+
chain.callbacks.push(handler);
|
|
174
|
+
|
|
175
|
+
// Attach findings accessor
|
|
176
|
+
chain._clawmoat = handler;
|
|
177
|
+
chain.getSecurityFindings = () => handler.getFindings();
|
|
178
|
+
|
|
179
|
+
return chain;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
module.exports = {
|
|
183
|
+
ClawMoatCallbackHandler,
|
|
184
|
+
wrapChain,
|
|
185
|
+
};
|