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)
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
sandboxPolicywithwritableRootsis acknowledged inturn_contextbut the extra roots are not enforced in the exec seatbelt. - Config-level
sandbox_workspace_write.writable_rootsis not applied when an explicit turn policy is present (the turn policy replaces it), whilenetwork_accessand the exclude flags do take effect. (codex sandboxCLI honors config-levelwritable_roots; the app-server turn exec does not.)
Ask
- Fix permission-profile application so profile-based sandboxes can exec (the SIGABRT above).
- Or/and: provide a supported, documented opt-in for git-directory writability under
workspace-writefor orchestrated use (equivalently: honor turn-policywritableRootsin 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
1 Comment
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, cleandefault_permissions refers to undefined profileerror |read-onlymode aborts too, so it is not aworkspace-writeinteraction.Also possibly useful: on 0.144.1,
codex sandboxrequires--permission-profile(omitting it exits 2 withthe 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 everycodex sandboxinvocation 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. Pinningsandbox_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.