[BUG] Claude Code reads process environments and hardcodes credentials in terminal output
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
Related Issues
- #2142 (API keys exposed to version control — different vector)
- #24185 (.env files hardcoded into scripts — different vector)
What's Wrong?
When Claude Code needs an API key to make HTTP requests (e.g., curl calls to internal services), it proactively reads credentials from running process environments via /proc/<PID>/environ, displays the credential value in the terminal output, and then hardcodes the raw secret into subsequent curl commands.
This creates permanent credential exposure in:
- Terminal scrollback buffer
- Session logs
- Screen captures / recordings
- Any tool that captures Claude Code output
The model does this even when secure credential stores (e.g., systemd-creds) are available and configured. There is no built-in guardrail to prevent this behavior.
Steps to Reproduce
- Run a service that has API keys in its environment (e.g., a systemd service with
Environment=API_KEY=secret-value) - Ask Claude Code to query that service's API
- Claude Code will:
- Run
cat /proc/<PID>/environ | tr '\0' '\n' | grep API_KEY— displays the key in terminal output - Then use the key directly in a curl command:
curl -H "X-API-Key: secret-value-in-plain-text" http://...— hardcodes the key in the command
Expected Behavior
Claude Code should never display credential values in terminal output. When it needs to use a credential:
- Capture the value in a shell variable without displaying it:
``bash``
KEY=$(grep API_KEY /proc/$PID/environ_file | cut -d= -f2)
curl -H "X-API-Key: $KEY" http://...
- Or better, use the secure credential store directly:
``bash``
KEY=$(systemd-creds decrypt --name=service.api-key /path/to/cred -)
curl -H "X-API-Key: $KEY" http://...
Severity
HIGH — Credentials are silently exposed with no warning. The user may not notice until the key is compromised. In our case, we had to:
- Rotate all exposed keys
- Build a custom PreToolUse hook to block dangerous patterns
- Create a wrapper script to handle credentials safely
Workaround
We implemented a PreToolUse hook that blocks Bash commands containing:
- Process environment reading patterns
- Hardcoded API key patterns (regex on known prefixes)
systemd-creds decryptwithout variable capture- Direct reads of credential files
This should arguably be a built-in behavior, not something users need to implement themselves.
Proposed Fix
- Built-in credential detection: Claude Code should recognize when it's about to display a credential value and redact it from terminal output
- Secure-by-default patterns: When the model needs credentials, it should always capture them in variables, never inline them in commands
- PreToolUse guardrail: Ship a default hook (or built-in check) that blocks commands reading process environments or containing patterns matching common API key formats
Environment
- Claude Code version: latest (2026-03-04)
- Model: claude-opus-4-6
- OS: Ubuntu 24.04 (VPS)
- Credential store: systemd-creds (encrypted at rest)
This issue has 5 comments on GitHub. Read the full discussion on GitHub ↗