Bash tool: env vars leak into spawned shells as literal string "undefined"
Summary
The Bash tool spawns shells with environment variables set to the literal string "undefined" instead of being unset. This silently breaks any tool that uses [ -n "$VAR" ] semantics, since "undefined" is a non-empty string. In my case it broke fnox — which treats FNOX_AGE_KEY as inline key content with priority over FNOX_AGE_KEY_FILE, then fails to parse the string undefined as an age identity.
Reproduction
In a clean shell launched by Claude Code's Bash tool:
$ printenv FNOX_AGE_KEY
undefined
$ echo $?
0
In a clean shell with no Claude Code involvement:
$ env -i HOME="$HOME" zsh -lc 'printenv FNOX_AGE_KEY'
$ echo $?
1
The variable is not set in any of:
- Any zsh init file (
/etc/zshenv,~/.zshenv,~/.zprofile,~/.zshrc) launchctl getenv FNOX_AGE_KEY~/Library/LaunchAgents/*.plist,/Library/LaunchAgents/*.plist- VS Code user settings (
terminal.integrated.env.osx) ~/.claude/settings.jsonenvblock- The parent process tree above the claude binary — VS Code Code Helper Plugin process has empty
FNOX_*; the claude native binary process hasFNOX_AGE_KEY=undefined
So the var is introduced between the Code Helper Plugin and the claude binary, i.e. inside the Claude Code spawn pipeline.
Hypothesis
The literal value "undefined" is the smoking gun. JavaScript code is constructing a key/value pair via template literal or String(prop) where prop is undefined, and writing it into the spawn env. The var name FNOX_AGE_KEY doesn't appear anywhere in the extension's bundled JS, so it's likely constructed dynamically (e.g. `\FNOX_${someKey}\``) which makes it ungreppable.
Impact
Anything that treats env-var presence as truthy will misbehave:
[ -n "$VAR" ] # passes — wrong
[ "$VAR" ] # passes — wrong
"${VAR:-default}" # returns "undefined" — wrong
In Rust, std::env::var("VAR").ok() returns Some("undefined") instead of None, which is what tripped fnox.
This bug is silent: tools won't error obviously, they'll fail in domain-specific ways downstream. fnox happened to fail with a parseable error ("non-identity data on line 1"); a tool that uses $VAR as a path could end up stat'ing a file literally named undefined.
Suggested fix
Wherever the spawn env is being constructed, filter out keys whose value is undefined (or null) before passing to child_process.spawn. Don't let JS stringification leak into the process boundary.
Environment
- Claude Code extension:
anthropic.claude-code-2.1.120-darwin-arm64 - Claude binary:
2.1.120 (Claude Code) - VS Code:
1.117.0 - macOS:
26.4.1 - Node (via mise):
v22.22.2 - Shell:
/bin/zsh
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗