permissions.<id>.network.unix_sockets config not propagated to macOS Seatbelt policy

Open 💬 2 comments Opened May 31, 2026 by naoto256

Summary

The canonical permissions schema accepts permissions.<id>.network.unix_sockets (per #15120) and codex doctor reports the config as loaded with no warnings, but the allowlist is never injected into the generated Seatbelt SBPL. Connecting to a listed AF_UNIX socket from a sandboxed child still produces a network-outbound denial.

The equivalent CLI flag --allow-unix-socket (from #17654) works correctly, which confirms the Seatbelt-side machinery is fine — only the config → SBPL wiring is missing.

Version

codex-cli 0.135.0-alpha.1
Codex.app on macOS 26.5 (aarch64)

Repro

~/.codex/config.toml:

default_permissions = "uds-test"

[permissions.uds-test]
extends = ":workspace"

[permissions.uds-test.network.unix_sockets]
"/tmp/.X11-unix" = "allow"
$ codex doctor | grep config
  ✓ config       loaded     # no warnings, profile recognized

$ codex sandbox --permissions-profile uds-test --log-denials -- \
    python3 -c 'import socket; s=socket.socket(socket.AF_UNIX); s.connect("/tmp/.X11-unix/X0")'
ERR PermissionError [Errno 1] Operation not permitted

=== Sandbox denials ===
(Python) network-outbound /tmp/.X11-unix/X0

The same socket via the CLI flag works:

$ codex sandbox --permissions-profile uds-test \
    --allow-unix-socket /tmp/.X11-unix -- \
    python3 -c 'import socket; s=socket.socket(socket.AF_UNIX); s.connect("/tmp/.X11-unix/X0")'
# OK

Other schema variants I tried (none work)

All accepted by the config loader, none reach Seatbelt:

  • permissions.<id>.network.unix_sockets = { "/path" = "allow" } — canonical per #15120
  • permissions.<id>.network.allow_unix_sockets = ["/path"] — legacy array form
  • permissions.<id>.experimental_network.unix_sockets = {...}
  • permissions.<id>.experimental_network.dangerously_allow_all_unix_sockets = true
  • permissions.<id>.network.network_access = true (also not wired)
  • Top-level experimental_network.unix_sockets
  • Top-level experimental_network.allow_unix_sockets

The only working config-side switch I found is the legacy, pre-profile path:

sandbox_mode = "workspace-write"
[sandbox_workspace_write]
network_access = true

…but that opens the entire network namespace, which is exactly the over-reach #15120's unix_sockets map was meant to avoid.

Expected

A permissions.<id>.network.unix_sockets entry on the active profile should produce the same SBPL allow rules as --allow-unix-socket:

(allow network-bind     (local  unix-socket (subpath "...")))
(allow network-outbound (remote unix-socket (subpath "...")))

Notes

  • On my install, only :workspace was a recognized built-in; extends = ":workspace-write" failed with "cannot extend unsupported built-in profile". Documenting which built-ins ship per build flavor would help.
  • Defining [permissions.workspace-write] directly (without extends) triggers the warning "Permissions profile workspace-write does not define any recognized filesystem entries" and silently strips the built-in filesystem defaults — that footgun is a separate UX concern.
  • Linux side has its own open issue (#16910); this one is specifically about the macOS Seatbelt path being half-wired.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗