Skip to content

Security: --env-all passes unprotected secrets; one-shot token list incomplete #1481

@lpcox

Description

@lpcox

Problem

When gh-aw invokes AWF with --env-all, all host environment variables — including secrets — are passed into the agent container. While AWF has a one-shot token mechanism that sanitizes known tokens from /proc/1/environ after agent startup, there are several gaps:

Upstream issue: github/gh-aw#23197

Gap 1: Incomplete one-shot token list

The one-shot token list (docker-manager.ts:517) covers:

COPILOT_GITHUB_TOKEN, GITHUB_TOKEN, GH_TOKEN, GITHUB_API_TOKEN,
GITHUB_PAT, GH_ACCESS_TOKEN, OPENAI_API_KEY, OPENAI_KEY,
ANTHROPIC_API_KEY, CLAUDE_API_KEY, CODEX_API_KEY

But gh-aw workflows inject additional secrets that are NOT in this list:

  • GITHUB_MCP_SERVER_TOKEN
  • GH_AW_GITHUB_TOKEN
  • GH_AW_GITHUB_MCP_SERVER_TOKEN

These tokens remain fully visible in the agent's environment for the entire run.

Gap 2: No --exclude-env flag

There is no way for callers to exclude specific env vars from --env-all passthrough. The only exclusion mechanism is the hardcoded EXCLUDED_ENV_VARS set (docker-manager.ts:467-492), which cannot be extended at runtime.

Gap 3: 5-second race window

The one-shot token mechanism waits 5 seconds (entrypoint.sh:682) for the agent to cache tokens via LD_PRELOAD before unsetting them. During this window, tokens are visible via env, printenv, or /proc/self/environ.

Gap 4: One-shot token list is not extensible

The list of tokens protected by one-shot sanitization is hardcoded in both docker-manager.ts (the AWF_ONE_SHOT_TOKENS env var) and entrypoint.sh (the unset_sensitive_tokens function). There is no CLI flag to add custom tokens to the one-shot protection list.

Attack Scenario

In a pull_request_target workflow with bash: true, a prompt injection in PR content could instruct the agent to:

  1. Run env | grep TOKEN (succeeds if within the 5s window, or for unprotected tokens at any time)
  2. Exfiltrate values via allowed channels (PR comments, repo-memory, allowed domains)

Proposed Solutions

1. Add --exclude-env flag (high priority)

Allow callers to exclude specific env vars from --env-all:

awf --env-all --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env GH_AW_GITHUB_TOKEN -- ...

Implementation:

  • Add --exclude-env <name> repeatable option to CLI (src/cli.ts)
  • Add excludeEnv?: string[] to WrapperConfig (src/types.ts)
  • Merge into EXCLUDED_ENV_VARS before the config.envAll loop (docker-manager.ts:596)

2. Add --one-shot-tokens flag (high priority)

Allow callers to extend the one-shot token protection list:

awf --env-all --one-shot-tokens GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN -- ...

Implementation:

  • Add --one-shot-tokens <names> option to CLI
  • Append to AWF_ONE_SHOT_TOKENS env var passed to container
  • entrypoint.sh already reads this var — just needs to merge custom tokens into unset_sensitive_tokens()

3. Expand default one-shot token list (medium priority)

Add commonly used gh-aw tokens to the default list in docker-manager.ts:517:

AWF_ONE_SHOT_TOKENS: 'COPILOT_GITHUB_TOKEN,GITHUB_TOKEN,GH_TOKEN,...,GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GH_AW_GITHUB_MCP_SERVER_TOKEN'

And mirror in entrypoint.sh unset_sensitive_tokens().

4. Reduce race window (low priority)

The 5-second sleep could be replaced with a readiness signal (e.g., the LD_PRELOAD library writes a ready file after caching tokens), but this is complex and the window is already small.

Relevant Files

  • src/docker-manager.ts:467-492EXCLUDED_ENV_VARS set
  • src/docker-manager.ts:517AWF_ONE_SHOT_TOKENS list
  • src/docker-manager.ts:596-603--env-all passthrough loop
  • containers/agent/entrypoint.sh:348-379unset_sensitive_tokens()
  • containers/agent/entrypoint.sh:674-689 — one-shot token sanitization flow
  • src/cli.ts:1263-1266--env flag definition
  • src/types.tsWrapperConfig interface

Metadata

Metadata

Assignees

Labels

No labels
No labels

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