[BUG] Bash sandbox fabricates phantom unreadable files when a hidden/denyRead path doesn't exist — breaks dotnet/SourceLink builds
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Environment
Claude Code 2.1.162
Linux, WSL2 (kernel 6.6.87.2-microsoft-standard-WSL2)
Bash sandbox enabled (bubblewrap)
Summary
The bash sandbox hides certain dotfiles by overlaying /dev/null on them (.gitmodules, .gitconfig, .bashrc, …). When a hidden path doesn't exist in the workspace, the overlay creates a phantom directory entry — a /dev/null character device. Because the sandbox root is mounted nodev, that device node can't be opened, so the phantom file is unreadable (EACCES) rather than absent. Tools that probe-then-read the file fail, even though it legitimately doesn't exist.
Real-world impact
dotnet build of any SourceLink-enabled project (the default for many SDK projects) in a repo without .gitmodules:
error : Error reading git repository information:
Access to the path '.../.gitmodules' is denied.
[.../Microsoft.Build.Tasks.Git.targets(25,5)]
The identical build succeeds outside the sandbox.
Misleading symptom
Under the default multi-node MSBuild, the worker-node error is dropped and the only output is:
Build FAILED.
0 Warning(s)
0 Error(s)
(exit 1, no diagnostics). dotnet build -m:1 is required to surface the real error — worth noting because the default failure mode gives zero clue.
Root cause
The file-hiding mechanism (overlaying /dev/null on each mask-list path) is applied regardless of whether the target exists. For a non-existent target the bind-mount materializes a phantom char device, and on the nodev sandbox root it's unreadable. Net effect: "file absent" (which tools handle gracefully) becomes "file present but unreadable" (which they don't). Note also that masked files do not read as empty here — the documented "empty file" semantics aren't achieved on a nodev mount; reads return EACCES.
What Should Happen?
Suggested fix
stat each mask-list path first and skip the overlay for paths that don't exist on the real filesystem (only mask extant files). Alternatively, mask via an empty regular file so reads return empty/EOF instead of EACCES.
Error Messages/Logs
Steps to Reproduce
Minimal repro
In a sandboxed bash session, in any directory with no .gitmodules:
$ ls -la .gitmodules
crw-rw-rw- 1 nobody nogroup 1, 3 ... .gitmodules # phantom /dev/null device
$ cat .gitmodules
cat: .gitmodules: Permission denied
Expected: No such file or directory.
Claude Model
Opus
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.162 (Claude Code)
Platform
Anthropic API
Operating System
Ubuntu/Debian Linux
Terminal/Shell
WSL (Windows Subsystem for Linux)
Additional Information
_No response_
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗