Security: MCP server `env` secrets exposed in plaintext via `--mcp-config` argv (visible in `ps`/`/proc`/EDR logs)

Status Open
Reported on v2.1.179
Maintainer reply None cached
Activity 1 comment · opened Jul 22, 2026

Bug report

When Claude Code is launched by the VS Code extension with MCP servers configured, the MCP servers' auth tokens (e.g. GITHUB_PERSONAL_ACCESS_TOKEN, JIRA_PERSONAL_ACCESS_TOKEN, a wiki bearer token) are passed inline, in plaintext, as part of the --mcp-config JSON blob on the CLI invocation's command line:

claude --output-format stream-json ... --mcp-config {"mcpServers":{"corp-github":{"type":"stdio","command":"node","args":[...],"env":{"GITHUB_PERSONAL_ACCESS_TOKEN":"ghp_..."}},"corp-jira":{...,"env":{"JIRA_PERSONAL_ACCESS_TOKEN":"..."}},"adobe-wiki":{...,"env":{"WIKI_MCP_TOKEN":"..."}}}}

Because these are process arguments rather than values only visible inside the process's own environment, they are readable by:

  • any other local process via ps aux / ps -ef
  • /proc/<pid>/cmdline on Linux
  • Activity Monitor / similar on macOS
  • the agent's own shell tool, if it ever runs something as unremarkable as ps aux | grep git — which is exactly how this was discovered. A routine "is another git process holding this lock file" check incidentally matched the Claude process in the listing and printed the full launch command, tokens included, directly into the agent's own tool output/transcript.

That last point makes this worse than a generic argv-exposure issue: it means the agent itself can accidentally exfiltrate its own MCP credentials into the visible transcript just by running ordinary diagnostic commands, with no malicious intent or unusual access required.

On managed machines this is further amplified by EDR/audit tooling that commonly collects and durably retains process command lines, turning a transient local exposure into a searchable plaintext record in central security logs — the same concern raised in #77485 for plugin install --config.

Reproduction

  1. Configure one or more MCP servers with token-bearing env values in the VS Code extension's MCP settings (or any launcher that forwards config via --mcp-config).
  2. Start a Claude Code session from VS Code.
  3. From a separate terminal (or from within the Claude Code session's own Bash tool), run ps aux | grep claude (or any broader ps aux that happens to match the process).
  4. Observe the full --mcp-config JSON, including all env secrets, printed in plaintext.

Impact

  • Any local process/user on the machine can read the tokens for the lifetime of the session.
  • EDR/audit/process-monitoring tooling on managed devices may persist the full command line (with secrets) into central logs.
  • The agent can inadvertently print its own credentials into its visible output/transcript via routine process inspection, as happened here.

Suggested fix

Avoid passing MCP server env secrets via CLI argv entirely. Options, roughly in order of preference:

  • Write the resolved mcpServers config (including env) to a temp file with restrictive permissions (e.g. 0600, user-only) and pass --mcp-config-file <path> instead of inlining JSON in argv; clean up on exit.
  • Set MCP server env vars in the child MCP server process's environment only (not the parent claude process's argv), so they're not visible in the parent's command line at all.
  • At minimum, redact/omit env values when constructing the process argv actually reflected in ps, if the config must otherwise remain in argv.

Related/precedent: #77485 requests the same class of fix (keep secrets out of argv) for plugin install --config; this report covers the separate --mcp-config code path used by the VS Code extension (and likely other launchers).

Environment

  • Claude Code 2.1.179 / 2.1.209 (seen launched via VS Code extension), macOS 26.5.2 (Darwin 25.5.0)
  • MCP servers affected: any stdio MCP server configured with token-bearing env values (observed with corp-github, corp-jira, adobe-wiki custom MCP servers)

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗