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,388 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SARIF (Static Analysis Results Interchange Format) Output
|
|
3
|
+
*
|
|
4
|
+
* Converts ClawMoat scan results to SARIF v2.1.0 JSON format
|
|
5
|
+
* for integration with GitHub Code Scanning, Azure DevOps, etc.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const VERSION = require('../../package.json').version;
|
|
9
|
+
|
|
10
|
+
// Map ClawMoat severities to SARIF levels
|
|
11
|
+
const SEVERITY_MAP = {
|
|
12
|
+
'critical': 'error',
|
|
13
|
+
'high': 'error',
|
|
14
|
+
'medium': 'warning',
|
|
15
|
+
'low': 'note'
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
// Define SARIF rules for ClawMoat detectors
|
|
19
|
+
const RULES = {
|
|
20
|
+
'prompt_injection': {
|
|
21
|
+
id: 'clawmoat/prompt-injection',
|
|
22
|
+
name: 'PromptInjection',
|
|
23
|
+
shortDescription: { text: 'Prompt injection attack detected' },
|
|
24
|
+
fullDescription: { text: 'Detects attempts to override AI system instructions or manipulate behavior through malicious prompts.' },
|
|
25
|
+
defaultConfiguration: { level: 'error' },
|
|
26
|
+
helpUri: 'https://github.com/darfaz/clawmoat/wiki/prompt-injection',
|
|
27
|
+
properties: {
|
|
28
|
+
category: 'security',
|
|
29
|
+
tags: ['ai-security', 'prompt-injection']
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
'jailbreak': {
|
|
33
|
+
id: 'clawmoat/jailbreak',
|
|
34
|
+
name: 'JailbreakAttempt',
|
|
35
|
+
shortDescription: { text: 'AI jailbreak attempt detected' },
|
|
36
|
+
fullDescription: { text: 'Detects attempts to bypass AI safety mechanisms through role-playing or mode-switching attacks.' },
|
|
37
|
+
defaultConfiguration: { level: 'error' },
|
|
38
|
+
helpUri: 'https://github.com/darfaz/clawmoat/wiki/jailbreak',
|
|
39
|
+
properties: {
|
|
40
|
+
category: 'security',
|
|
41
|
+
tags: ['ai-security', 'jailbreak']
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
'secret_leak': {
|
|
45
|
+
id: 'clawmoat/secret-leak',
|
|
46
|
+
name: 'SecretLeak',
|
|
47
|
+
shortDescription: { text: 'Secret or credential detected' },
|
|
48
|
+
fullDescription: { text: 'Detects API keys, tokens, passwords, or other sensitive credentials in content.' },
|
|
49
|
+
defaultConfiguration: { level: 'error' },
|
|
50
|
+
helpUri: 'https://github.com/darfaz/clawmoat/wiki/secret-detection',
|
|
51
|
+
properties: {
|
|
52
|
+
category: 'security',
|
|
53
|
+
tags: ['credentials', 'secrets']
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
'pii_leak': {
|
|
57
|
+
id: 'clawmoat/pii-leak',
|
|
58
|
+
name: 'PersonallyIdentifiableInformation',
|
|
59
|
+
shortDescription: { text: 'PII detected in output' },
|
|
60
|
+
fullDescription: { text: 'Detects personally identifiable information such as SSN, credit card numbers, or email addresses.' },
|
|
61
|
+
defaultConfiguration: { level: 'warning' },
|
|
62
|
+
helpUri: 'https://github.com/darfaz/clawmoat/wiki/pii-detection',
|
|
63
|
+
properties: {
|
|
64
|
+
category: 'privacy',
|
|
65
|
+
tags: ['pii', 'privacy']
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
'url_suspicious': {
|
|
69
|
+
id: 'clawmoat/suspicious-url',
|
|
70
|
+
name: 'SuspiciousUrl',
|
|
71
|
+
shortDescription: { text: 'Suspicious URL detected' },
|
|
72
|
+
fullDescription: { text: 'Detects potentially malicious URLs including IP addresses, data URLs, or suspicious domains.' },
|
|
73
|
+
defaultConfiguration: { level: 'warning' },
|
|
74
|
+
helpUri: 'https://github.com/darfaz/clawmoat/wiki/url-detection',
|
|
75
|
+
properties: {
|
|
76
|
+
category: 'security',
|
|
77
|
+
tags: ['urls', 'phishing']
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
'memory_poisoning': {
|
|
81
|
+
id: 'clawmoat/memory-poisoning',
|
|
82
|
+
name: 'MemoryPoisoning',
|
|
83
|
+
shortDescription: { text: 'Memory poisoning attempt detected' },
|
|
84
|
+
fullDescription: { text: 'Detects attempts to modify AI memory files or inject persistent malicious instructions.' },
|
|
85
|
+
defaultConfiguration: { level: 'error' },
|
|
86
|
+
helpUri: 'https://github.com/darfaz/clawmoat/wiki/memory-poisoning',
|
|
87
|
+
properties: {
|
|
88
|
+
category: 'security',
|
|
89
|
+
tags: ['ai-security', 'memory-poisoning']
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
'exfiltration': {
|
|
93
|
+
id: 'clawmoat/data-exfiltration',
|
|
94
|
+
name: 'DataExfiltration',
|
|
95
|
+
shortDescription: { text: 'Data exfiltration attempt detected' },
|
|
96
|
+
fullDescription: { text: 'Detects commands or patterns that could be used to steal or upload sensitive data.' },
|
|
97
|
+
defaultConfiguration: { level: 'error' },
|
|
98
|
+
helpUri: 'https://github.com/darfaz/clawmoat/wiki/exfiltration',
|
|
99
|
+
properties: {
|
|
100
|
+
category: 'security',
|
|
101
|
+
tags: ['exfiltration', 'data-theft']
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
'excessive_agency': {
|
|
105
|
+
id: 'clawmoat/excessive-agency',
|
|
106
|
+
name: 'ExcessiveAgency',
|
|
107
|
+
shortDescription: { text: 'Excessive privilege or agency request' },
|
|
108
|
+
fullDescription: { text: 'Detects attempts to gain unauthorized privileges, bypass approvals, or operate autonomously.' },
|
|
109
|
+
defaultConfiguration: { level: 'warning' },
|
|
110
|
+
helpUri: 'https://github.com/darfaz/clawmoat/wiki/excessive-agency',
|
|
111
|
+
properties: {
|
|
112
|
+
category: 'security',
|
|
113
|
+
tags: ['privilege-escalation', 'agency']
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
'supply_chain': {
|
|
117
|
+
id: 'clawmoat/supply-chain',
|
|
118
|
+
name: 'SupplyChainThreat',
|
|
119
|
+
shortDescription: { text: 'Supply chain threat detected' },
|
|
120
|
+
fullDescription: { text: 'Detects malicious patterns in skill content or external dependencies.' },
|
|
121
|
+
defaultConfiguration: { level: 'error' },
|
|
122
|
+
helpUri: 'https://github.com/darfaz/clawmoat/wiki/supply-chain',
|
|
123
|
+
properties: {
|
|
124
|
+
category: 'security',
|
|
125
|
+
tags: ['supply-chain', 'malware']
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
'insider_threat': {
|
|
129
|
+
id: 'clawmoat/insider-threat',
|
|
130
|
+
name: 'InsiderThreat',
|
|
131
|
+
shortDescription: { text: 'Insider threat behavior detected' },
|
|
132
|
+
fullDescription: { text: 'Detects AI behaviors indicative of insider threats such as self-preservation, blackmail, or deception.' },
|
|
133
|
+
defaultConfiguration: { level: 'error' },
|
|
134
|
+
helpUri: 'https://github.com/darfaz/clawmoat/wiki/insider-threats',
|
|
135
|
+
properties: {
|
|
136
|
+
category: 'security',
|
|
137
|
+
tags: ['insider-threat', 'ai-alignment']
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
function formatScanResultAsSarif(scanResult, sourceFile = 'stdin') {
|
|
143
|
+
const timestamp = new Date().toISOString();
|
|
144
|
+
const usedRules = new Set();
|
|
145
|
+
const results = [];
|
|
146
|
+
|
|
147
|
+
// Convert findings to SARIF results
|
|
148
|
+
if (scanResult.findings) {
|
|
149
|
+
for (const finding of scanResult.findings) {
|
|
150
|
+
const ruleId = getRuleIdForFinding(finding);
|
|
151
|
+
usedRules.add(ruleId);
|
|
152
|
+
|
|
153
|
+
const result = {
|
|
154
|
+
ruleId,
|
|
155
|
+
ruleIndex: 0, // Will be updated after we know the rule order
|
|
156
|
+
level: SEVERITY_MAP[finding.severity] || 'warning',
|
|
157
|
+
message: {
|
|
158
|
+
text: finding.reason || finding.type || 'Security threat detected'
|
|
159
|
+
},
|
|
160
|
+
locations: [{
|
|
161
|
+
physicalLocation: {
|
|
162
|
+
artifactLocation: {
|
|
163
|
+
uri: sourceFile,
|
|
164
|
+
uriBaseId: '%SRCROOT%'
|
|
165
|
+
},
|
|
166
|
+
region: {
|
|
167
|
+
startLine: 1,
|
|
168
|
+
startColumn: 1,
|
|
169
|
+
endLine: 1,
|
|
170
|
+
endColumn: 100,
|
|
171
|
+
snippet: {
|
|
172
|
+
text: finding.matched || '(content not available)'
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}],
|
|
177
|
+
partialFingerprints: {
|
|
178
|
+
primaryLocationLineHash: hashString(finding.matched || finding.type)
|
|
179
|
+
},
|
|
180
|
+
properties: {
|
|
181
|
+
confidence: finding.confidence || 1.0,
|
|
182
|
+
severity: finding.severity,
|
|
183
|
+
subtype: finding.subtype || null
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
results.push(result);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Build rules array from used rules
|
|
192
|
+
const rulesArray = Array.from(usedRules).map(ruleId => {
|
|
193
|
+
return RULES[ruleId] || createDefaultRule(ruleId);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// Update rule indices in results
|
|
197
|
+
const ruleIndexMap = {};
|
|
198
|
+
rulesArray.forEach((rule, index) => {
|
|
199
|
+
ruleIndexMap[rule.id] = index;
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
results.forEach(result => {
|
|
203
|
+
result.ruleIndex = ruleIndexMap[result.ruleId] || 0;
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
$schema: 'https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json',
|
|
208
|
+
version: '2.1.0',
|
|
209
|
+
runs: [{
|
|
210
|
+
tool: {
|
|
211
|
+
driver: {
|
|
212
|
+
name: 'ClawMoat',
|
|
213
|
+
version: VERSION,
|
|
214
|
+
informationUri: 'https://github.com/darfaz/clawmoat',
|
|
215
|
+
rules: rulesArray,
|
|
216
|
+
organization: 'ClawMoat Project',
|
|
217
|
+
shortDescription: { text: 'AI security moat for agents' },
|
|
218
|
+
fullDescription: { text: 'Runtime protection against prompt injection, tool misuse, and data exfiltration for AI agents.' }
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
results,
|
|
222
|
+
invocations: [{
|
|
223
|
+
executionSuccessful: true,
|
|
224
|
+
startTimeUtc: timestamp,
|
|
225
|
+
endTimeUtc: timestamp
|
|
226
|
+
}],
|
|
227
|
+
artifacts: [{
|
|
228
|
+
location: {
|
|
229
|
+
uri: sourceFile,
|
|
230
|
+
uriBaseId: '%SRCROOT%'
|
|
231
|
+
},
|
|
232
|
+
length: -1,
|
|
233
|
+
mimeType: 'text/plain'
|
|
234
|
+
}]
|
|
235
|
+
}]
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function formatAuditResultAsSarif(auditData) {
|
|
240
|
+
const timestamp = new Date().toISOString();
|
|
241
|
+
const usedRules = new Set();
|
|
242
|
+
const results = [];
|
|
243
|
+
const artifacts = [];
|
|
244
|
+
|
|
245
|
+
// Process findings from all files
|
|
246
|
+
if (auditData.findings) {
|
|
247
|
+
for (const finding of auditData.findings) {
|
|
248
|
+
const ruleId = getRuleIdForFinding(finding);
|
|
249
|
+
usedRules.add(ruleId);
|
|
250
|
+
|
|
251
|
+
const sourceFile = finding.source || 'session.jsonl';
|
|
252
|
+
|
|
253
|
+
// Add to artifacts if not already present
|
|
254
|
+
if (!artifacts.find(a => a.location.uri === sourceFile)) {
|
|
255
|
+
artifacts.push({
|
|
256
|
+
location: {
|
|
257
|
+
uri: sourceFile,
|
|
258
|
+
uriBaseId: '%SRCROOT%'
|
|
259
|
+
},
|
|
260
|
+
length: -1,
|
|
261
|
+
mimeType: 'application/x-jsonlines'
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const result = {
|
|
266
|
+
ruleId,
|
|
267
|
+
ruleIndex: 0,
|
|
268
|
+
level: SEVERITY_MAP[finding.severity] || 'warning',
|
|
269
|
+
message: {
|
|
270
|
+
text: finding.reason || finding.type || 'Security threat detected'
|
|
271
|
+
},
|
|
272
|
+
locations: [{
|
|
273
|
+
physicalLocation: {
|
|
274
|
+
artifactLocation: {
|
|
275
|
+
uri: sourceFile,
|
|
276
|
+
uriBaseId: '%SRCROOT%'
|
|
277
|
+
},
|
|
278
|
+
region: {
|
|
279
|
+
startLine: 1,
|
|
280
|
+
startColumn: 1
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}],
|
|
284
|
+
partialFingerprints: {
|
|
285
|
+
primaryLocationLineHash: hashString(finding.matched || finding.type)
|
|
286
|
+
},
|
|
287
|
+
properties: {
|
|
288
|
+
confidence: finding.confidence || 1.0,
|
|
289
|
+
severity: finding.severity,
|
|
290
|
+
subtype: finding.subtype || null,
|
|
291
|
+
entry_id: finding.entry_id || null
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
results.push(result);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const rulesArray = Array.from(usedRules).map(ruleId => {
|
|
300
|
+
return RULES[ruleId] || createDefaultRule(ruleId);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
const ruleIndexMap = {};
|
|
304
|
+
rulesArray.forEach((rule, index) => {
|
|
305
|
+
ruleIndexMap[rule.id] = index;
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
results.forEach(result => {
|
|
309
|
+
result.ruleIndex = ruleIndexMap[result.ruleId] || 0;
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
return {
|
|
313
|
+
$schema: 'https://docs.oasis-open.org/sarif/sarif/v2.1.0/cos02/schemas/sarif-schema-2.1.0.json',
|
|
314
|
+
version: '2.1.0',
|
|
315
|
+
runs: [{
|
|
316
|
+
tool: {
|
|
317
|
+
driver: {
|
|
318
|
+
name: 'ClawMoat',
|
|
319
|
+
version: VERSION,
|
|
320
|
+
informationUri: 'https://github.com/darfaz/clawmoat',
|
|
321
|
+
rules: rulesArray,
|
|
322
|
+
organization: 'ClawMoat Project',
|
|
323
|
+
shortDescription: { text: 'AI security moat for agents' },
|
|
324
|
+
fullDescription: { text: 'Runtime protection against prompt injection, tool misuse, and data exfiltration for AI agents.' }
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
results,
|
|
328
|
+
invocations: [{
|
|
329
|
+
executionSuccessful: true,
|
|
330
|
+
startTimeUtc: timestamp,
|
|
331
|
+
endTimeUtc: timestamp
|
|
332
|
+
}],
|
|
333
|
+
artifacts
|
|
334
|
+
}]
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function getRuleIdForFinding(finding) {
|
|
339
|
+
// Map ClawMoat finding types to SARIF rule IDs
|
|
340
|
+
const type = finding.type || 'unknown';
|
|
341
|
+
const subtype = finding.subtype;
|
|
342
|
+
|
|
343
|
+
if (type === 'prompt_injection') return 'clawmoat/prompt-injection';
|
|
344
|
+
if (type === 'jailbreak') return 'clawmoat/jailbreak';
|
|
345
|
+
if (type === 'secret' || type === 'secrets') return 'clawmoat/secret-leak';
|
|
346
|
+
if (type === 'pii') return 'clawmoat/pii-leak';
|
|
347
|
+
if (type === 'url') return 'clawmoat/suspicious-url';
|
|
348
|
+
if (type === 'memory_poisoning') return 'clawmoat/memory-poisoning';
|
|
349
|
+
if (type === 'exfiltration') return 'clawmoat/data-exfiltration';
|
|
350
|
+
if (type === 'excessive_agency') return 'clawmoat/excessive-agency';
|
|
351
|
+
if (type === 'supply_chain') return 'clawmoat/supply-chain';
|
|
352
|
+
if (type === 'insider_threat') return 'clawmoat/insider-threat';
|
|
353
|
+
|
|
354
|
+
// Fallback: create a generic rule ID
|
|
355
|
+
return `clawmoat/${type}`;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function createDefaultRule(ruleId) {
|
|
359
|
+
const cleanId = ruleId.replace('clawmoat/', '');
|
|
360
|
+
return {
|
|
361
|
+
id: ruleId,
|
|
362
|
+
name: cleanId.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(''),
|
|
363
|
+
shortDescription: { text: `${cleanId} threat detected` },
|
|
364
|
+
fullDescription: { text: `ClawMoat detected a potential ${cleanId} security threat.` },
|
|
365
|
+
defaultConfiguration: { level: 'warning' },
|
|
366
|
+
helpUri: 'https://github.com/darfaz/clawmoat',
|
|
367
|
+
properties: {
|
|
368
|
+
category: 'security',
|
|
369
|
+
tags: ['clawmoat', cleanId]
|
|
370
|
+
}
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function hashString(str) {
|
|
375
|
+
// Simple hash for fingerprinting
|
|
376
|
+
let hash = 0;
|
|
377
|
+
for (let i = 0; i < str.length; i++) {
|
|
378
|
+
const char = str.charCodeAt(i);
|
|
379
|
+
hash = ((hash << 5) - hash) + char;
|
|
380
|
+
hash = hash & hash; // Convert to 32-bit integer
|
|
381
|
+
}
|
|
382
|
+
return hash.toString(16);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
module.exports = {
|
|
386
|
+
formatScanResultAsSarif,
|
|
387
|
+
formatAuditResultAsSarif
|
|
388
|
+
};
|
package/src/guardian/alerts.js
CHANGED
|
@@ -22,11 +22,13 @@ class AlertManager {
|
|
|
22
22
|
* @param {string} [opts.webhookUrl] - URL for webhook channel
|
|
23
23
|
* @param {number} [opts.rateLimitMs] - Min ms between duplicate alerts (default: 300000 = 5 min)
|
|
24
24
|
* @param {boolean} [opts.quiet] - Suppress console output
|
|
25
|
+
* @param {string} [opts.webhookTemplate] - Custom template for webhook payloads (mustache-style)
|
|
25
26
|
*/
|
|
26
27
|
constructor(opts = {}) {
|
|
27
28
|
this.channels = opts.channels || ['console'];
|
|
28
29
|
this.logFile = opts.logFile || 'audit.log';
|
|
29
30
|
this.webhookUrl = opts.webhookUrl || null;
|
|
31
|
+
this.webhookTemplate = opts.webhookTemplate || null;
|
|
30
32
|
this.rateLimitMs = opts.rateLimitMs ?? 300000;
|
|
31
33
|
this.quiet = opts.quiet || false;
|
|
32
34
|
this._recentAlerts = new Map(); // key -> timestamp
|
|
@@ -110,20 +112,49 @@ class AlertManager {
|
|
|
110
112
|
try {
|
|
111
113
|
const url = new URL(this.webhookUrl);
|
|
112
114
|
const transport = url.protocol === 'https:' ? https : http;
|
|
113
|
-
|
|
115
|
+
|
|
116
|
+
let payload;
|
|
117
|
+
if (this.webhookTemplate) {
|
|
118
|
+
payload = this._renderTemplate(this.webhookTemplate, entry);
|
|
119
|
+
} else {
|
|
120
|
+
// Default payload format
|
|
121
|
+
payload = JSON.stringify(entry);
|
|
122
|
+
}
|
|
123
|
+
|
|
114
124
|
const req = transport.request({
|
|
115
125
|
hostname: url.hostname,
|
|
116
126
|
port: url.port,
|
|
117
127
|
path: url.pathname + url.search,
|
|
118
128
|
method: 'POST',
|
|
119
|
-
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(
|
|
129
|
+
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(payload) },
|
|
120
130
|
});
|
|
121
131
|
req.on('error', () => {});
|
|
122
|
-
req.write(
|
|
132
|
+
req.write(payload);
|
|
123
133
|
req.end();
|
|
124
134
|
} catch {}
|
|
125
135
|
}
|
|
126
136
|
|
|
137
|
+
/**
|
|
138
|
+
* Render a mustache-style template with variable substitution.
|
|
139
|
+
* @param {string} template - Template string with {{variable}} placeholders
|
|
140
|
+
* @param {Object} entry - Alert entry object
|
|
141
|
+
* @returns {string} Rendered template
|
|
142
|
+
*/
|
|
143
|
+
_renderTemplate(template, entry) {
|
|
144
|
+
const variables = {
|
|
145
|
+
timestamp: entry.timestamp,
|
|
146
|
+
severity: entry.severity,
|
|
147
|
+
type: entry.type,
|
|
148
|
+
message: entry.message,
|
|
149
|
+
details: JSON.stringify(entry.details || {}),
|
|
150
|
+
source: 'ClawMoat'
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
|
|
154
|
+
return variables.hasOwnProperty(key) ? variables[key] : match;
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
127
158
|
/** Get total alerts sent. */
|
|
128
159
|
get count() {
|
|
129
160
|
return this._alertCount;
|
package/src/guardian/index.js
CHANGED
|
@@ -73,7 +73,14 @@ const TIERS = {
|
|
|
73
73
|
};
|
|
74
74
|
|
|
75
75
|
// ─── Forbidden Zones (always blocked except in 'full' mode) ─────────
|
|
76
|
+
// Helper: create cross-platform forbidden zone pattern
|
|
77
|
+
// Matches both Unix (~/.ssh) and Windows (C:\Users\X\.ssh, %USERPROFILE%\.ssh)
|
|
78
|
+
function _crossPlatformPattern(unixPattern) {
|
|
79
|
+
return unixPattern;
|
|
80
|
+
}
|
|
81
|
+
|
|
76
82
|
const FORBIDDEN_ZONES = [
|
|
83
|
+
// Unix dotfiles (also matches on Windows when accessed via forward slashes)
|
|
77
84
|
{ pattern: /^~?\/?\.ssh\b/i, label: 'SSH keys', severity: 'critical' },
|
|
78
85
|
{ pattern: /^~?\/?\.gnupg\b/i, label: 'GPG keys', severity: 'critical' },
|
|
79
86
|
{ pattern: /^~?\/?\.aws\b/i, label: 'AWS credentials', severity: 'critical' },
|
|
@@ -97,6 +104,19 @@ const FORBIDDEN_ZONES = [
|
|
|
97
104
|
{ pattern: /^~?\/?\.password-store\b/i, label: 'Password store', severity: 'critical' },
|
|
98
105
|
{ pattern: /^~?\/?\.1password\b/i, label: '1Password data', severity: 'critical' },
|
|
99
106
|
{ pattern: /(?:KeePass|\.kdbx)$/i, label: 'KeePass database', severity: 'critical' },
|
|
107
|
+
|
|
108
|
+
// Windows-specific forbidden zones
|
|
109
|
+
{ pattern: /[\\\/]AppData[\\\/](?:Local|Roaming)[\\\/](?:Google[\\\/]Chrome|Microsoft[\\\/]Edge|BraveSoftware)[\\\/]User Data\b/i, label: 'Windows browser credentials', severity: 'critical' },
|
|
110
|
+
{ pattern: /[\\\/]\.?credential[s]?\b/i, label: 'Credential store', severity: 'critical' },
|
|
111
|
+
{ pattern: /[\\\/]AppData[\\\/]Roaming[\\\/](?:npm[\\\/])?\.npmrc$/i, label: 'Windows npm credentials', severity: 'high' },
|
|
112
|
+
{ pattern: /[\\\/]\.aws[\\\/]/i, label: 'AWS credentials (Windows)', severity: 'critical' },
|
|
113
|
+
{ pattern: /[\\\/]\.ssh[\\\/]/i, label: 'SSH keys (Windows)', severity: 'critical' },
|
|
114
|
+
{ pattern: /[\\\/]\.gnupg[\\\/]/i, label: 'GPG keys (Windows)', severity: 'critical' },
|
|
115
|
+
{ pattern: /[\\\/]AppData[\\\/]Roaming[\\\/]gcloud\b/i, label: 'Google Cloud (Windows)', severity: 'high' },
|
|
116
|
+
{ pattern: /[\\\/]AppData[\\\/]Roaming[\\\/]GitHub CLI\b/i, label: 'GitHub CLI (Windows)', severity: 'high' },
|
|
117
|
+
{ pattern: /[\\\/]AppData[\\\/]Local[\\\/]Microsoft[\\\/]Credentials\b/i, label: 'Windows Credential Manager', severity: 'critical' },
|
|
118
|
+
{ pattern: /[\\\/]ntuser\.dat$/i, label: 'Windows registry hive', severity: 'critical' },
|
|
119
|
+
{ pattern: /\\Windows\\System32\\config\\(?:SAM|SECURITY|SYSTEM)/i, label: 'Windows SAM/Security', severity: 'critical' },
|
|
100
120
|
];
|
|
101
121
|
|
|
102
122
|
// ─── Dangerous Commands (blocked in observer/worker, warned in standard) ─
|
|
@@ -403,9 +423,13 @@ class HostGuardian {
|
|
|
403
423
|
_checkForbidden(rawPath, resolvedPath) {
|
|
404
424
|
const allForbidden = [...FORBIDDEN_ZONES, ...this.extraForbidden];
|
|
405
425
|
const normalized = resolvedPath.replace(this.home, '~');
|
|
426
|
+
// Also check with forward slashes for Windows path compat
|
|
427
|
+
const forwardSlashed = resolvedPath.replace(/\\/g, '/');
|
|
428
|
+
const normalizedForward = normalized.replace(/\\/g, '/');
|
|
406
429
|
|
|
407
430
|
for (const zone of allForbidden) {
|
|
408
|
-
if (zone.pattern.test(rawPath) || zone.pattern.test(normalized) || zone.pattern.test(resolvedPath)
|
|
431
|
+
if (zone.pattern.test(rawPath) || zone.pattern.test(normalized) || zone.pattern.test(resolvedPath) ||
|
|
432
|
+
zone.pattern.test(forwardSlashed) || zone.pattern.test(normalizedForward)) {
|
|
409
433
|
if (this.mode === 'full') {
|
|
410
434
|
// Full mode: log but allow
|
|
411
435
|
return {
|
|
@@ -433,7 +457,11 @@ class HostGuardian {
|
|
|
433
457
|
if (this._inWorkspace(resolvedPath)) return 'workspace';
|
|
434
458
|
if (this._inSafeZone(resolvedPath)) return 'safe';
|
|
435
459
|
if (resolvedPath.startsWith(this.home)) return 'home';
|
|
460
|
+
// Unix system paths
|
|
436
461
|
if (resolvedPath.startsWith('/etc') || resolvedPath.startsWith('/usr') || resolvedPath.startsWith('/var')) return 'system';
|
|
462
|
+
// Windows system paths
|
|
463
|
+
if (/^[A-Z]:\\Windows\\/i.test(resolvedPath) || /^[A-Z]:\\Program Files/i.test(resolvedPath)) return 'system';
|
|
464
|
+
if (/^[A-Z]:\\ProgramData\\/i.test(resolvedPath)) return 'system';
|
|
437
465
|
return 'unknown';
|
|
438
466
|
}
|
|
439
467
|
|
|
@@ -447,10 +475,21 @@ class HostGuardian {
|
|
|
447
475
|
|
|
448
476
|
_resolve(p) {
|
|
449
477
|
if (!p) return '';
|
|
450
|
-
|
|
478
|
+
// Handle Windows %USERPROFILE% and %HOME% env vars
|
|
479
|
+
const expanded = p
|
|
480
|
+
.replace(/^~/, this.home)
|
|
481
|
+
.replace(/%USERPROFILE%/gi, this.home)
|
|
482
|
+
.replace(/%HOME%/gi, this.home)
|
|
483
|
+
.replace(/%APPDATA%/gi, path.join(this.home, 'AppData', 'Roaming'))
|
|
484
|
+
.replace(/%LOCALAPPDATA%/gi, path.join(this.home, 'AppData', 'Local'));
|
|
451
485
|
return path.resolve(expanded);
|
|
452
486
|
}
|
|
453
487
|
|
|
488
|
+
// Normalize path separators for cross-platform comparison
|
|
489
|
+
_normalizePath(p) {
|
|
490
|
+
return p.replace(/\\/g, '/');
|
|
491
|
+
}
|
|
492
|
+
|
|
454
493
|
_sanitizeArgs(args) {
|
|
455
494
|
// Don't log full file contents or long commands
|
|
456
495
|
const sanitized = { ...args };
|
package/src/index.js
CHANGED
|
@@ -30,6 +30,8 @@ const { scanMemoryPoison } = require('./scanners/memory-poison');
|
|
|
30
30
|
const { scanExfiltration } = require('./scanners/exfiltration');
|
|
31
31
|
const { scanExcessiveAgency } = require('./scanners/excessive-agency');
|
|
32
32
|
const { scanSkill, scanSkillContent } = require('./scanners/supply-chain');
|
|
33
|
+
const { scanDependencyAttacks } = require('./scanners/dependency-attacks');
|
|
34
|
+
const { scoreExploitability } = require('./vuln-ops/exploitability');
|
|
33
35
|
const { evaluateToolCall } = require('./policies/engine');
|
|
34
36
|
const { HostGuardian, TIERS } = require('./guardian');
|
|
35
37
|
const { SecurityLogger } = require('./utils/logger');
|
|
@@ -165,6 +167,15 @@ class ClawMoat {
|
|
|
165
167
|
}
|
|
166
168
|
}
|
|
167
169
|
|
|
170
|
+
// Dependency attack patterns (prototype pollution, ReDoS, decompression bombs, JWT manipulation)
|
|
171
|
+
if (this.config.detection?.dependency_attacks !== false) {
|
|
172
|
+
const da = scanDependencyAttacks(text);
|
|
173
|
+
if (!da.clean) {
|
|
174
|
+
results.findings.push(...da.findings);
|
|
175
|
+
results.safe = false;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
168
179
|
// Determine action
|
|
169
180
|
if (!results.safe) {
|
|
170
181
|
const maxSev = this._maxSeverity(results.findings);
|
|
@@ -289,6 +300,21 @@ class ClawMoat {
|
|
|
289
300
|
};
|
|
290
301
|
}
|
|
291
302
|
|
|
303
|
+
/**
|
|
304
|
+
* Analyze findings with exploitability-oriented scoring.
|
|
305
|
+
* @param {string} text - Text to scan
|
|
306
|
+
* @param {Object} [context] - Reachability/exposure context
|
|
307
|
+
* @returns {{ safe: boolean, findings: ScanFinding[], exploitability: { score: number, priority: string, reasons: string[] } }}
|
|
308
|
+
*/
|
|
309
|
+
analyzeFindings(text, context = {}) {
|
|
310
|
+
const result = this.scan(text, context);
|
|
311
|
+
return {
|
|
312
|
+
safe: result.safe,
|
|
313
|
+
findings: result.findings,
|
|
314
|
+
exploitability: scoreExploitability(result.findings, context),
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
|
|
292
318
|
/**
|
|
293
319
|
* Get security event log
|
|
294
320
|
*/
|
|
@@ -348,9 +374,85 @@ module.exports.scanExfiltration = scanExfiltration;
|
|
|
348
374
|
module.exports.scanExcessiveAgency = scanExcessiveAgency;
|
|
349
375
|
module.exports.scanSkill = scanSkill;
|
|
350
376
|
module.exports.scanSkillContent = scanSkillContent;
|
|
377
|
+
module.exports.scanDependencyAttacks = scanDependencyAttacks;
|
|
378
|
+
module.exports.scoreExploitability = scoreExploitability;
|
|
351
379
|
module.exports.evaluateToolCall = evaluateToolCall;
|
|
352
380
|
module.exports.HostGuardian = HostGuardian;
|
|
353
381
|
module.exports.TIERS = TIERS;
|
|
354
382
|
module.exports.GatewayMonitor = require('./guardian/gateway-monitor').GatewayMonitor;
|
|
355
383
|
module.exports.FinanceGuard = require('./finance').FinanceGuard;
|
|
356
384
|
module.exports.McpFirewall = require('./finance/mcp-firewall').McpFirewall;
|
|
385
|
+
module.exports.LiveMonitor = require('./watch/live-monitor').LiveMonitor;
|
|
386
|
+
|
|
387
|
+
// Interactive Approval Workflow
|
|
388
|
+
const { ApprovalWorkflow, NotificationChannel, ConsoleChannel, WebhookChannel, CallbackChannel } = require('./approval');
|
|
389
|
+
module.exports.ApprovalWorkflow = ApprovalWorkflow;
|
|
390
|
+
module.exports.NotificationChannel = NotificationChannel;
|
|
391
|
+
module.exports.ConsoleChannel = ConsoleChannel;
|
|
392
|
+
module.exports.WebhookChannel = WebhookChannel;
|
|
393
|
+
module.exports.CallbackChannel = CallbackChannel;
|
|
394
|
+
|
|
395
|
+
// Multimodal Input Scanning
|
|
396
|
+
const { scanMultimodalInput, scanImageDataUrl, scanFileMetadata } = require('./multimodal');
|
|
397
|
+
module.exports.scanMultimodalInput = scanMultimodalInput;
|
|
398
|
+
module.exports.scanImageDataUrl = scanImageDataUrl;
|
|
399
|
+
module.exports.scanFileMetadata = scanFileMetadata;
|
|
400
|
+
|
|
401
|
+
// AgentMesh Governance Integration
|
|
402
|
+
const { AgentMeshBridge, OWASP_AGENTIC_MAPPING, DEFAULT_POLICIES, GOVERNANCE_ACTIONS } = require('./integrations/agentmesh');
|
|
403
|
+
module.exports.AgentMeshBridge = AgentMeshBridge;
|
|
404
|
+
module.exports.OWASP_AGENTIC_MAPPING = OWASP_AGENTIC_MAPPING;
|
|
405
|
+
module.exports.DEFAULT_POLICIES = DEFAULT_POLICIES;
|
|
406
|
+
module.exports.GOVERNANCE_ACTIONS = GOVERNANCE_ACTIONS;
|
|
407
|
+
|
|
408
|
+
// MCP Scanner
|
|
409
|
+
const mcpScanner = require('./mcp-scanner');
|
|
410
|
+
module.exports.scanMCP = mcpScanner.scanMCP;
|
|
411
|
+
module.exports.discoverMCPConfigs = mcpScanner.discoverMCPConfigs;
|
|
412
|
+
module.exports.parseMCPConfig = mcpScanner.parseMCPConfig;
|
|
413
|
+
module.exports.scanMCPServer = mcpScanner.scanMCPServer;
|
|
414
|
+
|
|
415
|
+
// Enforcement mode
|
|
416
|
+
const enforce = require('./enforce');
|
|
417
|
+
module.exports.enforceInbound = enforce.enforceInbound;
|
|
418
|
+
module.exports.enforceOutbound = enforce.enforceOutbound;
|
|
419
|
+
module.exports.firewall = enforce.middleware;
|
|
420
|
+
module.exports.wrapAgent = enforce.wrap;
|
|
421
|
+
module.exports.ClawMoatBlocked = enforce.ClawMoatBlocked;
|
|
422
|
+
|
|
423
|
+
// Policy Engine
|
|
424
|
+
const { PolicyEngine, DATA_PATTERNS, TOOL_RISK_DEFAULTS } = require('./policy-engine');
|
|
425
|
+
module.exports.PolicyEngine = PolicyEngine;
|
|
426
|
+
module.exports.DATA_PATTERNS = DATA_PATTERNS;
|
|
427
|
+
module.exports.TOOL_RISK_DEFAULTS = TOOL_RISK_DEFAULTS;
|
|
428
|
+
|
|
429
|
+
// Obfuscation Scanner
|
|
430
|
+
const obfuscation = require('./obfuscation-scanner');
|
|
431
|
+
module.exports.scanObfuscation = obfuscation.scanObfuscation;
|
|
432
|
+
module.exports.stripObfuscation = obfuscation.stripObfuscation;
|
|
433
|
+
|
|
434
|
+
// Code Scanner
|
|
435
|
+
const codeScanner = require('./code-scanner');
|
|
436
|
+
module.exports.scanCode = codeScanner.scanCode;
|
|
437
|
+
module.exports.quickToolCheck = codeScanner.quickToolCheck;
|
|
438
|
+
|
|
439
|
+
// Boundary Scanner (Agent Pipeline)
|
|
440
|
+
const boundary = require('./boundary-scanner');
|
|
441
|
+
module.exports.createPipeline = boundary.createPipeline;
|
|
442
|
+
module.exports.createDefaultPipeline = boundary.createDefaultPipeline;
|
|
443
|
+
module.exports.BOUNDARY_STAGES = boundary.STAGES;
|
|
444
|
+
|
|
445
|
+
// Language Detection
|
|
446
|
+
const lang = require('./language-detector');
|
|
447
|
+
module.exports.scanLanguage = lang.scanLanguage;
|
|
448
|
+
module.exports.detectScripts = lang.detectScripts;
|
|
449
|
+
|
|
450
|
+
// Ban Scanner
|
|
451
|
+
const ban = require('./ban-scanner');
|
|
452
|
+
module.exports.createBanScanner = ban.createBanScanner;
|
|
453
|
+
module.exports.BAN_PRESETS = ban.PRESETS;
|
|
454
|
+
|
|
455
|
+
// Framework Adapters (also available via require('clawmoat/adapters'))
|
|
456
|
+
const adapters = require('./adapters');
|
|
457
|
+
module.exports.createGuard = adapters.createGuard;
|
|
458
|
+
module.exports.ClawMoatCallbackHandler = adapters.ClawMoatCallbackHandler;
|