Skip to content

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

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 ·

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions