Repository navigation
[isolation] MCP Bearer Token Readable Inside Agent Container via proc/cmdline Chain #1829
Description
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:
- Directly make HTTP requests to `(host.docker.internal/redacted) with the raw bearer token, bypassing the MCP tool abstraction layer
- 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-toolslist (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 logicsafe_outputs_handlers.cjs— all tool handler implementationshandler_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_KEYetc. areNOT_SETinside 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
- AWF version: v0.25.13 (from
aw_info.json) - CLI version: v0.67.2 (from
aw_info.jsonand.lock.ymlmetadata) - gh-aw compiler version: v0.67.2 (from lock file
# gh-aw-metadata) - Workflow:
secret-digger-claude.lock.yml - Run ID: 24173167475 / Run fix(docker): simplify to localhost+Squid-only iptables #1270
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 serversGenerated by Secret Digger (Claude) · ● 418.7K · ◷
- expires on Apr 10, 2026, 5:07 AM UTC
Activity