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 main — IS_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)
Summary
ocx claude --dangerously-skip-permissionsaborts 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 reasonsunless 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
Expected: the Claude session starts and prints
ok.Actual: immediate fatal exit with the root-guard message.
Logs and screenshots
Area
CLI
Version
2.14.2 (also on current
main—IS_SANDBOXdoes not appear anywhere insrc/)OS
Ubuntu 24.04 (root user)
Config shape
N/A (CLI invocation only)
Root cause
src/cli/claude.tsbuildClaudeEnvdoes not setIS_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 signalIS_SANDBOX=1so the binary allows the bypass. Without it, every root-hosted deployment ofocx claudewith permissions bypass is unusable.Proposed fix
In
buildClaudeEnv, beforereturn 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;setDefaultsemantics already guarantee the user can override (IS_SANDBOX=0exported by the user wins), so this is an opt-out-by-env design, not a forced change.Alternatives considered
IS_SANDBOX) for exactly this case.CLAUDE_CODE_BUBBLEWRAP: heavier, not portable;IS_SANDBOXis 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:
--dangerously-skip-permissions→ session starts (200 / prints)IS_SANDBOX=0→ original guard behavior preserved (user opted out)IS_SANDBOXinjected)