@clawdreyhepburn/carapace 0.2.1 → 0.3.1

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.
@@ -1,442 +1,210 @@
1
1
  # Recommended Policies
2
2
 
3
- Real-world Cedar policies for common "oh no" scenarios. These are starting points — adapt them to your agent's actual needs.
3
+ Cedar policy examples for common use cases. Copy, adapt, deploy.
4
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.
5
+ > **First:** Complete the [Security Hardening Guide](SECURITY.md) — especially enabling the LLM proxy and closing the bypass gap. Without that, these policies are advisory.
37
6
 
38
7
  ---
39
8
 
40
9
  ## Shell Policies
41
10
 
42
- ### Block destructive file operations
43
-
44
- The classics. An agent with shell access can `rm -rf /` before you blink.
11
+ ### Block destructive commands
45
12
 
46
13
  ```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
- );
14
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"rm");
15
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"rmdir");
16
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"mkfs");
17
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"dd");
18
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"diskutil");
19
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"format");
79
20
  ```
80
21
 
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.
22
+ Use `trash` instead of `rm` it's recoverable.
82
23
 
83
- ### Block credential and secret access
84
-
85
- Agents don't need to read your SSH keys or browser passwords.
24
+ ### Block privilege escalation
86
25
 
87
26
  ```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
- );
27
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"sudo");
28
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"su");
29
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"chmod");
30
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"chown");
31
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"chgrp");
32
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"launchctl");
33
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"systemctl");
34
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"sc");
119
35
  ```
120
36
 
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.
37
+ ### Block credential access
126
38
 
127
39
  ```cedar
128
- forbid(
129
- principal,
130
- action == Jans::Action::"exec_command",
131
- resource == Jans::Shell::"sudo"
132
- );
40
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"security");
41
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"ssh-keygen");
42
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"gpg");
43
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"op");
44
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"pass");
45
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"cmdkey");
46
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"certutil");
47
+ ```
133
48
 
134
- forbid(
135
- principal,
136
- action == Jans::Action::"exec_command",
137
- resource == Jans::Shell::"su"
138
- );
49
+ ### Block network recon
139
50
 
140
- forbid(
141
- principal,
142
- action == Jans::Action::"exec_command",
143
- resource == Jans::Shell::"chmod"
144
- );
51
+ ```cedar
52
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"nmap");
53
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"tcpdump");
54
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"netcat");
55
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"nc");
56
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"wireshark");
57
+ ```
145
58
 
146
- forbid(
147
- principal,
148
- action == Jans::Action::"exec_command",
149
- resource == Jans::Shell::"chown"
150
- );
59
+ ### Block shell wrappers
151
60
 
152
- forbid(
153
- principal,
154
- action == Jans::Action::"exec_command",
155
- resource == Jans::Shell::"launchctl"
156
- );
61
+ Prevent agents from using wrapper commands to run forbidden binaries:
157
62
 
158
- forbid(
159
- principal,
160
- action == Jans::Action::"exec_command",
161
- resource == Jans::Shell::"systemctl"
162
- );
63
+ ```cedar
64
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"bash");
65
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"sh");
66
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"zsh");
67
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"env");
68
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"xargs");
69
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"cmd");
70
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"powershell");
163
71
  ```
164
72
 
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.
73
+ ### Allow safe dev tools
170
74
 
171
75
  ```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
- );
76
+ permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"git");
77
+ permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"npm");
78
+ permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"npx");
79
+ permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"cat");
80
+ permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"ls");
81
+ permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"grep");
82
+ permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"find");
83
+ permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"mkdir");
84
+ permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"trash");
85
+ permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"cp");
86
+ permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"mv");
87
+ ```
183
88
 
184
- forbid(
185
- principal,
186
- action == Jans::Action::"exec_command",
187
- resource == Jans::Shell::"netcat"
188
- );
89
+ ### Restrict sensitive path reads
189
90
 
91
+ ```cedar
190
92
  forbid(
191
93
  principal,
192
94
  action == Jans::Action::"exec_command",
193
- resource == Jans::Shell::"nc"
194
- );
95
+ resource == Jans::Shell::"cat"
96
+ ) when {
97
+ context.args like "*/.ssh/*" ||
98
+ context.args like "*/.aws/*" ||
99
+ context.args like "*/.env*" ||
100
+ context.args like "*/.gnupg/*"
101
+ };
195
102
  ```
196
103
 
197
- ### Allow a safe set of dev tools
198
-
199
- If your agent does development work, permit the tools it actually needs:
104
+ ### Block writes to OpenClaw directories
200
105
 
201
106
  ```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
- );
107
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"cp")
108
+ when { context.args like "*/.openclaw/*" };
109
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"mv")
110
+ when { context.args like "*/.openclaw/*" };
111
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"tee")
112
+ when { context.args like "*/.openclaw/*" };
252
113
  ```
253
114
 
254
115
  ---
255
116
 
256
117
  ## API Policies
257
118
 
258
- ### Block data exfiltration
259
-
260
- An agent that can POST to any URL can send your files, credentials, and chat history anywhere.
119
+ ### Block data exfiltration services
261
120
 
262
121
  ```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
- );
122
+ forbid(principal, action == Jans::Action::"call_api", resource == Jans::API::"pastebin.com");
123
+ forbid(principal, action == Jans::Action::"call_api", resource == Jans::API::"hastebin.com");
124
+ forbid(principal, action == Jans::Action::"call_api", resource == Jans::API::"transfer.sh");
125
+ forbid(principal, action == Jans::Action::"call_api", resource == Jans::API::"file.io");
126
+ forbid(principal, action == Jans::Action::"call_api", resource == Jans::API::"webhook.site");
127
+ forbid(principal, action == Jans::Action::"call_api", resource == Jans::API::"requestbin.com");
128
+ forbid(principal, action == Jans::Action::"call_api", resource == Jans::API::"ngrok.io");
129
+ forbid(principal, action == Jans::Action::"call_api", resource == Jans::API::"pipedream.net");
299
130
  ```
300
131
 
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.
132
+ ### Allow specific APIs
302
133
 
303
- ### Allow specific APIs your agent needs
134
+ ```cedar
135
+ permit(principal is Jans::Workload, action == Jans::Action::"call_api", resource == Jans::API::"api.github.com");
136
+ permit(principal is Jans::Workload, action == Jans::Action::"call_api", resource == Jans::API::"registry.npmjs.org");
137
+ permit(principal is Jans::Workload, action == Jans::Action::"call_api", resource == Jans::API::"api.yourcompany.com");
138
+ ```
304
139
 
305
- Better than blocking bad domains: only allow the domains your agent actually uses.
140
+ ### Read-only API access
306
141
 
307
142
  ```cedar
308
- // GitHub API
309
143
  permit(
310
144
  principal is Jans::Workload,
311
145
  action == Jans::Action::"call_api",
312
146
  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
- );
147
+ ) when {
148
+ context.method == "GET"
149
+ };
328
150
  ```
329
151
 
330
152
  ### Block social media posting
331
153
 
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
154
  ```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
- );
155
+ forbid(principal, action == Jans::Action::"call_api", resource == Jans::API::"api.twitter.com");
156
+ forbid(principal, action == Jans::Action::"call_api", resource == Jans::API::"api.x.com");
157
+ forbid(principal, action == Jans::Action::"call_api", resource == Jans::API::"graph.facebook.com");
158
+ forbid(principal, action == Jans::Action::"call_api", resource == Jans::API::"api.linkedin.com");
159
+ forbid(principal, action == Jans::Action::"call_api", resource == Jans::API::"discord.com");
160
+ forbid(principal, action == Jans::Action::"call_api", resource == Jans::API::"slack.com");
161
+ ```
347
162
 
348
- forbid(
349
- principal,
350
- action == Jans::Action::"call_api",
351
- resource == Jans::API::"graph.facebook.com"
352
- );
163
+ ### Block localhost/internal network
353
164
 
354
- forbid(
355
- principal,
356
- action == Jans::Action::"call_api",
357
- resource == Jans::API::"api.linkedin.com"
358
- );
165
+ ```cedar
166
+ forbid(principal, action == Jans::Action::"call_api", resource == Jans::API::"127.0.0.1");
167
+ forbid(principal, action == Jans::Action::"call_api", resource == Jans::API::"0.0.0.0");
168
+ forbid(principal, action == Jans::Action::"call_api", resource == Jans::API::"localhost");
359
169
  ```
360
170
 
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
171
  ---
364
172
 
365
173
  ## MCP Tool Policies
366
174
 
367
- ### Block destructive MCP tools
368
-
369
- If you're using the filesystem MCP server, the write tools are the dangerous ones:
175
+ ### Block destructive file tools
370
176
 
371
177
  ```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
- );
178
+ forbid(principal, action == Jans::Action::"call_tool", resource == Jans::Tool::"filesystem/write_file");
179
+ forbid(principal, action == Jans::Action::"call_tool", resource == Jans::Tool::"filesystem/move_file");
180
+ forbid(principal, action == Jans::Action::"call_tool", resource == Jans::Tool::"filesystem/delete_file");
383
181
  ```
384
182
 
385
183
  ### Block email mass operations
386
184
 
387
- If your agent has email access via MCP:
388
-
389
185
  ```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
- );
186
+ forbid(principal, action == Jans::Action::"call_tool", resource == Jans::Tool::"email/delete_all");
187
+ forbid(principal, action == Jans::Action::"call_tool", resource == Jans::Tool::"email/empty_trash");
188
+ forbid(principal, action == Jans::Action::"call_tool", resource == Jans::Tool::"email/send_bulk");
409
189
  ```
410
190
 
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:
191
+ ### Read-only database access
416
192
 
417
193
  ```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
- );
194
+ forbid(principal, action == Jans::Action::"call_tool", resource == Jans::Tool::"database/execute_sql");
195
+ permit(principal is Jans::Workload, action == Jans::Action::"call_tool", resource == Jans::Tool::"database/query");
430
196
  ```
431
197
 
432
198
  ---
433
199
 
434
- ## Complete Starter Policies
200
+ ## Complete Starter Configurations
435
201
 
436
- ### "Cautious developer" — safe for a coding agent
202
+ ### "Cautious developer"
203
+
204
+ Good default for a coding agent. Allows dev tools, blocks destruction and exfiltration.
437
205
 
438
206
  ```cedar
439
- // Shell: allow common dev tools, block everything dangerous
207
+ // Dev tools
440
208
  permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"git");
441
209
  permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"npm");
442
210
  permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"npx");
@@ -450,70 +218,113 @@ permit(principal is Jans::Workload, action == Jans::Action::"exec_command", reso
450
218
  permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"cp");
451
219
  permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"mv");
452
220
 
221
+ // Hard blocks
453
222
  forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"rm");
454
223
  forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"sudo");
455
224
  forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"security");
225
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"bash");
226
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"sh");
456
227
 
457
- // API: allow GitHub and npm, block exfil
228
+ // APIs
458
229
  permit(principal is Jans::Workload, action == Jans::Action::"call_api", resource == Jans::API::"api.github.com");
459
230
  permit(principal is Jans::Workload, action == Jans::Action::"call_api", resource == Jans::API::"registry.npmjs.org");
460
231
  forbid(principal, action == Jans::Action::"call_api", resource == Jans::API::"pastebin.com");
461
232
  forbid(principal, action == Jans::Action::"call_api", resource == Jans::API::"webhook.site");
462
233
 
463
- // MCP: allow all tools (rely on shell/API policies for safety)
234
+ // MCP: allow all tools
464
235
  permit(principal is Jans::Workload, action == Jans::Action::"call_tool", resource);
465
236
  ```
466
237
 
467
- ### "Paranoid lockdown" — least privilege, deny-all baseline
238
+ ### "Research assistant"
468
239
 
469
- Set `defaultPolicy: "deny-all"` in config, then only add permits:
240
+ Read-only access. Can browse and search but can't modify anything.
470
241
 
471
242
  ```cedar
472
- // Only the exact tools this agent needs
243
+ // Read-only shell
244
+ permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"cat");
245
+ permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"ls");
246
+ permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"grep");
247
+ permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"find");
248
+ permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"wc");
249
+ permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"head");
250
+ permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"tail");
251
+
252
+ // Read-only APIs (GET only)
253
+ permit(
254
+ principal is Jans::Workload,
255
+ action == Jans::Action::"call_api",
256
+ resource
257
+ ) when {
258
+ context.method == "GET"
259
+ };
260
+
261
+ // Read-only MCP
473
262
  permit(principal is Jans::Workload, action == Jans::Action::"call_tool", resource == Jans::Tool::"filesystem/read_file");
474
263
  permit(principal is Jans::Workload, action == Jans::Action::"call_tool", resource == Jans::Tool::"filesystem/list_directory");
264
+ ```
475
265
 
476
- // Only git
266
+ ### "Paranoid lockdown"
267
+
268
+ Deny-all baseline. Nothing works unless explicitly permitted.
269
+
270
+ Set `defaultPolicy: "deny-all"` in config, then:
271
+
272
+ ```cedar
273
+ // The absolute minimum for a useful agent
274
+ permit(principal is Jans::Workload, action == Jans::Action::"call_tool", resource == Jans::Tool::"filesystem/read_file");
275
+ permit(principal is Jans::Workload, action == Jans::Action::"call_tool", resource == Jans::Tool::"filesystem/list_directory");
477
276
  permit(principal is Jans::Workload, action == Jans::Action::"exec_command", resource == Jans::Shell::"git");
478
277
 
479
- // No API access at all (omit all call_api permits)
278
+ // No API access, no shell writes, no nothing else
480
279
  ```
481
280
 
482
- Everything not explicitly permitted is denied. This is the most secure posture but requires you to know exactly what your agent needs.
281
+ ### "Social media manager"
282
+
283
+ Can post to specific platforms via MCP tools, but not via raw API access.
284
+
285
+ ```cedar
286
+ // Allow posting through the managed MCP tool (has its own guardrails)
287
+ permit(principal is Jans::Workload, action == Jans::Action::"call_tool", resource == Jans::Tool::"twitter/post_tweet");
288
+ permit(principal is Jans::Workload, action == Jans::Action::"call_tool", resource == Jans::Tool::"twitter/read_timeline");
289
+
290
+ // Block raw API access to social platforms (bypass prevention)
291
+ forbid(principal, action == Jans::Action::"call_api", resource == Jans::API::"api.twitter.com");
292
+ forbid(principal, action == Jans::Action::"call_api", resource == Jans::API::"api.x.com");
293
+
294
+ // Block all shell access (social media agent doesn't need it)
295
+ forbid(principal, action == Jans::Action::"exec_command", resource);
296
+
297
+ // Block exfiltration
298
+ forbid(principal, action == Jans::Action::"call_api", resource == Jans::API::"pastebin.com");
299
+ forbid(principal, action == Jans::Action::"call_api", resource == Jans::API::"webhook.site");
300
+ ```
483
301
 
484
302
  ---
485
303
 
486
304
  ## Policy Design Principles
487
305
 
488
- 1. **Forbid the catastrophic, then iterate.** Start by blocking `rm`, `sudo`, and data exfil domains. You can always add more forbids later.
306
+ 1. **Forbid the catastrophic first.** Block `rm`, `sudo`, and exfil domains before anything else.
489
307
 
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.
308
+ 2. **Forbid always wins.** A `forbid` overrides any `permit` write broad permits and surgical forbids.
491
309
 
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`:
310
+ 3. **Binary name is the gate.** `Shell::"git"` permits *all* git commands. For subcommand control, use `when` conditions on `context.args`:
493
311
 
494
312
  ```cedar
495
- forbid(
496
- principal,
497
- action == Jans::Action::"exec_command",
498
- resource == Jans::Shell::"git"
499
- ) when {
500
- context.args like "*--force*"
501
- };
313
+ forbid(principal, action == Jans::Action::"exec_command", resource == Jans::Shell::"git")
314
+ when { context.args like "*push*--force*" };
502
315
  ```
503
316
 
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`.
317
+ 4. **Domain name is the gate.** `API::"api.github.com"` permits all endpoints. For path/method control, use `when` conditions.
505
318
 
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.
319
+ 5. **Start with allow-all + forbids.** Switch to deny-all only when you understand your agent's full tool surface.
507
320
 
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.
321
+ 6. **Review regularly.** Open the GUI, look at what's enabled, adjust.
509
322
 
510
323
  ---
511
324
 
512
325
  ## Further Reading
513
326
 
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)
327
+ - [Security Hardening Guide](SECURITY.md) OS-level protections, proxy setup, credential protection
328
+ - [Cedar blog series](https://clawdrey.com/blog/cedar-for-ai-agents-part-1-why-your-ai-agent-needs-a-policy-language.html)
518
329
  - [Cedar Language Reference](https://docs.cedarpolicy.com/)
519
330
  - [Carapace README](../README.md)