Skip to content

sandbox-exec nesting fails when host tool (e.g. Claude Code) also uses sandbox-exec #84

@umiyosh

Description

@umiyosh

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

  1. Launch an application via cage auto-presets (e.g. claude → base + git-enabled + claude-code)
  2. The application internally uses sandbox-exec for its own command sandboxing (Claude Code's Bash tool)
  3. Inner sandbox-exec call fails because macOS does not support nesting sandbox-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:16 runInSandbox() — generates and applies profile without nesting check
  • main.go:127 main() — sets IN_CAGE env 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-nested flag
  • 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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions