Skip to content

fix(sandbox): run containers as host user instead of root#355

Merged
asheshgoplani merged 4 commits intoasheshgoplani:mainfrom
johnuopini:feat/sandbox-user-namespace
Mar 18, 2026
Merged

fix(sandbox): run containers as host user instead of root#355
asheshgoplani merged 4 commits intoasheshgoplani:mainfrom
johnuopini:feat/sandbox-user-namespace

Conversation

@johnuopini
Copy link
Copy Markdown
Contributor

Summary

  • Add --user <uid>:<gid> to docker create so sandbox containers run as the host user instead of root
  • Set HOME=/root explicitly since the host UID has no /etc/passwd entry in the container
  • chmod 755 /root in the Dockerfile so the non-root user can traverse to installed binaries

Problem

--cap-drop=ALL drops DAC_OVERRIDE, which prevents root from reading files it doesn't own. Sandbox file sync (sandbox.go) creates files owned by the host user (UID 1000, mode 0600). The container runs as root (UID 0), so root can't read .credentials.json, settings.json, etc. — causing Claude to hang on startup.

Fix

Run the container as the host user (--user uid:gid) instead of root. This is cleaner than re-adding DAC_OVERRIDE because:

  • Maintains full --cap-drop=ALL hardening
  • Principle of least privilege (no root inside container)
  • Files are naturally readable (container user = file owner)

--dangerously-skip-permissions continues to work because Claude Code gates it via IS_SANDBOX=1 env var, not a UID check.

Test plan

  • All internal/docker unit tests pass (3 new tests for HOME env var)
  • Manual: rebuilt sandbox image, verified non-root user reads 0600 bind-mounted files with --cap-drop=ALL
  • Manual: verified claude --version works inside container as non-root user
  • Manual: full end-to-end sandbox session starts and Claude runs without hanging

--cap-drop=ALL drops DAC_OVERRIDE, preventing root from reading
bind-mounted files owned by the host user. Run as --user uid:gid
so the container process owns the files naturally.
The host UID has no /etc/passwd entry inside the container, so HOME
defaults to /. Explicitly set HOME to containerHome so tools find
their config directories.
The container now runs as the host user instead of root. /root must
be traversable (execute bit) so the non-root user can reach installed
binaries at /root/.local/bin/ and /root/.opencode/bin/.
@asheshgoplani asheshgoplani merged commit 070f6f6 into asheshgoplani:main Mar 18, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants