1# Permissions – Codex
2
3Beta. Permission profiles are under active development and may change.
4
5Permission profiles do not compose with the older sandbox settings. Configure
6either `default_permissions` and `[permissions]`, or `sandbox_mode` /
7`sandbox_workspace_write`, but not both. If `sandbox_mode` appears in any
8active config layer, you pass `--sandbox`, or a config profile sets
9`sandbox_mode`, Codex uses those older sandbox settings instead of
10`default_permissions`.
11
12Permission profiles let you apply least-privilege boundaries to local commands
13Codex runs on your behalf. A profile is a named policy that combines filesystem
14rules, which define what commands can read or write, with network rules, which
15define which destinations commands can reach.
16
17Use profiles to give Codex enough access for the current task without granting
18broad access to your machine or network. For example, a read-only profile can
19let Codex inspect a project without editing it, while a write-capable profile
20can limit edits to selected workspace roots.
21
22Local permission profiles are supported on macOS, Linux, WSL, and native
23Windows. Platform-specific enforcement details and caveats are covered in
24[Security limitations](#security-limitations).
25
26For Codex cloud network settings, see [Internet Access](https://developers.openai.com/codex/cloud/internet-access).
27
28## Define and select a profile
29
30Codex includes three built-in permission profiles:
31
32- `:read-only` keeps local command execution read-only.
33- `:workspace` allows writes inside the active workspace roots.
34- `:danger-full-access` removes local sandbox restrictions and should be used
35 only when that broad access is intentional.
36
37Create a named profile under `[permissions.<name>]`, then set the top-level
38`default_permissions` key to that profile name or to one of the built-ins above.
39In this example, `project-edit` is a user-defined profile name, not a built-in
40value.
41
42Custom profiles use two related concepts:
43
44- `[permissions.<name>.workspace_roots]` adds concrete directories that should
45 count as workspace roots for that profile.
46- `[permissions.<name>.filesystem.":workspace_roots"]` defines the filesystem
47 rules Codex applies inside every effective workspace root: the current
48 session’s runtime workspace roots plus the profile-defined roots above.
49
50Profiles also use the normal config-layer model. Higher-precedence layers can
51add or replace entries under the same profile name without restating the whole
52profile.
53
54For example, an organization-level config and a user-level config can extend
55the same profile independently:
56
57```
58# /etc/codex/config.toml
59[permissions.server.workspace_roots]
60"~/code/server" = true
61```
62
63```
64# ~/.codex/config.toml
65[permissions.server.workspace_roots]
66"~/code/mobile-app" = true
67```
68
69When `server` is active, both workspace roots participate in the effective
70profile.
71
72```
73default_permissions = "project-edit"
74
75[permissions.project-edit.workspace_roots]
76"~/code/app" = true
77"~/code/shared-lib" = true
78
79[permissions.project-edit.filesystem]
80":minimal" = "read"
81
82[permissions.project-edit.filesystem.":workspace_roots"]
83"." = "write"
84".devcontainer" = "read"
85"**/*.env" = "deny"
86
87[permissions.project-edit.network]
88enabled = true
89
90[permissions.project-edit.network.domains]
91"api.openai.com" = "allow"
92"objects.githubusercontent.com" = "allow"
93"*.github.com" = "allow"
94"tracking.example.com" = "deny"
95```
96
97This profile:
98
99- Reads the minimal runtime paths common developer tools need.
100- Applies the same workspace-root rules to the current session and the
101 profile-defined roots.
102- Keeps IDE-adjacent settings such as `.devcontainer/` read-only under each
103 root.
104- Denies matching environment files with a glob rule.
105- Allows network access only through the configured domain policy.
106
107Inside an active profile, narrower deny rules stay in force even when a broader
108path is readable or writable. For example, a profile can make workspace roots
109writable while still setting a matching `.env` path to `deny`.
110
111## Configuration spec
112
113| Entry | Type / values | Default | Details |
114| --- | --- | --- | --- |
115| `default_permissions` | String profile name | None | Names the permissions profile Codex applies by default. The value must match a profile under `[permissions]` or a built-in profile such as `:workspace`. Required when permission profiles are active. If an older sandbox setting is active, Codex uses those older sandbox settings instead. |
116| `[permissions.<name>]` | Table | None | Defines a profile and its identifier. `default_permissions` selects one profile as the default; other permission-profile selectors also use the profile name. |
117| `[permissions.<name>.workspace_roots]` | Table | None | Adds profile-defined workspace roots that receive `:workspace_roots` filesystem rules alongside the current session’s runtime workspace roots. |
118| `permissions.<name>.workspace_roots."<path>"` | Boolean | `false` | Adds the path to the profile’s workspace root set when `true`. Entries set to `false` remain inactive. |
119| `[permissions.<name>.filesystem]` | Table | None | Maps filesystem paths to access values or scoped subpath maps. Missing or empty filesystem tables keep filesystem access restricted and emit a startup warning. |
120| `permissions.<name>.filesystem.glob_scan_max_depth` | Number | None | Limits deny-read glob expansion on Linux, WSL, and native Windows when Codex snapshots matches before sandbox startup. Larger values can increase startup scanning work. Use a value of at least `1` when an unbounded `**` pattern needs bounded pre-expansion. |
121| `[permissions.<name>.filesystem]."<path>"` | `read`, `write`, or `deny` | None | Grants direct access for a supported path. `deny` denies access and wins over equally specific `write` or `read` entries. Codex rejects direct write rules that the active runtime cannot enforce. |
122| `[permissions.<name>.filesystem."<path>"]."<subpath>"` | `read`, `write`, or `deny` | None | Grants access to a descendant of `<path>`. Use `.` for the base path. Other subpaths must be relative descendants and cannot contain `.` or `..` components. |
123| `[permissions.<name>.network]` | Table | None | Configures the network sandbox proxy and the sandbox network policy for the profile. |
124| `permissions.<name>.network.enabled` | Boolean | `false` | Enables network access for sandboxed commands in the profile. This changes the sandbox network policy; it does not start the network proxy by itself. |
125| `[permissions.<name>.network.domains]` | Table | None | Maps host patterns to `allow` or `deny`. If there are no `allow` entries, domain requests are blocked. Deny entries override allow entries. |
126| `permissions.<name>.network.domains."<pattern>"` | `allow` or `deny` | None | Supports exact hosts, `*.example.com` for subdomains, `**.example.com` for apex plus subdomains, and `*` as an allow-only global wildcard. Host patterns are normalized by trimming, lowercasing, stripping a trailing dot, and stripping simple ports or brackets. |
127| `[permissions.<name>.network.unix_sockets]` | Table | None | Maps Unix socket allowlist overrides. Use only for local integrations such as Docker. |
128| `permissions.<name>.network.unix_sockets."<path>"` | `allow` or `none` | None | Adds an absolute Unix socket path to the effective allowlist with `allow`, or clears an inherited allow entry with `none`. `none` is not a separate deny-list decision. |
129| `permissions.<name>.network.proxy_url` | URL string | `http://127.0.0.1:3128` | HTTP proxy listener used for `HTTP_PROXY`, `HTTPS_PROXY`, websocket proxy variables, and related tool proxy environment variables. |
130| `permissions.<name>.network.enable_socks5` | Boolean | `true` | Enables the SOCKS5 listener used for `ALL_PROXY` and FTP proxy variables. |
131| `permissions.<name>.network.socks_url` | URL string | `http://127.0.0.1:8081` | SOCKS5 listener address. |
132| `permissions.<name>.network.enable_socks5_udp` | Boolean | `true` | Enables SOCKS5 UDP support when the SOCKS5 listener is enabled. |
133| `permissions.<name>.network.allow_upstream_proxy` | Boolean | `true` | Allows the network sandbox proxy to respect upstream `HTTP(S)_PROXY` and `ALL_PROXY` settings for outbound requests. |
134| `permissions.<name>.network.allow_local_binding` | Boolean | `false` | Disables the local/private-network guard when `true`. When `false`, exact local literals such as `localhost` or `127.0.0.1` must be explicitly allowlisted, and hostnames that resolve to local or private IPs remain blocked. |
135| `permissions.<name>.network.dangerously_allow_non_loopback_proxy` | Boolean | `false` | Allows proxy listeners to bind non-loopback addresses. Leave unset for ordinary local development. |
136| `permissions.<name>.network.dangerously_allow_all_unix_sockets` | Boolean | `false` | Bypasses the Unix socket allowlist where Unix socket proxying is supported. This is a broad local escape hatch. |
137
138## Filesystem permissions
139
140Filesystem entries use `read`, `write`, or `deny`:
141
142| Access | Meaning |
143| --- | --- |
144| `read` | Allows commands to read files and list directories under the path. Commands cannot create, modify, rename, or delete files there. |
145| `write` | Allows commands to read and modify files under the path, including creating, renaming, and deleting files when the OS allows it. |
146| `deny` | Denies both reads and writes under the path. Use it to carve out a denied subpath from a broader `read` or `write` grant. |
147
148More specific entries override broader entries. When two entries target the
149same path, `deny` takes precedence over `write`, and `write` takes precedence
150over `read`.
151
152This precedence lets a profile describe a broad working area first, then carve
153out files or directories that should stay unreadable:
154
155```
156[permissions.project-edit.filesystem]
157":minimal" = "read"
158
159[permissions.project-edit.filesystem.":workspace_roots"]
160"." = "write"
161".devcontainer" = "read"
162"**/*.env" = "deny"
163```
164
165In this example, the workspace root stays writable, `.devcontainer/` stays
166readable without becoming writable, and matching environment files remain
167unavailable to sandboxed commands.
168
169A more specific path can also reopen a narrower subtree inside a broader deny:
170
171```
172[permissions.project-edit.filesystem]
173"~/Documents" = "deny"
174"~/Documents/codex" = "write"
175```
176
177Supported path forms:
178
179| Path | Meaning | Scoped subpaths |
180| --- | --- | --- |
181| `:root` | The filesystem root | `.` only |
182| `:minimal` | Platform and runtime paths needed by common tools | `.` only |
183| `:workspace_roots` | The current session’s workspace roots plus any enabled profile-defined workspace roots | Yes |
184| `:tmpdir` | The `$TMPDIR` location, when one is available | `.` only |
185| `/absolute/path` | A platform absolute path, such as `/path` on macOS/Linux/WSL or `C:\path` on native Windows | Yes |
186| `~/path` | A path under the current user’s home directory | Yes |
187
188On native Windows, home-relative paths can also use backslashes, such as
189`~\work`.
190
191Use `:root` only when a profile intentionally needs broad read coverage:
192
193```
194[permissions.audit.filesystem]
195":root" = "read"
196```
197
198Use nested entries under `:workspace_roots` to scope access to workspace-root
199relative subpaths:
200
201```
202[permissions.project-edit.filesystem.":workspace_roots"]
203"." = "write" # each workspace root
204"docs" = "read" # each workspace-root docs directory
205"generated" = "deny" # each workspace-root generated directory
206```
207
208Nested subpaths must stay inside their workspace root. Parent traversal such as
209`../other-repo` is rejected.
210
211### Deny reads with exact paths or globs
212
213Use `deny` for files or subtrees that Codex should not read, even when a broader
214profile rule grants access nearby. Exact paths work well for stable locations
215such as `~/.ssh`. Glob patterns work better when a profile needs to cover a
216family of sensitive files whose exact locations vary across repositories.
217
218When a glob sits under `:workspace_roots`, Codex interprets it relative to each
219effective workspace root. For example:
220
221```
222[permissions.project-edit.filesystem.":workspace_roots"]
223"**/*.env" = "deny"
224```
225
226This rule denies reads for matching `.env` files found beneath each runtime or
227profile-defined workspace root. Use it when you want to preserve normal
228workspace writes while keeping environment files, generated secrets, or similar
229credential-bearing files unreadable.
230
231`deny` glob patterns are supported as deny-read rules. `read` or `write` globs
232are less portable on Linux, WSL, and native Windows sandboxing, so prefer exact
233paths or subtree rules such as `"docs/**" = "read"` when possible.
234
235On Linux, WSL, and native Windows, an unbounded `**` deny-read pattern may need
236bounded pre-expansion before the sandbox starts. Set `glob_scan_max_depth` when
237you use an unbounded pattern such as `"**/*.env" = "deny"`:
238
239```
240[permissions.project-edit.filesystem]
241glob_scan_max_depth = 3
242
243[permissions.project-edit.filesystem.":workspace_roots"]
244"**/*.env" = "deny"
245```
246
247`glob_scan_max_depth` must be at least `1`. Higher values scan deeper before
248sandbox startup, which can add startup work on Linux, WSL, and native Windows.
249If you prefer not to use bounded expansion, enumerate explicit depths such as
250`*.env`, `*/*.env`, and `*/*/*.env`.
251
252Add reusable workspace roots to the profile when the same rules should apply to
253more than the current session root:
254
255```
256[permissions.project-edit.workspace_roots]
257"~/code/app" = true
258"~/code/shared-lib" = true
259```
260
261When this profile is active, Codex applies the `:workspace_roots` rules to the
262current session’s runtime workspace roots and to each enabled profile-defined
263workspace root.
264
265On native Windows, drive-letter paths such as `D:\work` and UNC paths such as
266`\\server\share` are supported as absolute paths.
267
268## Network permissions
269
270Set `enabled = true` to allow network access for the selected profile:
271
272```
273[permissions.project-edit.network]
274enabled = true
275```
276
277When network access is enabled, Codex uses full network behavior by default.
278Most profiles should also define domain rules:
279
280```
281[permissions.project-edit.network.domains]
282"example.com" = "allow" # exact host
283"*.example.com" = "allow" # subdomains only
284"**.example.com" = "allow" # apex and subdomains
285"ads.example.com" = "deny" # deny wins over allow
286```
287
288The network sandbox proxy binds to local listeners by default:
289
290```
291[permissions.project-edit.network]
292enabled = true
293proxy_url = "http://127.0.0.1:3128"
294enable_socks5 = true
295socks_url = "http://127.0.0.1:8081"
296enable_socks5_udp = true
297```
298
299Leave these listener settings at their defaults unless you are integrating with
300a specific runtime. The `dangerously_*` network keys are escape hatches for
301specialized environments and should not be used for ordinary local development.
302
303### Local and private networks
304
305Codex applies a local/private-network guard by default as a defense against DNS
306rebinding and accidental access to local services. To intentionally allow a
307literal local target, allowlist the exact host or IP literal:
308
309```
310[permissions.project-edit.network.domains]
311"localhost" = "allow"
312"127.0.0.1" = "allow"
313```
314
315Set `allow_local_binding = true` only when the profile must reach allowlisted
316hostnames that resolve to local or private addresses:
317
318```
319[permissions.project-edit.network]
320enabled = true
321allow_local_binding = true
322
323[permissions.project-edit.network.domains]
324"localhost" = "allow"
325```
326
327### Unix sockets
328
329Unix socket proxying is a local escape hatch for tools such as Docker. Use it
330sparingly:
331
332```
333[permissions.project-edit.network.unix_sockets]
334"/var/run/docker.sock" = "allow"
335"/tmp/old.sock" = "none"
336```
337
338Use `none` to clear a socket allow entry inherited from a lower-precedence
339configuration layer. It is not a domain-style deny rule.
340
341When Unix sockets are enabled, keep proxy listeners bound to loopback addresses.
342
343## Migrate from older sandbox settings
344
345Permission profiles replace the older combination of `sandbox_mode` and
346`sandbox_workspace_write` when you want one reusable profile to describe both
347filesystem and network behavior. Use one system or the other for a session, not
348both.
349
350Suggested starting points:
351
352- For a read-only workflow, use the built-in `:read-only` profile or define a
353 custom profile with read access only where needed.
354- For workspace editing, use the built-in `:workspace` profile or define a
355 custom profile that writes through `:workspace_roots` and adds only the extra
356 temp or cache paths the workflow needs.
357- For unrestricted local execution, use `:danger-full-access` only when you
358 intentionally want the broadest local access model.
359
360Profiles describe the local default posture for a session. Organization-managed
361requirements can still add restrictions that user configuration should not
362broaden. See [Managed configuration](https://developers.openai.com/codex/enterprise/managed-configuration)
363for admin-enforced filesystem and network constraints.
364
365## Scope and enforcement
366
367Permission profiles define the boundaries for local sandboxed command
368execution. Use them together with approval policies and the separate controls
369for other Codex surfaces.
370
371### What profiles control
372
373- **Local command execution:** Permission profiles govern sandboxed commands
374 that run on your machine. App connectors, MCP servers, browser or
375 computer-use surfaces, Codex cloud environment settings, and approved
376 escalations use their own controls.
377- **Filesystem writes:** A write-capable profile can create persistent changes.
378 Treat writes to scripts, build steps, package manager hooks, shell startup
379 files, and shared directories as sensitive because later tools or users can
380 execute those files outside the original sandbox context.
381- **Outbound destinations:** Network domain rules constrain where sandboxed
382 command traffic can go through the network proxy. They do not determine
383 whether an allowed destination is trustworthy, and wildcard allow rules stay
384 broad.
385- **Local services:** Local and private network targets are blocked by default.
386 Allowlisting `localhost`, private IPs, Unix sockets, or setting
387 `allow_local_binding = true` explicitly opens access to local services.
388
389### How enforcement works
390
391- On macOS, Codex uses Seatbelt sandbox profiles. If the selected policy cannot
392 be enforced by the platform sandbox, Codex refuses to run the command instead
393 of silently running it unsandboxed.
394- On Linux and WSL, Codex uses [bubblewrap](https://github.com/containers/bubblewrap)
395 and [seccomp](https://www.kernel.org/doc/html/latest/userspace-api/seccomp_filter.html),
396 with Landlock available for compatibility fallback paths. The strongest
397 enforcement path depends on user namespaces and kernel support; restricted
398 container hosts can force compatibility paths, and unsupported split policies
399 are refused.
400- On native Windows, [`elevated` sandboxing](https://developers.openai.com/codex/windows#windows-sandbox)
401 is strongest because it can use dedicated lower-privilege sandbox users,
402 filesystem permission boundaries, and firewall rules. `unelevated`
403 sandboxing is a fallback with weaker network isolation and cannot enforce
404 every split read/write carveout, so unsupported policies are refused. Use WSL
405 when you need the Linux sandbox model.
406
407### Operational guidance
408
409Choose the narrowest profile that still lets the task complete, especially when
410you grant writes or outbound network access. Keep approval policy, secret
411handling, and allow rules aligned with that access level.
412
413## Common profiles
414
415### Read-only with network allowlist
416
417```
418default_permissions = "readonly-net"
419
420[permissions.readonly-net.filesystem]
421":minimal" = "read"
422
423[permissions.readonly-net.filesystem.":workspace_roots"]
424"." = "read"
425
426[permissions.readonly-net.network]
427enabled = true
428
429[permissions.readonly-net.network.domains]
430"api.openai.com" = "allow"
431```
432
433### Workspace write without network
434
435```
436default_permissions = "project-edit"
437
438[permissions.project-edit.filesystem]
439":minimal" = "read"
440
441[permissions.project-edit.filesystem.":workspace_roots"]
442"." = "write"
443
444[permissions.project-edit.network]
445enabled = false
446```
447
448### Workspace write with public web access
449
450```
451default_permissions = "workspace-net"
452
453[permissions.workspace-net.filesystem]
454":minimal" = "read"
455
456[permissions.workspace-net.filesystem.":workspace_roots"]
457"." = "write"
458
459[permissions.workspace-net.network]
460enabled = true
461
462[permissions.workspace-net.network.domains]
463"*" = "allow"
464```
465
466Use the global `"*"` allow rule only when you intend to allow public network
467access. Deny rules can narrow a broad allowlist.
468