Sandbox masking placeholders are created in the project working directory instead of $HOME, appearing as untracked files on every Bash command

Status Open
Reported on v2.1.220
Maintainer reply ✓ Yes — bcherny
Activity 3 comments · opened Aug 3, 2026
💡 Likely answer: A maintainer (bcherny, collaborator) responded on this thread — see the highlighted reply below.

Summary

With the Bash sandbox enabled on Linux, every sandboxed command creates nine zero-byte dotfiles at the root of the current working directory, then removes them when the command finishes. When the working directory is a git repository, these appear as untracked files for the duration of each command, so the SCM view and any file watcher see them repeatedly appear and disappear.

The files are the sandbox's masking placeholders for shell-init and config paths. They are being created relative to the working directory instead of $HOME.

Environment

  • Claude Code 2.1.220 (VS Code extension anthropic.claude-code)
  • Linux (Ubuntu), bubblewrap 0.11.1, @anthropic-ai/sandbox-runtime 0.0.67
  • Working directory: a git worktree
  • sandbox.enabled: true, allowUnsandboxedCommands: false

Steps to reproduce

  1. Enable the Bash sandbox on Linux.
  2. Open a git repository as the working directory.
  3. Run any sandboxed Bash command.
  4. Watch the repository root, or git status, while the command runs.

Observed

Nine files appear at the repository root, all zero bytes and mode 444:

-r--r--r-- 1 glen glen 0  .bash_profile
-r--r--r-- 1 glen glen 0  .bashrc
-r--r--r-- 1 glen glen 0  .gitconfig
-r--r--r-- 1 glen glen 0  .gitmodules
-r--r--r-- 1 glen glen 0  .idea
-r--r--r-- 1 glen glen 0  .profile
-r--r--r-- 1 glen glen 0  .ripgreprc
-r--r--r-- 1 glen glen 0  .zprofile
-r--r--r-- 1 glen glen 0  .zshrc

git status reports them as untracked:

?? .bash_profile
?? .bashrc
?? .gitconfig
?? .gitmodules
?? .idea
?? .profile
?? .ripgreprc
?? .zprofile
?? .zshrc

They are removed when the command completes, so the SCM view flickers between counts as commands run. They are visible to host-side tooling while they exist — this was first noticed via the VS Code Source Control panel, not from inside the sandbox.

Evidence that this is a path-resolution issue

.zshenv and .zlogin are absent from the list above. Those two are declared in user settings as sandbox.filesystem.denyWrite: ["~/.zshenv", "~/.zprofile", "~/.zlogin"], i.e. with a ~/ prefix, and they resolve to $HOME correctly.

The nine that do appear correspond to the built-in shell-init/config protections rather than to anything declared in settings. Per the documented path-prefix rules, a path with no prefix resolves relative to the project root — which matches the observed behavior exactly.

The home-directory paths remain correctly protected, so this is the placeholder creation being misplaced rather than protection being lost:

/home/glen/.zshrc        denied (read-only file system)
/home/glen/.zshenv       denied
/home/glen/.bashrc       denied
/home/glen/.gitconfig    denied

Expected

Masking placeholders should be created outside the project tree — e.g. in the session temp directory — and the built-in deny paths for home dotfiles should resolve against $HOME rather than the working directory. Running a Bash command should not create files inside the user's repository.

Impact

  • Files are created inside the user's repository as a side effect of running any Bash command, and are visible to host-side tools while they exist.
  • Continuous SCM and file-watcher churn in any repo used with the sandbox enabled.
  • A git add -A (or any tooling that stages broadly) issued while a sandboxed command is in flight can pick them up.
  • A zero-byte .gitmodules at a repository root can shadow a tracked one. Harmless in a repo with no submodules; in a repo that uses them, git submodule operations would see an empty file for the duration of each command.
  • A zero-byte file named .idea conflicts with the JetBrains project directory of the same name.

---

_Drafted by Claude (Anthropic AI assistant)._

View original on GitHub ↗

3 Comments

glen-84 · 27 days ago

Related prior art: #72748 looks like the same cwd-relative mask-path resolution, surfacing as a hard failure instead of silent file creation — bwrap cannot create a placeholder at .git because a directory already exists at that path. Where nothing exists, as with the dotfiles above, creation succeeds and the file is visible to host-side tooling for the duration of each command.

#79997 and #80284 appear to be the same class of mask-path construction problem.

If maintainers consider this a duplicate of #72748, no objection — the two symptoms look like one cause seen from opposite sides.

_Drafted by Claude (Anthropic AI assistant)._

andyabsww · 16 days ago

I see the same nine placeholders, same 444 mode — but here they are not ephemeral. They persisted on disk for hours, across multiple sessions, and were still present after every Claude Code session had ended. Confirmed from an unsandboxed shell, so this is not the in-sandbox view:

$ ls -la .bashrc .zshrc .gitconfig .mcp.json .profile .zprofile \
        .bash_profile .gitmodules .ripgreprc .vscode
-r--r--r-- 1 user user 0 Aug 14 10:46 .bashrc
... (all ten, 0 bytes, 0444)

I can't explain why yours are cleaned up and mine are not — plausible variables are the Claude Code version (2.1.232 here), the platform (Ubuntu on WSL2, bubblewrap, repo on a native ext4 VHD rather than a Windows mount), or whether the session exits cleanly versus being killed. If the cleanup is best-effort on teardown, anything that skips teardown would leave them behind, which would fit both reports.

Two differences from your list that may be diagnostic: my set includes .mcp.json and .vscode but not .idea, so the set appears to vary — presumably with what exists in $HOME, or with version.

Worth flagging that .vscode is created as a file, not a directory, so anything that later tries to create .vscode/settings.json in that repo will fail. Same for .gitmodules at 0444 and git submodule add. Neither bit me, but they would bite someone.

This may be the same root cause as #78818, where the persistence of .git/config.lock is well established — if so, a fix there that unlinks sandbox-created placeholders on teardown would cover these too.

bcherny collaborator · 5 days ago

Reproduced on v2.1.233 on Linux (Ubuntu 24.04, bubblewrap) with a clean config and sandbox.enabled: true.

While any sandboxed Bash command runs in a git working directory, polling the repository root from outside shows the same nine zero-byte, mode 444 files you listed (.bash_profile, .bashrc, .gitconfig, .gitmodules, .idea, .profile, .ripgreprc, .zprofile, .zshrc) appearing at the project root and disappearing when the command finishes — git status reports them as untracked for the duration. On 2.1.233 we also observed transient .mcp.json and .vscode placeholders alongside the nine you reported.

Your evidence that this is the built-in home-dotfile protections resolving against the working directory instead of $HOME matches what we observed (paths declared with a ~/ prefix in settings resolve correctly and do not appear in the project). Flagging this to the team as a confirmed bug — placeholder files should not be created inside the user's repository.

🤖 Generated with Claude Code