[BUG] `CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1` leaves an empty `~/.bash_profile` behind, silently breaking login-shell PATH

Open 💬 0 comments Opened Jul 10, 2026 by mhsong55

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?

With CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1, Claude Code creates empty 0-byte files in $HOME at startup — one for each path in a fixed list of shell and package-manager dotfiles that does not already exist. It never removes them, and deleting one then running again recreates it.

The damaging one is ~/.bash_profile.

Bash login shells read only the first of ~/.bash_profile~/.bash_login~/.profile. Of those three, a stock Debian/Ubuntu account has only ~/.profile/etc/skel ships .profile, .bashrc and .bash_logout, and no .bash_profile. So for as long as the empty ~/.bash_profile exists, no login shell reads ~/.profile: ~/.local/bin and ~/bin drop out of PATH, ~/.bashrc is not sourced, and anything else ~/.profile loads (~/.cargo/env, for instance) is skipped. On my machine this also removed claude itself from the login-shell PATH, since the native installer puts it in ~/.local/bin.

This is distinct from the project-directory pollution of #17087 and #51405. This is $HOME, so the symptom is not a dirty git status but a quietly altered environment for every login shell on the account.

No sandbox opt-in is involved. Per the sandboxing docs, sandbox.credentials "affects sandboxed Bash commands only", while CLAUDE_CODE_SUBPROCESS_ENV_SCRUB strips credentials "from all subprocesses regardless of sandboxing". I never set sandbox.enabled anywhere.

What Should Happen?

Claude Code should not create the user's shell and toolchain dotfiles.

~/.bash_profile above all. It is not clutter but semantics: its mere existence stops every login shell on the account from reading ~/.profile. It should never be created. The other ten files, and the .pip and .config/pip directories, are empty and inert, but they should not be left behind either.

Removing them at exit would not be enough. I checked while a run was still in flight: ~/.bash_profile is already on disk, and a login shell started at that moment has already lost ~/.profile. An interactive session lasts hours, and a crash or kill -9 would leave the file behind for good.

Error Messages/Logs

None. Nothing is printed, prompted, or logged when the files are created.

Steps to Reproduce

Deterministic, and no authentication is needed: the run fails at the API-key check after the files are written. bubblewrap is installed on my machine; I did not test a host without it.

env -i clears PATH, so resolve the binary first and call it by absolute path.

CLAUDE=$(readlink -f "$(command -v claude)")   # e.g. ~/.local/share/claude/versions/2.1.205

# 1. A home dir shaped like a stock Debian/Ubuntu account: ~/.profile, no ~/.bash_profile
rm -rf /tmp/fakehome && mkdir -p /tmp/fakehome/proj /tmp/fakehome/.local/bin
printf 'export PATH="$HOME/.local/bin:$PATH"\n' > /tmp/fakehome/.profile

# 2. BEFORE — the login shell reads ~/.profile
env -i HOME=/tmp/fakehome bash -lc 'echo "$PATH"'      # contains ~/.local/bin

# 3. Run Claude Code once with the variable set
cd /tmp/fakehome/proj
env -i HOME=/tmp/fakehome PATH=/usr/bin:/bin ANTHROPIC_API_KEY=sk-invalid \
  CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1 \
  "$CLAUDE" -p 'hi' --max-turns 1 </dev/null

# 4. A file that did not exist now does; the one that did exist is untouched
wc -c /tmp/fakehome/.bash_profile    # 0
wc -c /tmp/fakehome/.profile         # unchanged

# 5. AFTER — the login shell no longer reads ~/.profile
env -i HOME=/tmp/fakehome bash -lc 'echo "$PATH"'      # ~/.local/bin is gone

# 6. Removing the stub restores it
rm /tmp/fakehome/.bash_profile
env -i HOME=/tmp/fakehome bash -lc 'echo "$PATH"'      # back to normal

Running the same block without CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1 adds only .claude and .claude.json, and steps 2 and 5 print the same PATH.

On a home directory where none of them exist yet, the run creates these 11 files — all 0 bytes — and 2 directories:

.bash_aliases  .bash_profile  .bashrc     .bunfig.toml  .gitconfig
.netrc         .npmrc         .profile    .yarnrc       .yarnrc.yml
.zshrc         .config/       .pip/

~/.profile is on that list, which is why step 1 seeds it: because it already exists, it is left alone, and wc -c shows its byte count unchanged. Existing dotfiles keep their contents and their mtimes. Only the files you did not have get created — which is why this goes unnoticed on a real machine.

Claude Model

Not sure / Multiple models

Is this a regression?

No, this never worked

Last Working Version

None

Claude Code Version

2.1.205

Platform

Anthropic API

Operating System

Ubuntu/Debian Linux

Terminal/Shell

Other

Additional Information

Claude Code names these files itself. Run it with the variable set inside a git repository, and it appends this to .git/info/exclude:

# claude-code scrub-mode stubs
/bunfig.toml
/package.json
/.npmrc
/.yarnrc
...

So for the project directory the stubs are deliberately kept out of git status — the side effect is recognised and handled there. Nothing equivalent happens for $HOME, where the same mechanism drops ~/.bash_profile.

Two more things from that same file suggest nothing tracks what was created: the block is appended again on every run (the .git/info/exclude in my repo now contains it twice), and the stubs in $HOME are never removed.

Versions. I ran the reproducer against every build I still have installed — 2.1.198, 2.1.199, 2.1.201, 2.1.202, 2.1.204 and 2.1.205 — and all six create ~/.bash_profile.

Environment details. Native installer, ~/.local/bin/claude~/.local/share/claude/versions/. Kernel 6.8.0-117-generic. Terminal is Ghostty running tmux, shell is bash. bubblewrap 0.9.0-1ubuntu0.1 (behaviour on a host without it: not tested). sandbox was never enabled in any settings file. None of this matters to the bug — the reproducer above is non-interactive and writes the files before any terminal state is involved.

Workaround. Make ~/.bash_profile source ~/.profile. I verified this survives: after another Claude Code run the file's contents are unchanged, so the line stays.

if [ -f "$HOME/.profile" ]; then . "$HOME/.profile"; fi

Related.

  • #46584 — same symptom, no maintainer response, auto-closed as stale. #46585 — its duplicate, closed and locked.
  • #74799 — open, no response yet: stub files still created on startup (Fedora)
  • #17087 — the project-directory variant, closed as completed by a maintainer
  • #51405 — same area, closed by its own author

View original on GitHub ↗