acpmux: an agent never inherits another harness's login
An agent acpmux started inherited the daemon's own environment, including another harness's login. A daemon started with CLAUDE_CODE_OAUTH_TOKEN in its env (how the machine vault test hands Claude Code its login) gave it to Codex too, and Codex writes its whole shell env to ~/.codex/shell_snapshots. The vault test's home scan found the Claude login in three of those files.
harness_command now removes every other harness's login keys after the daemon env, the login shell and machine env are applied, and before the profile's own env, so a value a profile sets on purpose still passes.
- The table is
agent/foreign_login.rs. A test keeps it in sync with the pool's credential list (hub/pool/auth.rsAUTH_ENV). - Harness sign-ins (
CLAUDE_CODE_OAUTH_TOKEN,CLAUDE_CONFIG_DIR,CODEX_HOME,OPENCODE_CONFIG) are removed from every other agent. - Provider API keys (
ANTHROPIC_API_KEY,ANTHROPIC_AUTH_TOKEN,OPENAI_API_KEY) are removed only between Claude Code and Codex, so multi-provider harnesses (OpenCode, pi, Gemini) keep them. - The agent is the one the profile's kind and command line run, not its
familylabel ({"argv": ["codex-acp"], "family": "mine"}is Codex). - A profile that is not one model agent is left alone: the Chief brain (
chief acp) passes every login on to the harnesses under it on purpose.
Behavior change: a name delivered in machine secrets or added to loginEnvAllow no longer reaches another harness's agent either (a delivered OPENAI_API_KEY no longer reaches Claude Code's Bash). Set it in the profile's env to give it on purpose. Exempting delivered names would let the Claude login reach Codex again.
Not changed: agent_login.rs (the CLI sign-in runner, claude /login, codex login) still inherits the daemon env; it runs a sign-in, not an agent session.
Test
an_agent_never_inherits_another_harness_login (agent/command.rs), committed before the fix:
- base + test (2c95286): fails on Linux and macOS,
Codex inherits CLAUDE_CODE_OAUTH_TOKEN(https://github.com/manaflow-ai/cmux/actions/runs/41838867259) - fix (c920547): passes on Linux and macOS with every
logintest (verify-cmux-tui-hosted.sh --filter login, https://github.com/manaflow-ai/cmux/actions/runs/41841448796)
Observed / Not run
Observed: the hosted runs above. Both also fail cargo clippy (macOS targets) on cmux-host unused imports, which this PR does not touch (base red). Not run: the full hosted suite; the machine vault test in stub mode, which runs after this lands (its last run failed only on this leak).
Changelog
Fixed: an agent no longer inherits another agent's sign-in from the acpmux daemon's environment.
Agent session: agent session
🤖 Generated with Claude Code
![Autofix with [code]smith](https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png)
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Stops an acpmux agent from inheriting another harness's login from the daemon's environment. A daemon started with Claude Code's login in its env gave it to every agent it started; Codex wrote it to ~/.codex/shell_snapshots on disk. harness_command now removes every other family's login keys after the daemon, login shell, and machine env are applied, and before the profile's own env, so a value a profile sets on purpose still passes.
- The scrub runs on every harness spawn path: agent sessions, chat forks, model lists, and sign-in probes.
- The scrubbed family comes from what actually runs: the executable, what a runner (
npx,node,bun) starts as its first plain word, or, when both are unknown, the profile name's first word. A runner option that may take a value (or aK=Vassignment) makes the command unknown, and no substring of an argument counts. Codex'sCODEX_API_KEYsign-in is scrubbed from the other harnesses. A custom-named profile running theclaude-acpACP adapter counts as Claude Code, not unknown. - Only the Chief brain—this very binary or the
cmux-tuibeside it, resolved, runningchief acp—keeps all logins to pass to child agents; acmuxelsewhere on PATH is no host, anduniichat-agentstarts no harness. - A command that names no known agent, or more than one, is deny-by-default: it loses every harness's sign-in and keeps only the provider API keys.
- A test keeps the login table in sync with the pool's credential list.
Behavior change
Machine secrets or loginEnvAllow entries no longer pass another harness's login to an agent; set such a value in the profile's env instead.