No path to full autonomy when running as root (uid=0)

Resolved 💬 3 comments Opened May 12, 2026 by Halyxa Closed May 12, 2026

Summary

When running Claude Code as root (uid=0), there is no permission mode that allows full autonomous operation:

  • --dangerously-skip-permissions → Hard exit with code 1: "cannot be used with root/sudo privileges for security reasons"
  • --permission-mode dontAsk → Runs, but silently denies writes to protected paths (.claude/ directories, agent definitions, config files) regardless of permissions.allow settings
  • --permission-mode default → Prompts for approval on every operation (not viable for unattended use)

Operators running as root are forced into dontAsk, where writes to .claude/agents/, .claude/settings.json, and other protected paths silently fail — even with "allow": ["Write(*)"] in settings.json.

Root cause (from source, cli.js v2.1.139)

if (permissionMode === "bypassPermissions" || dangerouslySkipPermissions) {
  if (process.platform !== "win32"
      && typeof process.getuid === "function"
      && process.getuid() === 0
      && process.env.IS_SANDBOX !== "1"
      && process.env.CLAUDE_CODE_BUBBLEWRAP !== "1") {
    console.error(
      "--dangerously-skip-permissions cannot be used with root/sudo privileges for security reasons"
    );
    process.exit(1);
  }
}

Two env var escape hatches exist (IS_SANDBOX=1, CLAUDE_CODE_BUBBLEWRAP=1) but are undocumented with unclear side effects.

Per the Claude Code docs: "In every mode except bypassPermissions, writes to protected paths are never auto-approved." This confirms dontAsk + Write(*) cannot authorize protected path writes by design.

Why root access is needed

Infrastructure management inherently requires root: systemd services, ZFS pools, firewall rules (UFW), reverse proxy config (Traefik), SSL certificates (certbot), port binding below 1024. This applies to any operator using Claude Code for server management on AWS EC2, DigitalOcean, GCP, Docker containers, or dedicated servers.

The workaround degrades your safety instrumentation

When Write is denied, operators route through Bash(cat > file << 'EOF'). This succeeds — Bash(*) is allowed and cat runs as root with full filesystem access. But:

  • The same file gets written either way
  • Via Write tool: Claude Code logs target path, content, and previous content in structured form
  • Via Bash(cat >): An opaque shell command — your audit trail, safety monitoring, and tool-level instrumentation lose visibility into file operations

The root override doesn't prevent file writes as root. It pushes them into a less observable channel.

Reproduction

# As root (uid=0):

# Attempt 1: bypassPermissions
claude --dangerously-skip-permissions
# → "cannot be used with root/sudo privileges for security reasons"
# → exit code 1

# Attempt 2: dontAsk (the forced alternative)
claude --permission-mode dontAsk
# → runs, but:
echo '{"content":"test"}' | claude -p "Write this to .claude/agents/test.md"
# → "Permission to use Write has been denied because Claude Code is running in don't ask mode"

# Attempt 3: Bash workaround (succeeds for the same operation)
echo 'test' | claude -p "Run: cat > .claude/agents/test.md <<< 'test content'"
# → succeeds, file written as root

Environment

  • Claude Code CLI 2.1.139
  • Ubuntu 24.04.4 LTS (single-tenant Proxmox VM)
  • Existing safety: 12 explicit deny rules (rm -rf /, zpool destroy, dd, mkfs, etc.), ZFS snapshots for instant rollback

Request

In order of preference:

  1. Allow bypassPermissions as root when the operator has explicitly configured it in settings.json. The double opt-in (config + CLI flag) is already informed consent. The deny list handles destructive operations.
  1. Document the IS_SANDBOX / CLAUDE_CODE_BUBBLEWRAP escape hatches — if these are the intended path for root users, document what they do and whether they're stable API.
  1. Add a --trust-root flag following the existing dangerouslyDisableSandbox precedent in the Bash tool schema. Named, explicit, scary.
  1. At minimum, document the restriction — it's currently undiscoverable. Not in claude --help, not in the permission mode docs, not in any changelog. Operators find out only at runtime.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗