[BUG] Sandbox blocks its own zsh `eval` wrapper — every Bash command fails with exit 126
Bug Description
# [BUG] Sandbox blocks its own zsh eval wrapper — every Bash command fails with exit 126
## Environment
- Claude Code version: 2.1.209
- OS: macOS (Darwin 25.5.0), sandbox backend: Apple Seatbelt (/usr/bin/sandbox-exec)
- Login shell: zsh (macOS default)
- Install: native CLI, interactive session
## Summary
With sandbox.enabled: true and zsh as the user shell, 100% of Bash tool commands fail with exit code 126, including trivial ones like pwd. The sandbox's own static security filter ("Command uses eval or $()/ backticks at command position") rejects the eval-based wrapper that Claude Code itself generates for zsh. The sandbox blocks itself.
## Minimal reproduction
1. macOS machine whose login shell is zsh (the default).
2. ~/.claude/settings.json:
``json
{ "sandbox": { "enabled": true } }
`
3. Let Claude run any Bash tool command, e.g. pwd.
Nothing else is required — reproduces without hooks, permission rules, or plugins. Also reproduces when the sandbox is enabled via the /sandbox UI command with "regular bash permissions".
**Verified with hooks disabled:** re-ran the repro with "disableAllHooks": true — the failure is byte-for-byte identical, same decoded eval wrapper in the LogTag. Also tested with "disableAllHooks": false — same result. Hooks are not involved; the block occurs in the sandbox layer before any hook could run.
## Expected behavior
The command runs inside the Seatbelt sandbox and succeeds.
## Actual behavior
Every command fails immediately:
Exit code 126
[BLOCKED — DO NOT RETRY] Command uses eval or $()/ backticks at command
position, which is blocked regardless of allowlist. This is a permanent
security restriction, not a transient error.
text
## Root cause analysis
The Seatbelt profile embeds the wrapped command as a base64 LogTag. Decoding it for the pwd repro shows the wrapper Claude Code generates for zsh:
setopt NO_EXTENDED_GLOB NO_BARE_GLOB_QUAL 2>/dev/null || true && eval pwd < /dev/null && pwd -P >| /...
text
The zsh compatibility wrapper places eval in command position **by design**. The sandbox's static analyzer then rejects any command with eval in command position "regardless of allowlist". The two components are mutually exclusive: on zsh, no command can ever pass.
Notes:
- sandbox.failIfUnavailable: true does not catch this — the sandbox initializes "successfully"; only command execution is broken.
- The user-facing effect is that users conclude the sandbox is broken and disable it entirely ("enabled": false), which is a net security regression — the opposite of the feature's intent.
## Workaround
Disable the sandbox (sandbox.enabled: false) and rely on permission deny rules + hooks. Untested alternative: launching with SHELL=/bin/bash claude so the zsh wrapper is not used.
## Possibly related (but distinct) issues
- anthropics/claude-code#22241 — zsh "operation not permitted" on /tmp/claude-{UID}/cwd-*` (commands still succeeded there; here they hard-fail)
- anthropics/claude-code#22109 — zsh cwd-tracking sandbox noise
- anthropics/claude-code#28479 — zsh shell initialization handling
Environment Info
- Platform: darwin
- Terminal: Apple_Terminal
- Version: 2.1.209
- Feedback ID: 966943a8-670b-4291-9d97-464ce5592a8f
Errors
[]