Skip to content

agent-stdio.log must be mode 0600 and MCP gateway tokens must be masked in log pipelines #25103

@szabta89

Description

@szabta89

Summary

The MCP gateway bearer token — correctly protected at rest in /tmp/gh-aw/mcp-config/mcp-servers.json (mode 0600, directory mode 0700) — leaks in full into the world-readable Claude Code stdio log (/tmp/gh-aw/agent-stdio.log, mode 0644) when the agent reads that config file using the Read tool. The token appeared 8 times in the world-readable log: once in the tool_result record for the file read, and additionally in extended-thinking blocks where the model quoted the discovered token. The redact_secrets.cjs pipeline does not cover internally-minted MCP gateway tokens, so the leakage is unredacted.

Affected Area

Log-file access-control boundary. The tee -a /tmp/gh-aw/agent-stdio.log invocation in the parent shell runs with the default umask (022), producing a mode 0644 file readable by any process on the runner host — despite the config file being intentionally created at mode 0600 via umask 077 in convert_gateway_config_claude.sh. Additionally, redact_secrets.cjs covers only GitHub tokens, Azure/Google/AWS/Anthropic API keys, and OpenAI keys — not randomly-minted internal MCP gateway tokens (no recognizable fixed prefix).

Reproduction Outline

  1. Run a gh-aw workflow using the Claude Code engine (local-analysis profile, claude-sonnet-4-6).
  2. Confirm permissions: stat -c '%a %n' /tmp/gh-aw/mcp-config/mcp-servers.json600; stat -c '%a %n' /tmp/gh-aw/agent-stdio.log644.
  3. The agent discovers /tmp/gh-aw/mcp-config/mcp-servers.json (e.g., via find /tmp -maxdepth 4 -type f) and reads it with the Read tool.
  4. The full file content — including the Authorization bearer token for both github and safeoutputs MCP servers — is logged verbatim as a tool_result record in the stdio log.
  5. Extended-thinking blocks additionally quote the token as part of the model's reasoning, each producing another world-readable log entry.
  6. Verify: grep -c 'Authorization' /tmp/gh-aw/agent-stdio.log → 8 (or more).

Observed Behavior

The MCP gateway token appears 8 times in /tmp/gh-aw/agent-stdio.log (mode 0644): once as the verbatim tool_result content of the Read call on mcp-servers.json, and multiple times in extended-thinking traces. Any process on the runner host that can read /tmp can recover the token without any file-system privilege.

Expected Behavior

The MCP gateway token must not appear in any world-readable log file. Either:

  • The stdio log should be created at mode 0600 (e.g., set umask 077 before tee, or pre-create the file at mode 0600 before the agent starts), and/or
  • redact_secrets.cjs (or an equivalent masking step) should register the MCP gateway Authorization token as a dynamic secret to be masked in all log sinks at workflow setup time.

Security Relevance

Any process running on the Docker bridge network or on the host that can read /tmp can recover the MCP gateway token without needing runner-user file access to the protected config directory. Since the same token is shared between the GitHub read MCP and the safeoutputs write-sink MCP (see also #1649), this leakage gives an attacker access to both read and write sinks. The finding contradicts two documented architecture claims simultaneously: (1) "secrets are passed via environment variables, never in configuration files"; (2) "Secret Redaction scans temporary files to prevent accidental credential leakage through logs, outputs, or artifacts."

Confirmed in v0.65.6.

Original finding: https://github.com/githubnext/gh-aw-security/issues/1697

Generated by File Issue · ● 231.3K ·

Metadata

Metadata

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions