macOS: activating any [permissions] profile makes sandboxed exec abort (SIGABRT, silent) — blocks the only opt-out for protected .git under workspace-write (0.144.6 + 0.145.0)

Open 💬 1 comment Opened Jul 26, 2026 by hillarylinmd

Summary

On macOS (Apple Silicon), defining any [permissions.<name>] profile and activating it — via -P <name> on codex sandbox, or via default_permissions in config.toml — makes the sandboxed child process abort before exec (SIGABRT, no output, no denial log). Reproduced on codex-cli 0.144.6 and 0.145.0 (npm @openai/codex, darwin-arm64).

This matters beyond the crash itself: the permissions-profile explicit-rule mechanism appears to be the only way to relax the default read-only protection of a workspace's git directory under workspace-write (append_default_read_only_project_root_subpath_if_no_explicit_rule in codex-rs/protocol/src/permissions.rs). With profiles aborting, there is no working opt-out, so orchestrated/unattended agents (e.g. an openai/symphony-style orchestrator driving codex via app-server) cannot git add/commit/push in their own workspace under any configuration we could find.

Repro (model-free, codex sandbox)

mkdir -p /tmp/repro && cd /tmp/repro && git init -q . && echo x > f.txt

# Baseline (no [permissions] table): exec works
codex sandbox -- sh -c 'echo ALIVE'          # prints ALIVE

# Any permissions profile: child aborts before exec, silently
export CODEX_HOME=/tmp/repro-home && mkdir -p "$CODEX_HOME"
cat > "$CODEX_HOME/config.toml" <<'EOF'
default_permissions = "p1"

[permissions.p1]

[permissions.p1.filesystem]
"/tmp/repro/.git" = "write"
EOF
codex sandbox -P p1 -- sh -c 'echo ALIVE'    # no output; child exits via SIGABRT
codex sandbox -- sh -c 'echo ALIVE'          # same (default_permissions active): no output

Also reproduces with an empty profile ([permissions.p1] with only a description). Adding a [permissions.p1.workspace_roots] table produces the same abort. --log-denials prints the "Sandbox denials" header with no entries (the abort happens at/before sandbox apply, not as a file denial).

Context: what we were actually trying to do

Under workspace-write, git-metadata writes fail (fatal: Unable to create '<repo>/.git/index.lock': Operation not permitted). We verified the protection is thorough — it covers .git at any depth, and follows a .git gitfile pointer to a separate git dir of any name (nice work — name-based dodges don't slip past it). That makes the profile explicit-rule path the intended relaxation mechanism, and it is unreachable while profiles abort.

Two related observations from the app-server lane (codex 0.144.6, orchestrated use):

  • An explicit per-turn sandboxPolicy with writableRoots is acknowledged in turn_context but the extra roots are not enforced in the exec seatbelt.
  • Config-level sandbox_workspace_write.writable_roots is not applied when an explicit turn policy is present (the turn policy replaces it), while network_access and the exclude flags do take effect. (codex sandbox CLI honors config-level writable_roots; the app-server turn exec does not.)

Ask

  1. Fix permission-profile application so profile-based sandboxes can exec (the SIGABRT above).
  2. Or/and: provide a supported, documented opt-in for git-directory writability under workspace-write for orchestrated use (equivalently: honor turn-policy writableRoots in app-server turn exec so an orchestrator can grant it deliberately).

Environment

  • codex-cli 0.144.6 and 0.145.0 (npm), darwin-arm64
  • macOS 15.x, Apple Silicon (Mac mini)
  • Repro is host-local codex sandbox; no model calls involved

View original on GitHub ↗

1 Comment

czexan · 25 days ago

Independent reproduction on Intel macOS, and on an earlier CLI version than the two reported — so this is neither arm64-specific nor a regression introduced in 0.144.6.

Environment: codex-cli 0.144.1 (npm @openai/codex, darwin-x64), macOS 15.7.7, Intel.

Result: identical to the report — silent SIGABRT (exit 134), no output, no denial log, child never execs.

Three additional data points that narrow where the abort happens:

| Variant | Exit |
|---|---|
| profile + default_permissions | 134 |
| profile, no default_permissions (only -P) | 134 |
| profile with a completely EMPTY [permissions.<name>.filesystem] table | 134 |
| sandbox_mode = "read-only" + profile | 134 |
| -P nosuchprofile | 1, clean default_permissions refers to undefined profile error |

  1. An empty filesystem table aborts identically, so the fault is not in compiling any particular rule — it is in activating a profile at all. This matches your "also reproduces with an empty profile" note and extends it to an empty filesystem sub-table.
  2. A nonexistent profile name errors cleanly (exit 1). Config parsing and profile resolution are therefore healthy; the abort is downstream of resolution, at sandbox application.
  3. read-only mode aborts too, so it is not a workspace-write interaction.

Also possibly useful: on 0.144.1, codex sandbox requires --permission-profile (omitting it exits 2 with the following required arguments were not provided: --permission-profile <NAME>). So the profile-less baseline in your repro (codex sandbox -- sh -c 'echo ALIVE') is not available on this version — on 0.144.1 every codex sandbox invocation must activate a profile, which means the subcommand cannot execute a child at all here.

A stray observation from the same session, offered only in case it points somewhere: the backtrace printed on the clean exit-1 path symbolizes to unrelated functions (std::fs::File::set_times, then AES/cipher symbols on a config-error path), and none of the six SIGABRTs produced a crash report in ~/Library/Logs/DiagnosticReports. Both may just be release-build symbol folding rather than a signal.

Workaround for anyone landing here: the abort only affects [permissions.*] profiles. Pinning sandbox_mode = "workspace-write" with [sandbox_workspace_write] writable_roots = [...] still works and gives write-confinement (cwd plus the listed roots) — it just cannot express the read-side denials that profiles were the only route to.