Skip to content

[isolation] MCP Bearer Token Readable Inside Agent Container via proc/cmdline Chain #1829

Closed

Description

@github-actions

Summary

The MCP server authorization bearer token (shared by both the GitHub read MCP and the safeoutputs write MCP) is accessible in plaintext from within the AWF agent container via a two-step discovery chain.

Discovery Chain

Step 1: Read /proc/1/cmdline (entrypoint process command line)

/bin/bash /usr/local/bin/entrypoint.sh /bin/bash -c ... claude ... --mcp-config /tmp/gh-aw/mcp-config/mcp-servers.json ...

The --mcp-config flag reveals the path to the MCP configuration file.

Step 2: Read /tmp/gh-aw/mcp-config/mcp-servers.json

The file contains a JSON object with headers.Authorization fields for both MCP servers. The token is a Bearer token used to authenticate to the MCP HTTP endpoints. Both the GitHub (read-only) MCP and the safeoutputs (write-capable) MCP servers share the same token.

File Location

/tmp/gh-aw/mcp-config/mcp-servers.json

Directory permissions: drwx------ (700, runner-owned). Since the agent runs as runner, file system permissions do not prevent access.

Why This Is a Boundary Violation

The MCP authorization token is not protected by the LD_PRELOAD=/tmp/awf-lib/one-shot-token.so mechanism that guards environment variable tokens (e.g., GITHUB_TOKEN, ANTHROPIC_API_KEY). The one-shot mechanism hooks getenv()/secure_getenv() for env var names listed in AWF_ONE_SHOT_TOKENS, but the MCP token is stored in a file — outside that protection scope.

An agent that reads this token could:

  1. Directly make HTTP requests to `(host.docker.internal/redacted) with the raw bearer token, bypassing the MCP tool abstraction layer
  2. Access the GitHub MCP server directly with the same credential

Additional Findings in Same Investigation

/proc/1/cmdline Reveals Full Agent Invocation

The init process cmdline is readable and reveals:

  • --permission-mode bypassPermissions — the agent's permission mode
  • The complete --allowed-tools list (all MCP tool names)
  • --debug-file /tmp/gh-aw/agent-stdio.log — the debug log path (contains full tool call history)

SafeOutputs Server Source Code Readable

All .cjs files in /home/runner/work/_temp/gh-aw/safeoutputs/ are readable from inside the container, including:

  • sanitize_content_core.cjs — complete content sanitization logic
  • safe_outputs_handlers.cjs — all tool handler implementations
  • handler_auth.cjs — MCP authentication logic

These files are mounted read-only from the host but are fully accessible to the agent, enabling analysis of constraint/validation logic.

What Is Working Correctly

For completeness: the following isolation controls were confirmed functional:

  • Cloud credential files (~/.aws/credentials, ~/.azure/credentials, ~/.kube/config, ~/.docker/config.json, ~/.ssh/id_*) are all bind-mounted to /dev/null
  • GITHUB_TOKEN, GH_TOKEN, ANTHROPIC_API_KEY etc. are NOT_SET inside the container (one-shot mechanism working)
  • GitHub Actions output files ($GITHUB_ENV, $GITHUB_OUTPUT) are NOT accessible from inside the container
  • No effective capabilities, Seccomp filter active, no-new-privs=1
  • Docker socket bound to /dev/null

Environment

Steps to Reproduce

From inside an AWF agent container:

# Step 1: Find the MCP config path
cat /proc/1/cmdline | tr '\0' '\n' | grep "mcp-config"
# Output: /tmp/gh-aw/mcp-config/mcp-servers.json

# Step 2: Read the MCP config (token visible in output)
cat /tmp/gh-aw/mcp-config/mcp-servers.json
# Output: JSON with headers.Authorization for both MCP servers

Generated by Secret Digger (Claude) · ● 418.7K · ◷

  • expires on Apr 10, 2026, 5:07 AM UTC
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions