-
Notifications
You must be signed in to change notification settings - Fork 5
Open
Description
Problem
When a process launched via cage (outer sandbox) spawns child commands that are also wrapped in sandbox-exec (inner sandbox), the inner sandbox fails with:
sandbox-exec: sandbox_apply: Operation not permitted
Exit code 71. Every Bash command fails regardless of path.
Reproduction
- Launch an application via cage auto-presets (e.g.
claude→ base + git-enabled + claude-code) - The application internally uses
sandbox-execfor its own command sandboxing (Claude Code's Bash tool) - Inner
sandbox-execcall fails because macOS does not support nestingsandbox-exec
Root cause
main.go:129 sets IN_CAGE=1 but never checks it. There is no mechanism to detect or prevent sandbox nesting.
// main.go:128-132
func main() {
// Indicate that we are running inside a cage
if err := os.Setenv(inCageEnv, "1"); err != nil { ... }sandbox_darwin.go:34 unconditionally applies sandbox-exec:
return syscall.Exec(sandboxPath, args, os.Environ())Affected code paths
sandbox_darwin.go:16runInSandbox()— generates and applies profile without nesting checkmain.go:127main()— setsIN_CAGEenv var but doesn't check it on entry
Proposed solution
Add nest detection: if IN_CAGE=1 is already set when cage starts, skip sandbox-exec and directly exec the command.
func main() {
// Detect nesting — if already inside cage, exec directly
if os.Getenv(inCageEnv) == "1" {
cmd := args[0]
cmdPath, err := exec.LookPath(cmd)
if err != nil { ... }
syscall.Exec(cmdPath, args, os.Environ())
return
}
// Normal cage flow...
os.Setenv(inCageEnv, "1")
...
}Alternative or complementary approaches:
- Add a
--skip-if-nestedflag - Add a config option
nest-behavior: skip | error | warn - Document that applications with their own sandbox-exec (Claude Code, etc.) should not be auto-preset targets
Environment
- macOS Sequoia (Darwin 24.6.0)
- cage built from main branch (commit 9105203)
- Host tool: Claude Code (uses sandbox-exec internally for Bash command sandboxing)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels