[BUG] 2.1.281: scrub sandbox still fails to create ancestor .claude stub when the ancestor is owned by another uid (as root, --cap-drop ALL)
What's wrong
With CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1, every Bash tool call fails before the command runs:
bwrap: Can't mkdir /root/actions-runner-2/.claude: Permission denied
This looks like a variant of #79997 (fixed in 2.1.227) that still occurs on 2.1.281.
Environment
- Claude Code 2.1.281 (native), Ubuntu 24.04, kernel 6.8, bubblewrap 0.9.0,
kernel.apparmor_restrict_unprivileged_userns=0. - Claude runs as root. The cwd is
/root/actions-runner-2/_work/<repo>/<repo>(a second self-hosted GitHub Actions runner). /root/actions-runner-2is owned by uid 1001 with mode 755, as extracted from GitHub's runner tarball. All directories below it are owned by root.
Cause (from the captured bwrap argv)
The sandbox adds denyWrite entries for <ancestor>/.claude (and .mcp.json) at every ancestor of the cwd, and for missing paths it adds --ro-bind /tmp/claude-empty-XXXX <ancestor>/.claude. bwrap runs with --unshare-user --cap-drop ALL. Inside that user namespace, uid 1001 is unmapped, so root has no DAC override on /root/actions-runner-2 and cannot create the mount-point stub. The stubs under root-owned ancestors (_work/.claude, _work/<repo>/.claude) are fine.
A minimal bwrap test on the same host shows the same result:
bwrap --unshare-pid --unshare-user --cap-drop ALL --ro-bind / / --bind /tmp /tmp \
--ro-bind /tmp/empty /tmp/t/u1001/.claude true # fails: Can't mkdir ... Permission denied
# same command with /tmp/t/u0 (owned by root) succeeds
Expected
A missing ancestor stub that cannot be created should not kill every Bash call. For example, the fix from #79997 could also cover ancestors that the process owner cannot write to inside the user namespace, not only root-owned ancestors seen by a non-root user.
Related
- #79997
- #97730 (the same runner host, where
$HOME/actions-runneris also denied)
---
Created with LLM: Opus 5.5 | medium | Harness: Claude Code