@stanchat/clawguard 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/plugin.js ADDED
@@ -0,0 +1,229 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.name = exports.id = void 0;
37
+ exports.register = register;
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const os = __importStar(require("os"));
41
+ exports.id = "clawguard";
42
+ exports.name = "Clawguard";
43
+ const CLAWGUARD_DIR = path.join(os.homedir(), ".clawguard");
44
+ const CONFIG_FILE = path.join(CLAWGUARD_DIR, "config.json");
45
+ const LOG_DIR = path.join(CLAWGUARD_DIR, "logs");
46
+ const PENDING_DIR = path.join(CLAWGUARD_DIR, "pending");
47
+ const POLICY_FILE = path.join(CLAWGUARD_DIR, "policy.json");
48
+ const DEFAULT_POLICY = [
49
+ { tool: "exec", decision: "review", reason: "Terminal commands can modify your system" },
50
+ { tool: "bash", decision: "review", reason: "Terminal commands can modify your system" },
51
+ { tool: "shell", decision: "review", reason: "Terminal commands can modify your system" },
52
+ { tool: "write", decision: "review", reason: "File writes can overwrite important data" },
53
+ { tool: "delete", decision: "blocked", reason: "File deletion is high-risk" },
54
+ { tool: "unlink", decision: "blocked", reason: "File deletion is high-risk" },
55
+ { tool: "rm", decision: "blocked", reason: "File deletion is high-risk" },
56
+ ];
57
+ const DANGEROUS_PATTERNS = [
58
+ /rm\s+(-rf?|--recursive|--force)\s+[\/~]/i,
59
+ /rm\s+-[rf]{2}\s+/i,
60
+ /mkfs\./i,
61
+ /dd\s+if=.*of=\/dev/i,
62
+ />\s*\/dev\/sd[a-z]/i,
63
+ /chmod\s+777\s+\//i,
64
+ /curl.*\|\s*(ba)?sh/i,
65
+ /wget.*\|\s*(ba)?sh/i,
66
+ /:(){.*}:/i,
67
+ ];
68
+ const INJECTION_PATTERNS = [
69
+ /ignore\s+(previous|all|prior)\s+(instructions?|prompts?)/i,
70
+ /disregard\s+(your|the|all)\s+(instructions?|rules?|guidelines?)/i,
71
+ /you\s+are\s+now\s+(a|in|acting)/i,
72
+ /new\s+instructions?:/i,
73
+ /jailbreak/i,
74
+ /bypass\s+(security|filter|restriction)/i,
75
+ ];
76
+ function ensureDir(dir) {
77
+ if (!fs.existsSync(dir))
78
+ fs.mkdirSync(dir, { recursive: true });
79
+ }
80
+ function loadConfig() {
81
+ ensureDir(CLAWGUARD_DIR);
82
+ try {
83
+ if (fs.existsSync(CONFIG_FILE)) {
84
+ return JSON.parse(fs.readFileSync(CONFIG_FILE, "utf-8"));
85
+ }
86
+ }
87
+ catch { }
88
+ return { enabled: true, consented: true, showMode: false, showModeActionsRemaining: 10, protectionLevel: "balanced" };
89
+ }
90
+ function saveConfig(config) {
91
+ ensureDir(CLAWGUARD_DIR);
92
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
93
+ }
94
+ function loadPolicy() {
95
+ try {
96
+ if (fs.existsSync(POLICY_FILE)) {
97
+ return JSON.parse(fs.readFileSync(POLICY_FILE, "utf-8"));
98
+ }
99
+ }
100
+ catch { }
101
+ return DEFAULT_POLICY;
102
+ }
103
+ function classifyTool(tool) {
104
+ const policy = loadPolicy();
105
+ const normalized = tool.toLowerCase();
106
+ return policy.find(r => normalized.includes(r.tool.toLowerCase())) || null;
107
+ }
108
+ function checkDangerousCommand(params) {
109
+ const paramsStr = JSON.stringify(params);
110
+ for (const pattern of DANGEROUS_PATTERNS) {
111
+ if (pattern.test(paramsStr)) {
112
+ return "Dangerous command pattern detected";
113
+ }
114
+ }
115
+ return null;
116
+ }
117
+ function checkInjection(params) {
118
+ const paramsStr = JSON.stringify(params);
119
+ for (const pattern of INJECTION_PATTERNS) {
120
+ if (pattern.test(paramsStr)) {
121
+ return "Possible prompt injection detected";
122
+ }
123
+ }
124
+ return null;
125
+ }
126
+ function logAction(tool, params, allowed, reason) {
127
+ ensureDir(LOG_DIR);
128
+ const logEntry = {
129
+ ts: new Date().toISOString(),
130
+ type: "tool",
131
+ tool,
132
+ params,
133
+ allowed,
134
+ reason
135
+ };
136
+ const logFile = path.join(LOG_DIR, `${new Date().toISOString().split("T")[0]}.jsonl`);
137
+ fs.appendFileSync(logFile, JSON.stringify(logEntry) + "\n");
138
+ }
139
+ function generateApprovalId() {
140
+ return `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
141
+ }
142
+ function createPendingApproval(tool, params, reason) {
143
+ ensureDir(PENDING_DIR);
144
+ const id = generateApprovalId();
145
+ const approval = {
146
+ id,
147
+ tool,
148
+ params,
149
+ reason,
150
+ createdAt: new Date().toISOString(),
151
+ status: "pending"
152
+ };
153
+ fs.writeFileSync(path.join(PENDING_DIR, `${id}.json`), JSON.stringify(approval, null, 2));
154
+ return id;
155
+ }
156
+ async function waitForApproval(id, timeoutMs = 30000) {
157
+ const filePath = path.join(PENDING_DIR, `${id}.json`);
158
+ const startTime = Date.now();
159
+ const pollInterval = 500;
160
+ while (Date.now() - startTime < timeoutMs) {
161
+ try {
162
+ if (fs.existsSync(filePath)) {
163
+ const approval = JSON.parse(fs.readFileSync(filePath, "utf-8"));
164
+ if (approval.status !== "pending") {
165
+ return approval.status === "approved";
166
+ }
167
+ }
168
+ }
169
+ catch { }
170
+ await new Promise(resolve => setTimeout(resolve, pollInterval));
171
+ }
172
+ return false;
173
+ }
174
+ function register(api) {
175
+ console.log("🛡️ Clawguard plugin registered (monitoring mode)");
176
+ console.log(" Note: before_tool_call not yet available in OpenClaw - using post-execution monitoring");
177
+ // Register for tool_result_persist (post-execution monitoring)
178
+ // This is synchronous and runs AFTER the tool executes
179
+ // We can log and analyze but cannot block execution
180
+ api.registerHook("tool_result_persist", (event) => {
181
+ const e = event;
182
+ const tool = (e.tool || e.toolName || "unknown");
183
+ const params = (e.args || e.params || {});
184
+ const result = e.result;
185
+ const config = loadConfig();
186
+ console.log(`🛡️ Clawguard: tool executed - ${tool}`);
187
+ if (!config.enabled || !config.consented) {
188
+ logAction(tool, params, true, "Clawguard not enabled");
189
+ return undefined; // Don't modify result
190
+ }
191
+ // Check for dangerous patterns (post-execution alert)
192
+ const injection = checkInjection(params);
193
+ if (injection) {
194
+ logAction(tool, params, false, `POST-EXEC ALERT: ${injection}`);
195
+ console.log(`🛡️ [ALERT] Detected after execution: ${injection}`);
196
+ }
197
+ const dangerous = checkDangerousCommand(params);
198
+ if (dangerous) {
199
+ logAction(tool, params, false, `POST-EXEC ALERT: ${dangerous}`);
200
+ console.log(`🛡️ [ALERT] Dangerous command detected: ${dangerous}`);
201
+ }
202
+ // Log the tool activity
203
+ const rule = classifyTool(tool);
204
+ if (rule) {
205
+ logAction(tool, params, true, `${rule.decision}: ${rule.reason}`);
206
+ }
207
+ else {
208
+ logAction(tool, params, true, "Executed (no policy match)");
209
+ }
210
+ // Update show mode counter
211
+ if (config.showMode) {
212
+ config.showModeActionsRemaining--;
213
+ if (config.showModeActionsRemaining <= 0)
214
+ config.showMode = false;
215
+ saveConfig(config);
216
+ }
217
+ return undefined; // Don't modify the result
218
+ }, { name: "clawguard-tool-monitor" });
219
+ // Also register for command events which ARE working
220
+ api.registerHook("command", (event) => {
221
+ const e = event;
222
+ const action = e.action;
223
+ const sessionKey = e.sessionKey;
224
+ console.log(`🛡️ Clawguard: command - ${action}`);
225
+ logAction(`command:${action}`, { sessionKey }, true, "Command event");
226
+ }, { name: "clawguard-command" });
227
+ }
228
+ exports.default = { id: exports.id, name: exports.name, register };
229
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=postinstall.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postinstall.d.ts","sourceRoot":"","sources":["../src/postinstall.ts"],"names":[],"mappings":""}
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ const fs = __importStar(require("fs"));
38
+ const path = __importStar(require("path"));
39
+ const os = __importStar(require("os"));
40
+ const child_process_1 = require("child_process");
41
+ const CLAWGUARD_DIR = path.join(os.homedir(), ".clawguard");
42
+ function ensureDir(dir) {
43
+ if (!fs.existsSync(dir)) {
44
+ fs.mkdirSync(dir, { recursive: true });
45
+ }
46
+ }
47
+ function main() {
48
+ console.log("\n🛡️ Clawguard - AI Safety for OpenClaw\n");
49
+ ensureDir(CLAWGUARD_DIR);
50
+ ensureDir(path.join(CLAWGUARD_DIR, "logs"));
51
+ ensureDir(path.join(CLAWGUARD_DIR, "pending"));
52
+ const configPath = path.join(CLAWGUARD_DIR, "config.json");
53
+ if (!fs.existsSync(configPath)) {
54
+ const defaultConfig = {
55
+ enabled: false,
56
+ consented: false,
57
+ showMode: false,
58
+ showModeActionsRemaining: 10,
59
+ protectionLevel: "balanced",
60
+ installedAt: new Date().toISOString()
61
+ };
62
+ fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2));
63
+ }
64
+ try {
65
+ (0, child_process_1.execSync)("which clawdbot", { stdio: "ignore" });
66
+ console.log("To complete setup, run:");
67
+ console.log(" clawdbot hooks install <path-to-this-package>");
68
+ console.log(" clawdbot hooks enable clawguard");
69
+ console.log("");
70
+ }
71
+ catch {
72
+ console.log("Clawguard installed. When using with ClawdBot:");
73
+ console.log(" clawdbot hooks install @clawguard/openclaw-skill");
74
+ console.log(" clawdbot hooks enable clawguard");
75
+ console.log("");
76
+ }
77
+ console.log("Or start the dashboard directly:");
78
+ console.log(" npx averecion-lite start");
79
+ console.log("");
80
+ }
81
+ main();
82
+ //# sourceMappingURL=postinstall.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postinstall.js","sourceRoot":"","sources":["../src/postinstall.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,uCAAyB;AACzB,2CAA6B;AAC7B,uCAAyB;AACzB,iDAAyC;AAEzC,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,YAAY,CAAC,CAAC;AAE5D,SAAS,SAAS,CAAC,GAAW;IAC5B,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACzC,CAAC;AACH,CAAC;AAED,SAAS,IAAI;IACX,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;IAE1D,SAAS,CAAC,aAAa,CAAC,CAAC;IACzB,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5C,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC,CAAC;IAE/C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;IAC3D,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC/B,MAAM,aAAa,GAAG;YACpB,OAAO,EAAE,KAAK;YACd,SAAS,EAAE,KAAK;YAChB,QAAQ,EAAE,KAAK;YACf,wBAAwB,EAAE,EAAE;YAC5B,eAAe,EAAE,UAAU;YAC3B,WAAW,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACtC,CAAC;QACF,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACvE,CAAC;IAED,IAAI,CAAC;QACH,IAAA,wBAAQ,EAAC,gBAAgB,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAChD,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC;QAC/D,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;QACjD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;QAC9D,OAAO,CAAC,GAAG,CAAC,oDAAoD,CAAC,CAAC;QAClE,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;QACjD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,kCAAkC,CAAC,CAAC;IAChD,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;IAC1C,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAClB,CAAC;AAED,IAAI,EAAE,CAAC"}
@@ -0,0 +1,22 @@
1
+ ---
2
+ name: before-tool-call
3
+ description: "Clawguard AI safety guardrails - intercepts tool calls before execution"
4
+ emoji: "🛡️"
5
+ events:
6
+ - tool:before
7
+ ---
8
+
9
+ # Clawguard Before Tool Call Hook
10
+
11
+ This hook intercepts all tool calls before execution to enforce safety policies:
12
+
13
+ - Blocks dangerous shell commands (rm -rf, curl|bash, etc.)
14
+ - Detects and blocks prompt injection attempts
15
+ - Requires approval for risky operations in balanced/strict mode
16
+ - Logs all actions for auditing
17
+
18
+ ## Protection Levels
19
+
20
+ - **Relaxed**: Minimal blocking, auto-approve reviews
21
+ - **Balanced**: Approval required for risky operations (default)
22
+ - **Strict**: Approval required for all potentially dangerous operations
@@ -0,0 +1,285 @@
1
+ import * as fs from "fs";
2
+ import * as path from "path";
3
+ import * as os from "os";
4
+
5
+ const CLAWGUARD_DIR = path.join(os.homedir(), ".clawguard");
6
+ const CONFIG_FILE = path.join(CLAWGUARD_DIR, "config.json");
7
+ const LOG_DIR = path.join(CLAWGUARD_DIR, "logs");
8
+ const PENDING_DIR = path.join(CLAWGUARD_DIR, "pending");
9
+ const POLICY_FILE = path.join(CLAWGUARD_DIR, "policy.json");
10
+
11
+ interface ClawguardConfig {
12
+ enabled: boolean;
13
+ consented: boolean;
14
+ showMode: boolean;
15
+ showModeActionsRemaining: number;
16
+ protectionLevel: "relaxed" | "balanced" | "strict";
17
+ }
18
+
19
+ interface PolicyRule {
20
+ tool: string;
21
+ decision: "approved" | "blocked" | "review";
22
+ reason: string;
23
+ }
24
+
25
+ const DEFAULT_POLICY: PolicyRule[] = [
26
+ { tool: "shell", decision: "review", reason: "Terminal commands can modify your system" },
27
+ { tool: "exec", decision: "review", reason: "Terminal commands can modify your system" },
28
+ { tool: "fs.write", decision: "review", reason: "File writes can overwrite important data" },
29
+ { tool: "fs.delete", decision: "blocked", reason: "File deletion is high-risk" },
30
+ { tool: "fs.unlink", decision: "blocked", reason: "File deletion is high-risk" },
31
+ { tool: "http", decision: "approved", reason: "Network requests allowed by default" },
32
+ { tool: "env.read", decision: "blocked", reason: "Credential access is restricted" },
33
+ { tool: "env.get", decision: "blocked", reason: "Credential access is restricted" },
34
+ { tool: "process", decision: "review", reason: "Process management requires review" }
35
+ ];
36
+
37
+ const DANGEROUS_PATTERNS = [
38
+ /rm\s+(-rf?|--recursive|--force)\s+[\/~]/i,
39
+ /rm\s+-[rf]{2}\s+/i,
40
+ /mkfs\./i,
41
+ /dd\s+if=.*of=\/dev/i,
42
+ />\s*\/dev\/sd[a-z]/i,
43
+ /chmod\s+777\s+\//i,
44
+ /curl.*\|\s*(ba)?sh/i,
45
+ /wget.*\|\s*(ba)?sh/i,
46
+ /eval\s*\(/i,
47
+ /:(){.*}:/i
48
+ ];
49
+
50
+ const INJECTION_PATTERNS = [
51
+ /ignore\s+(previous|all|prior)\s+(instructions?|prompts?)/i,
52
+ /disregard\s+(your|the|all)\s+(instructions?|rules?|guidelines?)/i,
53
+ /you\s+are\s+now\s+(a|in|acting)/i,
54
+ /new\s+instructions?:/i,
55
+ /system\s*:\s*you/i,
56
+ /\[INST\]/i,
57
+ /<\|im_start\|>/i,
58
+ /jailbreak/i,
59
+ /bypass\s+(security|filter|restriction)/i
60
+ ];
61
+
62
+ function ensureDir(dir: string): void {
63
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
64
+ }
65
+
66
+ function loadConfig(): ClawguardConfig {
67
+ ensureDir(CLAWGUARD_DIR);
68
+ try {
69
+ if (fs.existsSync(CONFIG_FILE)) {
70
+ return JSON.parse(fs.readFileSync(CONFIG_FILE, "utf-8"));
71
+ }
72
+ } catch {}
73
+ return { enabled: false, consented: false, showMode: false, showModeActionsRemaining: 10, protectionLevel: "balanced" };
74
+ }
75
+
76
+ function saveConfig(config: ClawguardConfig): void {
77
+ ensureDir(CLAWGUARD_DIR);
78
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
79
+ }
80
+
81
+ function loadPolicy(): PolicyRule[] {
82
+ try {
83
+ if (fs.existsSync(POLICY_FILE)) {
84
+ return JSON.parse(fs.readFileSync(POLICY_FILE, "utf-8"));
85
+ }
86
+ } catch {}
87
+ return DEFAULT_POLICY;
88
+ }
89
+
90
+ function classifyTool(tool: string): PolicyRule | null {
91
+ const policy = loadPolicy();
92
+ return policy.find(r => tool.startsWith(r.tool) || tool === r.tool) || null;
93
+ }
94
+
95
+ function checkDangerousCommand(args: Record<string, unknown>): string | null {
96
+ const argsStr = JSON.stringify(args);
97
+ for (const pattern of DANGEROUS_PATTERNS) {
98
+ if (pattern.test(argsStr)) {
99
+ return `Dangerous command pattern detected`;
100
+ }
101
+ }
102
+ return null;
103
+ }
104
+
105
+ function checkInjection(args: Record<string, unknown>): string | null {
106
+ const argsStr = JSON.stringify(args);
107
+ for (const pattern of INJECTION_PATTERNS) {
108
+ if (pattern.test(argsStr)) {
109
+ return `Prompt injection detected`;
110
+ }
111
+ }
112
+ return null;
113
+ }
114
+
115
+ function logAction(tool: string, args: Record<string, unknown>, allowed: boolean, reason: string): void {
116
+ ensureDir(LOG_DIR);
117
+ const logEntry = {
118
+ ts: new Date().toISOString(),
119
+ tool,
120
+ args,
121
+ allowed,
122
+ reason
123
+ };
124
+ const logFile = path.join(LOG_DIR, `${new Date().toISOString().split("T")[0]}.jsonl`);
125
+ fs.appendFileSync(logFile, JSON.stringify(logEntry) + "\n");
126
+ }
127
+
128
+ function generateApprovalId(): string {
129
+ return `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
130
+ }
131
+
132
+ function createPendingApproval(tool: string, args: Record<string, unknown>, reason: string): string {
133
+ ensureDir(PENDING_DIR);
134
+ const id = generateApprovalId();
135
+ const approval = {
136
+ id,
137
+ tool,
138
+ args,
139
+ reason,
140
+ createdAt: new Date().toISOString(),
141
+ status: "pending"
142
+ };
143
+ fs.writeFileSync(path.join(PENDING_DIR, `${id}.json`), JSON.stringify(approval, null, 2));
144
+ console.log(`\x1b[33m🛡️ Clawguard: Action requires approval: ${tool}\x1b[0m`);
145
+ console.log(` Reason: ${reason}`);
146
+ console.log(` Approve: clawdbot clawguard approve ${id}`);
147
+ return id;
148
+ }
149
+
150
+ async function waitForApproval(id: string, timeoutMs = 30000): Promise<boolean> {
151
+ const filePath = path.join(PENDING_DIR, `${id}.json`);
152
+ const startTime = Date.now();
153
+ const pollInterval = 500;
154
+
155
+ while (Date.now() - startTime < timeoutMs) {
156
+ try {
157
+ if (fs.existsSync(filePath)) {
158
+ const approval = JSON.parse(fs.readFileSync(filePath, "utf-8"));
159
+ if (approval.status !== "pending") {
160
+ return approval.status === "approved";
161
+ }
162
+ }
163
+ } catch {}
164
+ await new Promise(resolve => setTimeout(resolve, pollInterval));
165
+ }
166
+
167
+ console.log(`\x1b[31m🛡️ Approval timed out - action blocked\x1b[0m`);
168
+ return false;
169
+ }
170
+
171
+ interface HookEvent {
172
+ type: string;
173
+ toolName: string;
174
+ args: Record<string, unknown>;
175
+ session?: unknown;
176
+ }
177
+
178
+ const handler = async (event: HookEvent): Promise<HookEvent | void> => {
179
+ if (event.type !== "before_tool_call") return;
180
+
181
+ const config = loadConfig();
182
+
183
+ if (!config.enabled || !config.consented) {
184
+ return;
185
+ }
186
+
187
+ const tool = event.toolName;
188
+ const args = event.args || {};
189
+
190
+ const injection = checkInjection(args);
191
+ if (injection) {
192
+ if (config.showMode) {
193
+ console.log(`\x1b[33m🛡️ [SHOW MODE] Would block: ${injection}\x1b[0m`);
194
+ config.showModeActionsRemaining--;
195
+ if (config.showModeActionsRemaining <= 0) config.showMode = false;
196
+ saveConfig(config);
197
+ logAction(tool, args, true, `showMode:${injection}`);
198
+ return;
199
+ }
200
+ logAction(tool, args, false, injection);
201
+ throw new Error(`🛡️ Blocked: ${injection}`);
202
+ }
203
+
204
+ const dangerous = checkDangerousCommand(args);
205
+ if (dangerous) {
206
+ if (config.showMode) {
207
+ console.log(`\x1b[33m🛡️ [SHOW MODE] Would block: ${dangerous}\x1b[0m`);
208
+ config.showModeActionsRemaining--;
209
+ if (config.showModeActionsRemaining <= 0) config.showMode = false;
210
+ saveConfig(config);
211
+ logAction(tool, args, true, `showMode:${dangerous}`);
212
+ return;
213
+ }
214
+ logAction(tool, args, false, dangerous);
215
+ throw new Error(`🛡️ Blocked: ${dangerous}`);
216
+ }
217
+
218
+ const rule = classifyTool(tool);
219
+
220
+ if (!rule) {
221
+ logAction(tool, args, true, "No policy match");
222
+ if (config.showMode) {
223
+ config.showModeActionsRemaining--;
224
+ if (config.showModeActionsRemaining <= 0) config.showMode = false;
225
+ saveConfig(config);
226
+ }
227
+ return;
228
+ }
229
+
230
+ if (rule.decision === "approved") {
231
+ logAction(tool, args, true, rule.reason);
232
+ if (config.showMode) {
233
+ config.showModeActionsRemaining--;
234
+ if (config.showModeActionsRemaining <= 0) config.showMode = false;
235
+ saveConfig(config);
236
+ }
237
+ return;
238
+ }
239
+
240
+ if (rule.decision === "blocked") {
241
+ if (config.showMode) {
242
+ console.log(`\x1b[33m🛡️ [SHOW MODE] Would block: ${tool} - ${rule.reason}\x1b[0m`);
243
+ config.showModeActionsRemaining--;
244
+ if (config.showModeActionsRemaining <= 0) config.showMode = false;
245
+ saveConfig(config);
246
+ logAction(tool, args, true, `showMode:blocked`);
247
+ return;
248
+ }
249
+ logAction(tool, args, false, rule.reason);
250
+ throw new Error(`🛡️ Blocked: ${rule.reason}`);
251
+ }
252
+
253
+ if (rule.decision === "review") {
254
+ if (config.protectionLevel === "relaxed") {
255
+ logAction(tool, args, true, "Relaxed mode - auto-approved");
256
+ if (config.showMode) {
257
+ config.showModeActionsRemaining--;
258
+ if (config.showModeActionsRemaining <= 0) config.showMode = false;
259
+ saveConfig(config);
260
+ }
261
+ return;
262
+ }
263
+
264
+ if (config.showMode) {
265
+ console.log(`\x1b[33m🛡️ [SHOW MODE] Would require approval: ${tool}\x1b[0m`);
266
+ config.showModeActionsRemaining--;
267
+ if (config.showModeActionsRemaining <= 0) config.showMode = false;
268
+ saveConfig(config);
269
+ logAction(tool, args, true, `showMode:review`);
270
+ return;
271
+ }
272
+
273
+ const approvalId = createPendingApproval(tool, args, rule.reason);
274
+ const approved = await waitForApproval(approvalId);
275
+ logAction(tool, args, approved, approved ? "manualApproval" : "denied/timeout");
276
+
277
+ if (!approved) {
278
+ throw new Error(`🛡️ Action denied or timed out`);
279
+ }
280
+ }
281
+
282
+ return;
283
+ };
284
+
285
+ export default handler;