Skip to content

[Bug]: ocx claude --dangerously-skip-permissions aborts as root (uid==0) because IS_SANDBOX is never set #1688

Description

@rrmlima

Summary

ocx claude --dangerously-skip-permissions aborts immediately when running as root (uid == 0), which is the default on most VPS deployments. Claude Code 2.1.205+ embeds a safety guard that exits with --dangerously-skip-permissions cannot be used with root/sudo privileges for security reasons unless it believes it runs inside a sandbox (IS_SANDBOX=1) or a bubblewrap wrapper is present. The opencodex proxy launches the session, so it should mark the environment accordingly.

Reproduction

# As root (typical VPS):
ocx claude --dangerously-skip-permissions --print "ok"

Expected: the Claude session starts and prints ok.
Actual: immediate fatal exit with the root-guard message.

Logs and screenshots

--dangerously-skip-permissions cannot be used with root/sudo privileges for security reasons

Area

CLI

Version

2.14.2 (also on current mainIS_SANDBOX does not appear anywhere in src/)

OS

Ubuntu 24.04 (root user)

Config shape

N/A (CLI invocation only)

Root cause

src/cli/claude.ts buildClaudeEnv does not set IS_SANDBOX. The guard is in the official Claude Code binary, not in opencodex — but since the proxy owns the launched session (a controlled, proxy-launched environment), it must signal IS_SANDBOX=1 so the binary allows the bypass. Without it, every root-hosted deployment of ocx claude with permissions bypass is unusable.

Proposed fix

In buildClaudeEnv, before return env;:

   for (const [name, value] of Object.entries(effectiveModelEnv(config.claudeCode, contextWindows, auto))) {
     setDefault(name, value);
   }
+  // Root bypass guard (Claude Code 2.1.205+): the CLI refuses --dangerously-skip-permissions
+  // when uid==0 unless it believes it runs inside a sandbox. Servers are commonly root, so
+  // treat the proxy-launched session as one — opt out by exporting IS_SANDBOX=0 yourself.
+  if (typeof process.getuid === "function" && process.getuid() === 0) {
+    setDefault("IS_SANDBOX", "1");
+  }
   return env;

setDefault semantics already guarantee the user can override (IS_SANDBOX=0 exported by the user wins), so this is an opt-out-by-env design, not a forced change.

Alternatives considered

  • Document "run as non-root": impractical on VPS setups where the service owns root files, and Claude Code already provides the sandbox escape hatch (IS_SANDBOX) for exactly this case.
  • Require CLAUDE_CODE_BUBBLEWRAP: heavier, not portable; IS_SANDBOX is the documented, minimal signal.

Additional context

The same pattern is used by other proxy-launcher tools: the session is a controlled environment created by the parent process, so marking it as sandboxed for the child's safety guard is accurate and safe. The user opt-out (IS_SANDBOX=0) preserves the strict behavior for anyone who wants it.

Test matrix:

  • root + --dangerously-skip-permissions → session starts (200 / prints)
  • root + exported IS_SANDBOX=0 → original guard behavior preserved (user opted out)
  • non-root → unchanged (no IS_SANDBOX injected)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingcliCLI, config inject, packaging flagsneeds-infoWaiting on reporter for a concrete spec or reproduction

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions