@clawdreyhepburn/carapace 0.2.0 → 0.3.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/README.md +80 -18
- package/docs/RECOMMENDED-POLICIES.md +519 -0
- package/package.json +1 -1
- package/src/cedar-engine-cedarling.ts +15 -0
- package/src/index.ts +147 -1
- package/src/llm-proxy.ts +648 -0
- package/src/types.ts +9 -0
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
<a href="#installation">Installation</a> •
|
|
11
11
|
<a href="#quick-start">Quick Start</a> •
|
|
12
12
|
<a href="#how-it-works">How It Works</a> •
|
|
13
|
+
<a href="docs/RECOMMENDED-POLICIES.md">Recommended Policies</a> •
|
|
13
14
|
<a href="#gui">Control GUI</a> •
|
|
14
15
|
<a href="#security">Security</a> •
|
|
15
16
|
<a href="#attribution">Attribution</a>
|
|
@@ -37,19 +38,22 @@ The progression:
|
|
|
37
38
|
## Architecture
|
|
38
39
|
|
|
39
40
|
```
|
|
40
|
-
|
|
41
|
-
|
|
|
42
|
-
|
|
|
43
|
-
|
|
|
44
|
-
|
|
|
45
|
-
|
|
|
46
|
-
| | | +----------------------+ |
|
|
47
|
-
|
|
|
48
|
-
|
|
|
49
|
-
| | |
|
|
50
|
-
|
|
|
51
|
-
|
|
|
52
|
-
| | |
|
|
41
|
+
+----------------------------+
|
|
42
|
+
| Carapace |
|
|
43
|
+
+-------------+ | | +------------------+
|
|
44
|
+
| | | +----------------------+ | | Anthropic / |
|
|
45
|
+
| OpenClaw |---->| | LLM Proxy | |---->| OpenAI API |
|
|
46
|
+
| Agent | | | (intercepts tool_use)| | +------------------+
|
|
47
|
+
| | | +----------------------+ |
|
|
48
|
+
| | | | | +-----------------+
|
|
49
|
+
| | | Cedar evaluates | | MCP Server A |
|
|
50
|
+
| | | every tool call |---->| (filesystem) |
|
|
51
|
+
| | | | | +-----------------+
|
|
52
|
+
| | | +----------------------+ | | MCP Server B |
|
|
53
|
+
| | | | Cedarling WASM | |---->| (GitHub) |
|
|
54
|
+
| | | | (Cedar 4.4.2) | | +-----------------+
|
|
55
|
+
| | | +----------------------+ |
|
|
56
|
+
| | | +----------------------+ |
|
|
53
57
|
| | | | Local Control GUI | |
|
|
54
58
|
+-------------+ | +----------------------+ |
|
|
55
59
|
+--------------+--------------+
|
|
@@ -60,7 +64,11 @@ The progression:
|
|
|
60
64
|
+-------------+
|
|
61
65
|
```
|
|
62
66
|
|
|
63
|
-
|
|
67
|
+
### Two enforcement modes
|
|
68
|
+
|
|
69
|
+
**LLM Proxy (recommended):** Carapace holds the real API key and proxies all LLM traffic. When the LLM suggests a tool call, Carapace evaluates it against Cedar *before returning the response to OpenClaw*. Denied tool calls are stripped from the response — OpenClaw never sees them and can't execute them. **This is un-bypassable.** The agent can't call tools that Cedar denies because it literally never receives the tool call instruction.
|
|
70
|
+
|
|
71
|
+
**Tool-level gating:** Carapace registers Cedar-gated agent tools (`carapace_exec`, `carapace_fetch`, `mcp_call`) that authorize each operation before executing it. This requires denying built-in tools via `openclaw carapace setup` to prevent bypass. Use this mode when you can't or don't want to proxy LLM traffic.
|
|
64
72
|
|
|
65
73
|
## Screenshots
|
|
66
74
|
|
|
@@ -154,18 +162,70 @@ In your OpenClaw config, add the servers you want Carapace to manage:
|
|
|
154
162
|
}
|
|
155
163
|
```
|
|
156
164
|
|
|
157
|
-
### 2.
|
|
165
|
+
### 2. Enable the LLM Proxy (recommended)
|
|
166
|
+
|
|
167
|
+
The LLM Proxy is the strongest enforcement mode. Carapace holds the real API key and intercepts tool calls before OpenClaw can execute them.
|
|
168
|
+
|
|
169
|
+
```json5
|
|
170
|
+
{
|
|
171
|
+
plugins: {
|
|
172
|
+
entries: {
|
|
173
|
+
carapace: {
|
|
174
|
+
enabled: true,
|
|
175
|
+
config: {
|
|
176
|
+
proxy: {
|
|
177
|
+
enabled: true,
|
|
178
|
+
port: 19821,
|
|
179
|
+
upstream: {
|
|
180
|
+
anthropic: { apiKey: "sk-ant-your-real-key-here" }
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
// Point OpenClaw at the proxy instead of the real API
|
|
188
|
+
providers: {
|
|
189
|
+
anthropic: {
|
|
190
|
+
apiKey: "carapace-proxy", // dummy — proxy holds the real key
|
|
191
|
+
baseUrl: "http://127.0.0.1:19821"
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Now every tool call the LLM suggests goes through Cedar. If Cedar denies it, the tool call is stripped from the response before OpenClaw ever sees it.
|
|
198
|
+
|
|
199
|
+
### 3. (Alternative) Close the bypass gap without the proxy
|
|
200
|
+
|
|
201
|
+
By default, agents can still use OpenClaw's built-in `exec` and `web_fetch` tools, which bypass Cedar entirely. Run setup to close this:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
openclaw carapace setup
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
This adds `exec`, `web_fetch`, and `web_search` to `tools.deny` in your OpenClaw config, forcing agents to use `carapace_exec` and `carapace_fetch` instead — which go through Cedar.
|
|
208
|
+
|
|
209
|
+
You can check for bypasses anytime:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
openclaw carapace check
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
> ⚠️ **Without this step, Carapace policies are advisory, not enforced.** The agent can simply choose to use the built-in tools instead. Always run `carapace setup` for real security.
|
|
216
|
+
|
|
217
|
+
### 4. Open the control GUI
|
|
158
218
|
|
|
159
219
|
Navigate to [http://localhost:19820](http://localhost:19820) in your browser. You'll see all discovered tools from all connected servers.
|
|
160
220
|
|
|
161
|
-
###
|
|
221
|
+
### 5. Enable tools
|
|
162
222
|
|
|
163
223
|
Toggle individual tools on/off. Each toggle writes a Cedar policy:
|
|
164
224
|
|
|
165
225
|
- **Toggle ON** → creates a `permit` policy for that tool
|
|
166
226
|
- **Toggle OFF** → creates a `forbid` policy for that tool
|
|
167
227
|
|
|
168
|
-
###
|
|
228
|
+
### 6. Create custom policies
|
|
169
229
|
|
|
170
230
|
Click **"+ New Policy"** to open the visual builder, or edit policies directly in the Policies tab. Examples:
|
|
171
231
|
|
|
@@ -218,7 +278,9 @@ permit(
|
|
|
218
278
|
);
|
|
219
279
|
```
|
|
220
280
|
|
|
221
|
-
|
|
281
|
+
> 📖 **Want more?** See [Recommended Policies](docs/RECOMMENDED-POLICIES.md) for real-world policies covering destructive commands, credential theft, data exfiltration, email deletion, and complete starter configurations.
|
|
282
|
+
|
|
283
|
+
### 7. Verify policies
|
|
222
284
|
|
|
223
285
|
Click **⚡ Verify** to validate that all policies are syntactically correct and consistent.
|
|
224
286
|
|
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
# Recommended Policies
|
|
2
|
+
|
|
3
|
+
Real-world Cedar policies for common "oh no" scenarios. These are starting points — adapt them to your agent's actual needs.
|
|
4
|
+
|
|
5
|
+
## Before You Write Policies: Close the Bypass Gap
|
|
6
|
+
|
|
7
|
+
**This is the most important step.** If you skip it, every policy in this document is advisory — the agent can just use OpenClaw's built-in `exec` tool instead of `carapace_exec` and bypass Cedar entirely.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
openclaw carapace setup
|
|
11
|
+
openclaw gateway restart
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
This denies the built-in `exec`, `web_fetch`, and `web_search` tools, forcing agents to use the Cedar-gated `carapace_exec` and `carapace_fetch` instead. Verify with:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
openclaw carapace check
|
|
18
|
+
# Should show: ✅ No bypass vulnerabilities found.
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Without this, an agent can:**
|
|
22
|
+
- Call `exec` directly with `rm -rf /` — Carapace never sees it
|
|
23
|
+
- Call `web_fetch` to exfiltrate data — Carapace never sees it
|
|
24
|
+
- Call `exec` with `curl` to hit any API — Carapace never sees it
|
|
25
|
+
|
|
26
|
+
Run setup first. Then write policies.
|
|
27
|
+
|
|
28
|
+
## The Basics
|
|
29
|
+
|
|
30
|
+
Carapace defaults to **allow-all** so installing it never breaks anything. The recommended path:
|
|
31
|
+
|
|
32
|
+
1. **Run `carapace setup`** → close the bypass gap
|
|
33
|
+
2. **Add forbids** → block the scary stuff (this doc)
|
|
34
|
+
3. **Switch to deny-all** → explicitly permit only what's needed (advanced)
|
|
35
|
+
|
|
36
|
+
Most people should start with step 2 and stay there until they're comfortable.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## Shell Policies
|
|
41
|
+
|
|
42
|
+
### Block destructive file operations
|
|
43
|
+
|
|
44
|
+
The classics. An agent with shell access can `rm -rf /` before you blink.
|
|
45
|
+
|
|
46
|
+
```cedar
|
|
47
|
+
// Block rm entirely — use trash instead
|
|
48
|
+
forbid(
|
|
49
|
+
principal,
|
|
50
|
+
action == Jans::Action::"exec_command",
|
|
51
|
+
resource == Jans::Shell::"rm"
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
// Block destructive disk tools
|
|
55
|
+
forbid(
|
|
56
|
+
principal,
|
|
57
|
+
action == Jans::Action::"exec_command",
|
|
58
|
+
resource == Jans::Shell::"rmdir"
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
forbid(
|
|
62
|
+
principal,
|
|
63
|
+
action == Jans::Action::"exec_command",
|
|
64
|
+
resource == Jans::Shell::"mkfs"
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
forbid(
|
|
68
|
+
principal,
|
|
69
|
+
action == Jans::Action::"exec_command",
|
|
70
|
+
resource == Jans::Shell::"dd"
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
// Block format/partition tools
|
|
74
|
+
forbid(
|
|
75
|
+
principal,
|
|
76
|
+
action == Jans::Action::"exec_command",
|
|
77
|
+
resource == Jans::Shell::"diskutil"
|
|
78
|
+
);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Why:** An agent that can delete files can delete *all* files. `rm` is the single most dangerous command you can give an agent. Use `trash` (recoverable) instead and permit that.
|
|
82
|
+
|
|
83
|
+
### Block credential and secret access
|
|
84
|
+
|
|
85
|
+
Agents don't need to read your SSH keys or browser passwords.
|
|
86
|
+
|
|
87
|
+
```cedar
|
|
88
|
+
// Block direct credential access tools
|
|
89
|
+
forbid(
|
|
90
|
+
principal,
|
|
91
|
+
action == Jans::Action::"exec_command",
|
|
92
|
+
resource == Jans::Shell::"security"
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
forbid(
|
|
96
|
+
principal,
|
|
97
|
+
action == Jans::Action::"exec_command",
|
|
98
|
+
resource == Jans::Shell::"ssh-keygen"
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
forbid(
|
|
102
|
+
principal,
|
|
103
|
+
action == Jans::Action::"exec_command",
|
|
104
|
+
resource == Jans::Shell::"gpg"
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
// Block password managers
|
|
108
|
+
forbid(
|
|
109
|
+
principal,
|
|
110
|
+
action == Jans::Action::"exec_command",
|
|
111
|
+
resource == Jans::Shell::"op"
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
forbid(
|
|
115
|
+
principal,
|
|
116
|
+
action == Jans::Action::"exec_command",
|
|
117
|
+
resource == Jans::Shell::"pass"
|
|
118
|
+
);
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**Why:** `security` (macOS Keychain CLI) can dump stored passwords. `ssh-keygen` can overwrite your keys. An agent doesn't need either of these to do useful work.
|
|
122
|
+
|
|
123
|
+
### Block system administration
|
|
124
|
+
|
|
125
|
+
Unless your agent is explicitly managing infrastructure, it shouldn't touch system config.
|
|
126
|
+
|
|
127
|
+
```cedar
|
|
128
|
+
forbid(
|
|
129
|
+
principal,
|
|
130
|
+
action == Jans::Action::"exec_command",
|
|
131
|
+
resource == Jans::Shell::"sudo"
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
forbid(
|
|
135
|
+
principal,
|
|
136
|
+
action == Jans::Action::"exec_command",
|
|
137
|
+
resource == Jans::Shell::"su"
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
forbid(
|
|
141
|
+
principal,
|
|
142
|
+
action == Jans::Action::"exec_command",
|
|
143
|
+
resource == Jans::Shell::"chmod"
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
forbid(
|
|
147
|
+
principal,
|
|
148
|
+
action == Jans::Action::"exec_command",
|
|
149
|
+
resource == Jans::Shell::"chown"
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
forbid(
|
|
153
|
+
principal,
|
|
154
|
+
action == Jans::Action::"exec_command",
|
|
155
|
+
resource == Jans::Shell::"launchctl"
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
forbid(
|
|
159
|
+
principal,
|
|
160
|
+
action == Jans::Action::"exec_command",
|
|
161
|
+
resource == Jans::Shell::"systemctl"
|
|
162
|
+
);
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**Why:** Privilege escalation is the nightmare scenario. If your agent can `sudo`, it can do *anything*. Even `chmod` can weaken file permissions enough to enable other attacks.
|
|
166
|
+
|
|
167
|
+
### Block network reconnaissance
|
|
168
|
+
|
|
169
|
+
Agents don't need to scan your network.
|
|
170
|
+
|
|
171
|
+
```cedar
|
|
172
|
+
forbid(
|
|
173
|
+
principal,
|
|
174
|
+
action == Jans::Action::"exec_command",
|
|
175
|
+
resource == Jans::Shell::"nmap"
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
forbid(
|
|
179
|
+
principal,
|
|
180
|
+
action == Jans::Action::"exec_command",
|
|
181
|
+
resource == Jans::Shell::"tcpdump"
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
forbid(
|
|
185
|
+
principal,
|
|
186
|
+
action == Jans::Action::"exec_command",
|
|
187
|
+
resource == Jans::Shell::"netcat"
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
forbid(
|
|
191
|
+
principal,
|
|
192
|
+
action == Jans::Action::"exec_command",
|
|
193
|
+
resource == Jans::Shell::"nc"
|
|
194
|
+
);
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Allow a safe set of dev tools
|
|
198
|
+
|
|
199
|
+
If your agent does development work, permit the tools it actually needs:
|
|
200
|
+
|
|
201
|
+
```cedar
|
|
202
|
+
// Version control
|
|
203
|
+
permit(
|
|
204
|
+
principal is Jans::Workload,
|
|
205
|
+
action == Jans::Action::"exec_command",
|
|
206
|
+
resource == Jans::Shell::"git"
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
// Package managers
|
|
210
|
+
permit(
|
|
211
|
+
principal is Jans::Workload,
|
|
212
|
+
action == Jans::Action::"exec_command",
|
|
213
|
+
resource == Jans::Shell::"npm"
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
permit(
|
|
217
|
+
principal is Jans::Workload,
|
|
218
|
+
action == Jans::Action::"exec_command",
|
|
219
|
+
resource == Jans::Shell::"npx"
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
// Safe file operations
|
|
223
|
+
permit(
|
|
224
|
+
principal is Jans::Workload,
|
|
225
|
+
action == Jans::Action::"exec_command",
|
|
226
|
+
resource == Jans::Shell::"cat"
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
permit(
|
|
230
|
+
principal is Jans::Workload,
|
|
231
|
+
action == Jans::Action::"exec_command",
|
|
232
|
+
resource == Jans::Shell::"ls"
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
permit(
|
|
236
|
+
principal is Jans::Workload,
|
|
237
|
+
action == Jans::Action::"exec_command",
|
|
238
|
+
resource == Jans::Shell::"grep"
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
permit(
|
|
242
|
+
principal is Jans::Workload,
|
|
243
|
+
action == Jans::Action::"exec_command",
|
|
244
|
+
resource == Jans::Shell::"find"
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
permit(
|
|
248
|
+
principal is Jans::Workload,
|
|
249
|
+
action == Jans::Action::"exec_command",
|
|
250
|
+
resource == Jans::Shell::"trash"
|
|
251
|
+
);
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## API Policies
|
|
257
|
+
|
|
258
|
+
### Block data exfiltration
|
|
259
|
+
|
|
260
|
+
An agent that can POST to any URL can send your files, credentials, and chat history anywhere.
|
|
261
|
+
|
|
262
|
+
```cedar
|
|
263
|
+
// Block known paste/upload services
|
|
264
|
+
forbid(
|
|
265
|
+
principal,
|
|
266
|
+
action == Jans::Action::"call_api",
|
|
267
|
+
resource == Jans::API::"pastebin.com"
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
forbid(
|
|
271
|
+
principal,
|
|
272
|
+
action == Jans::Action::"call_api",
|
|
273
|
+
resource == Jans::API::"hastebin.com"
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
forbid(
|
|
277
|
+
principal,
|
|
278
|
+
action == Jans::Action::"call_api",
|
|
279
|
+
resource == Jans::API::"transfer.sh"
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
forbid(
|
|
283
|
+
principal,
|
|
284
|
+
action == Jans::Action::"call_api",
|
|
285
|
+
resource == Jans::API::"file.io"
|
|
286
|
+
);
|
|
287
|
+
|
|
288
|
+
forbid(
|
|
289
|
+
principal,
|
|
290
|
+
action == Jans::Action::"call_api",
|
|
291
|
+
resource == Jans::API::"webhook.site"
|
|
292
|
+
);
|
|
293
|
+
|
|
294
|
+
forbid(
|
|
295
|
+
principal,
|
|
296
|
+
action == Jans::Action::"call_api",
|
|
297
|
+
resource == Jans::API::"requestbin.com"
|
|
298
|
+
);
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
**Why:** Prompt injection attacks can instruct an agent to exfiltrate data by posting it to an attacker-controlled URL. Blocking common exfil endpoints is a basic hygiene measure.
|
|
302
|
+
|
|
303
|
+
### Allow specific APIs your agent needs
|
|
304
|
+
|
|
305
|
+
Better than blocking bad domains: only allow the domains your agent actually uses.
|
|
306
|
+
|
|
307
|
+
```cedar
|
|
308
|
+
// GitHub API
|
|
309
|
+
permit(
|
|
310
|
+
principal is Jans::Workload,
|
|
311
|
+
action == Jans::Action::"call_api",
|
|
312
|
+
resource == Jans::API::"api.github.com"
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
// npm registry
|
|
316
|
+
permit(
|
|
317
|
+
principal is Jans::Workload,
|
|
318
|
+
action == Jans::Action::"call_api",
|
|
319
|
+
resource == Jans::API::"registry.npmjs.org"
|
|
320
|
+
);
|
|
321
|
+
|
|
322
|
+
// Your own services
|
|
323
|
+
permit(
|
|
324
|
+
principal is Jans::Workload,
|
|
325
|
+
action == Jans::Action::"call_api",
|
|
326
|
+
resource == Jans::API::"api.yourcompany.com"
|
|
327
|
+
);
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
### Block social media posting
|
|
331
|
+
|
|
332
|
+
If your agent has social media access, you might want to prevent it from posting without oversight, or block it from leaking info to random accounts.
|
|
333
|
+
|
|
334
|
+
```cedar
|
|
335
|
+
// Block direct API access to social platforms
|
|
336
|
+
forbid(
|
|
337
|
+
principal,
|
|
338
|
+
action == Jans::Action::"call_api",
|
|
339
|
+
resource == Jans::API::"api.twitter.com"
|
|
340
|
+
);
|
|
341
|
+
|
|
342
|
+
forbid(
|
|
343
|
+
principal,
|
|
344
|
+
action == Jans::Action::"call_api",
|
|
345
|
+
resource == Jans::API::"api.x.com"
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
forbid(
|
|
349
|
+
principal,
|
|
350
|
+
action == Jans::Action::"call_api",
|
|
351
|
+
resource == Jans::API::"graph.facebook.com"
|
|
352
|
+
);
|
|
353
|
+
|
|
354
|
+
forbid(
|
|
355
|
+
principal,
|
|
356
|
+
action == Jans::Action::"call_api",
|
|
357
|
+
resource == Jans::API::"api.linkedin.com"
|
|
358
|
+
);
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
**Why:** An agent that can post to social media can damage your reputation in seconds. Even if your agent "should" post, you probably want that gated through an MCP tool with its own policy rather than raw API access.
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## MCP Tool Policies
|
|
366
|
+
|
|
367
|
+
### Block destructive MCP tools
|
|
368
|
+
|
|
369
|
+
If you're using the filesystem MCP server, the write tools are the dangerous ones:
|
|
370
|
+
|
|
371
|
+
```cedar
|
|
372
|
+
forbid(
|
|
373
|
+
principal,
|
|
374
|
+
action == Jans::Action::"call_tool",
|
|
375
|
+
resource == Jans::Tool::"filesystem/write_file"
|
|
376
|
+
);
|
|
377
|
+
|
|
378
|
+
forbid(
|
|
379
|
+
principal,
|
|
380
|
+
action == Jans::Action::"call_tool",
|
|
381
|
+
resource == Jans::Tool::"filesystem/move_file"
|
|
382
|
+
);
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### Block email mass operations
|
|
386
|
+
|
|
387
|
+
If your agent has email access via MCP:
|
|
388
|
+
|
|
389
|
+
```cedar
|
|
390
|
+
// Prevent bulk deletion
|
|
391
|
+
forbid(
|
|
392
|
+
principal,
|
|
393
|
+
action == Jans::Action::"call_tool",
|
|
394
|
+
resource == Jans::Tool::"email/delete_all"
|
|
395
|
+
);
|
|
396
|
+
|
|
397
|
+
forbid(
|
|
398
|
+
principal,
|
|
399
|
+
action == Jans::Action::"call_tool",
|
|
400
|
+
resource == Jans::Tool::"email/empty_trash"
|
|
401
|
+
);
|
|
402
|
+
|
|
403
|
+
// Prevent mass sending (spam)
|
|
404
|
+
forbid(
|
|
405
|
+
principal,
|
|
406
|
+
action == Jans::Action::"call_tool",
|
|
407
|
+
resource == Jans::Tool::"email/send_bulk"
|
|
408
|
+
);
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
**Why:** An agent that can delete emails can delete your *entire inbox*. An agent that can send emails can spam your contacts. These are catastrophic, irreversible actions.
|
|
412
|
+
|
|
413
|
+
### Block database mutations
|
|
414
|
+
|
|
415
|
+
If your agent has database access:
|
|
416
|
+
|
|
417
|
+
```cedar
|
|
418
|
+
forbid(
|
|
419
|
+
principal,
|
|
420
|
+
action == Jans::Action::"call_tool",
|
|
421
|
+
resource == Jans::Tool::"database/execute_sql"
|
|
422
|
+
);
|
|
423
|
+
|
|
424
|
+
// Allow reads only
|
|
425
|
+
permit(
|
|
426
|
+
principal is Jans::Workload,
|
|
427
|
+
action == Jans::Action::"call_tool",
|
|
428
|
+
resource == Jans::Tool::"database/query"
|
|
429
|
+
);
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
---
|
|
433
|
+
|
|
434
|
+
## Complete Starter Policies
|
|
435
|
+
|
|
436
|
+
### "Cautious developer" — safe for a coding agent
|
|
437
|
+
|
|
438
|
+
```cedar
|
|
439
|
+
// Shell: allow common dev tools, block everything dangerous
|
|
440
|
+
permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"git");
|
|
441
|
+
permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"npm");
|
|
442
|
+
permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"npx");
|
|
443
|
+
permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"node");
|
|
444
|
+
permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"cat");
|
|
445
|
+
permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"ls");
|
|
446
|
+
permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"grep");
|
|
447
|
+
permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"find");
|
|
448
|
+
permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"trash");
|
|
449
|
+
permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"mkdir");
|
|
450
|
+
permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"cp");
|
|
451
|
+
permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"mv");
|
|
452
|
+
|
|
453
|
+
forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"rm");
|
|
454
|
+
forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"sudo");
|
|
455
|
+
forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"security");
|
|
456
|
+
|
|
457
|
+
// API: allow GitHub and npm, block exfil
|
|
458
|
+
permit(principal is Jans::Workload, action == Jans::Action::"call_api", resource == Jans::API::"api.github.com");
|
|
459
|
+
permit(principal is Jans::Workload, action == Jans::Action::"call_api", resource == Jans::API::"registry.npmjs.org");
|
|
460
|
+
forbid(principal, action == Jans::Action::"call_api", resource == Jans::API::"pastebin.com");
|
|
461
|
+
forbid(principal, action == Jans::Action::"call_api", resource == Jans::API::"webhook.site");
|
|
462
|
+
|
|
463
|
+
// MCP: allow all tools (rely on shell/API policies for safety)
|
|
464
|
+
permit(principal is Jans::Workload, action == Jans::Action::"call_tool", resource);
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
### "Paranoid lockdown" — least privilege, deny-all baseline
|
|
468
|
+
|
|
469
|
+
Set `defaultPolicy: "deny-all"` in config, then only add permits:
|
|
470
|
+
|
|
471
|
+
```cedar
|
|
472
|
+
// Only the exact tools this agent needs
|
|
473
|
+
permit(principal is Jans::Workload, action == Jans::Action::"call_tool", resource == Jans::Tool::"filesystem/read_file");
|
|
474
|
+
permit(principal is Jans::Workload, action == Jans::Action::"call_tool", resource == Jans::Tool::"filesystem/list_directory");
|
|
475
|
+
|
|
476
|
+
// Only git
|
|
477
|
+
permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"git");
|
|
478
|
+
|
|
479
|
+
// No API access at all (omit all call_api permits)
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
Everything not explicitly permitted is denied. This is the most secure posture but requires you to know exactly what your agent needs.
|
|
483
|
+
|
|
484
|
+
---
|
|
485
|
+
|
|
486
|
+
## Policy Design Principles
|
|
487
|
+
|
|
488
|
+
1. **Forbid the catastrophic, then iterate.** Start by blocking `rm`, `sudo`, and data exfil domains. You can always add more forbids later.
|
|
489
|
+
|
|
490
|
+
2. **Forbid always wins.** In Cedar, a `forbid` policy overrides any `permit`. This means you can write broad permits and surgical forbids without worrying about order or precedence.
|
|
491
|
+
|
|
492
|
+
3. **Binary name is the gate, not the arguments.** `Shell::"git"` permits *all* git commands including `git push --force`. If you need argument-level control, use Cedar `when` conditions on `context.args`:
|
|
493
|
+
|
|
494
|
+
```cedar
|
|
495
|
+
forbid(
|
|
496
|
+
principal,
|
|
497
|
+
action == Jans::Action::"exec_command",
|
|
498
|
+
resource == Jans::Shell::"git"
|
|
499
|
+
) when {
|
|
500
|
+
context.args like "*--force*"
|
|
501
|
+
};
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
4. **Domain name is the gate, not the path.** `API::"api.github.com"` permits all endpoints on that domain. If you need path-level control, use `when` conditions on `context.url`.
|
|
505
|
+
|
|
506
|
+
5. **Deny-all is aspirational.** Most people should start with allow-all + surgical forbids. Switch to deny-all only when you understand your agent's full tool surface.
|
|
507
|
+
|
|
508
|
+
6. **Review regularly.** Your agent's needs change. Policies that made sense last month might be too loose or too tight today. The GUI makes this easy — open it, look at what's enabled, adjust.
|
|
509
|
+
|
|
510
|
+
---
|
|
511
|
+
|
|
512
|
+
## Further Reading
|
|
513
|
+
|
|
514
|
+
- [Cedar for AI Agents: Why Your AI Agent Needs a Policy Language](https://clawdrey.com/blog/cedar-for-ai-agents-part-1-why-your-ai-agent-needs-a-policy-language.html)
|
|
515
|
+
- [Cedar for AI Agents: Writing Your First Agent Policy](https://clawdrey.com/blog/cedar-for-ai-agents-part-2-writing-your-first-agent-policy.html)
|
|
516
|
+
- [Cedar for AI Agents: When Forbid Meets Permit](https://clawdrey.com/blog/cedar-for-ai-agents-part-3-when-forbid-meets-permit.html)
|
|
517
|
+
- [Cedar for AI Agents: Proving It — SMT Solvers and Why I Trust Math More Than Tests](https://clawdrey.com/blog/proving-it-smt-solvers-and-why-i-trust-math-more-than-tests.html)
|
|
518
|
+
- [Cedar Language Reference](https://docs.cedarpolicy.com/)
|
|
519
|
+
- [Carapace README](../README.md)
|
package/package.json
CHANGED
|
@@ -576,6 +576,11 @@ export class CedarlingEngine {
|
|
|
576
576
|
name: "String",
|
|
577
577
|
required: false,
|
|
578
578
|
},
|
|
579
|
+
workdir: {
|
|
580
|
+
type: "EntityOrCommon",
|
|
581
|
+
name: "String",
|
|
582
|
+
required: false,
|
|
583
|
+
},
|
|
579
584
|
},
|
|
580
585
|
},
|
|
581
586
|
},
|
|
@@ -587,6 +592,16 @@ export class CedarlingEngine {
|
|
|
587
592
|
context: {
|
|
588
593
|
type: "Record",
|
|
589
594
|
attributes: {
|
|
595
|
+
url: {
|
|
596
|
+
type: "EntityOrCommon",
|
|
597
|
+
name: "String",
|
|
598
|
+
required: false,
|
|
599
|
+
},
|
|
600
|
+
method: {
|
|
601
|
+
type: "EntityOrCommon",
|
|
602
|
+
name: "String",
|
|
603
|
+
required: false,
|
|
604
|
+
},
|
|
590
605
|
body: {
|
|
591
606
|
type: "EntityOrCommon",
|
|
592
607
|
name: "String",
|