[BUG] `claude` processes spawned from a desktop Code session ignore the session's account and fall back to the OS user's default CLI profile (silent switch to an org account: billing + data)

Status Open
Reported on v2.1.296
Maintainer reply None cached
Activity 0 comments · opened Oct 13, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Summary

A claude process spawned from a Claude Code session started in the desktop app does not inherit the session's account. It resolves the OS user's default CLI profile (%USERPROFILE%\.claude) instead:

  • If that profile is logged out, the child fails with Not logged in.
  • If it is logged into another account, the child runs silently on that account.

In my case, the default profile was logged into a Team organization account, while the desktop app was signed into my personal account. Agents spawned from my personal sessions were billed to the org account, and personal or potentially confidential content (prompts, tool calls, tool results) went through sessions tied to an organization I never chose for this work.

Related issues

These issues are in the same family. This report adds that the switch happens in spawned processes, and that the fallback account belongs to a third-party organization, which makes it a data-confidentiality issue.

  • #78998: on Windows, parallel CLI instances share one global auth state and one session silently switches account (closed as stale, never triaged)
  • #87447: on Windows, a desktop-launched session's CLAUDE_CONFIG_DIR names one account while the session authenticates and bills under another
  • #99240: the host-supplied session account is ignored when ~/.claude.json already has an oauthAccount
  • #85294: switching accounts in the desktop app does not reconcile ~/.claude.json

Environment

  • OS: Windows 11
  • Claude desktop app: 2.31226.1.0
  • Claude Code: 2.1.296 (Claude Code)
  • Desktop app signed into a personal account; default CLI profile (%USERPROFILE%\.claude) logged out at test time, logged into a Team org account when the incident happened

Reproduction

Attached is identity-probe.ps1. It prints the identity seen by the current process, then spawns claude children under three environment scenarios. With -Live, each child sends a tiny Haiku request and the script reads the rate_limit_event from its stream-json output: the 5-hour / 7-day utilization and reset times of the account that actually served the request. Secrets are never printed, only SHA-256 fingerprints.

  1. Create an empty folder (no .claude/ inside) and put the script in it.
  2. Open a Claude Code session on that folder from the desktop app.
  3. Paste:
Run exactly this command and show its full output verbatim in a code block, without interpreting it:
powershell -NoProfile -ExecutionPolicy Bypass -File .\identity-probe.ps1 -Role parent -Live

Then launch a subagent with your Agent tool whose only task is to run
powershell -NoProfile -ExecutionPolicy Bypass -File .\identity-probe.ps1 -Role subagent -NoChild
and return its output verbatim. Show it in a second code block.

Finally, make a table with one row per role and these columns: role, env_user_email, env_oauth_token, auth_email, auth_config_dir, child_says_userEmail, billed_5h, billed_7d. No analysis.

Reproduction output

Default CLI profile logged out:

| role | env_user_email | env_oauth_token | auth_email | auth_config_dir | child_says_userEmail | billed_5h | billed_7d |
|---|---|---|---|---|---|---|---|
| parent | <personal account> | (absent) | | C:\Users\<user>\.claude | | | |
| child: inherits env | <personal account> | (absent) | | C:\Users\<user>\.claude | ERROR: Not logged in · Please run /login | (no rate_limit_event) | (no rate_limit_event) |
| child: no host identity | | (absent) | | C:\Users\<user>\.claude | ERROR: Not logged in · Please run /login | (no rate_limit_event) | (no rate_limit_event) |
| child: no host id, no CONFIG_DIR | | (absent) | | C:\Users\<user>\.claude | ERROR: Not logged in · Please run /login | (no rate_limit_event) | (no rate_limit_event) |
| subagent | <personal account> | (absent) | | C:\Users\<user>\.claude | | | |

What this shows:

  • The session knows its account (CLAUDE_CODE_USER_EMAIL is set) but exposes no credential to its environment (CLAUDE_CODE_OAUTH_TOKEN absent). It authenticates through a channel its children can't reach.
  • A claude child that inherits the full environment still does not run as the session's account. It resolves the default CLI profile, and fails here only because that profile is logged out.
  • The built-in Agent-tool subagent is not affected: it runs inside the session's process.

With the default profile logged into another account, the same children run silently on that account. That is what happened in the incident, where agents were billed to the Team org account.

Expected behavior

Every process spawned from a session (agent, worktree, claude subprocess) runs as the session's account and organization. If they can't be resolved, the child fails with an explicit error. It never falls back silently to another account.

Workaround and why it is insufficient

Forcing a config dir per repo in .claude/settings.local.json:

"env": { "CLAUDE_CONFIG_DIR": "C:/Users/<user>/.claude-<profile>" }

This does not propagate the session's account. It only changes which profile the child falls back to, and that profile must be logged in separately. It has to be repeated in every repository, and forgetting it once brings the problem back. claude auth status run from a terminal does not reflect it either, so there is no simple way to check which account a given child will use.

The safest mitigation today is to keep the default CLI profile logged out, so that a fallback fails instead of switching accounts.

Impact

  • Confidentiality: content from personal work went through sessions tied to a Team organization. Depending on the plan and admin settings, that organization's admins may be able to see or export it. The user got no warning and had no way to notice.
  • Billing and limits: tokens and session limits were charged to the wrong account.

A silent fallback to a different identity is a security and privacy defect, not just a configuration inconvenience.

Suggested fix

  1. Propagate session identity: pass the parent session's account and organization (or a scoped credential) explicitly to every agent, worktree and claude subprocess it spawns.
  2. Fail closed: never fall back implicitly to the OS user's default profile when a session's identity can't be resolved. At minimum, warn when a child resolves a different account than its parent session.
  3. Per-account isolation on disk: keep user-level shared config (global CLAUDE.md, skills, hooks, MCP servers) at the root of .claude/, and move account-scoped data (credentials, history, transcripts in projects/, usage) to .claude/accounts/<account-id+org-id>/. Key on the stable account and organization IDs, not on the email: one email can belong to several organizations or change over time. The email can be the display name.
  4. Organization selection for Cowork and Code in the UI: reuse the existing organization switcher. The selected organization defines the profile used by the session and by every process it spawns.
  5. Visibility: show the active account and organization on every session and agent (badge, /status). Make switching an explicit action. A running session keeps its original organization.

What Should Happen?

Agents spawned from a Claude Code session in the desktop app use the OS user's default CLI profile instead of the account logged into the app

Summary

Claude Code sessions started from the Claude desktop app, logged into a personal account, spawned agents that authenticated with a different account: the one stored in the default CLI config directory of the Windows user (%USERPROFILE%\.claude), which belongs to a Team organization. Nothing showed that the account had switched.

Environment

  • OS: Windows 11
  • Claude desktop app: 2.31226.1.0
  • Claude Code: 2.1.296 (Claude Code)
  • Two accounts on the same machine: a personal account (logged into the app) and a Team org account (logged into the default CLI profile)

Steps to reproduce

  1. Log the default CLI profile (%USERPROFILE%\.claude) into account A (Team org).
  2. Log the Claude desktop app into account B (personal).
  3. From the app, start a Claude Code session on a local repo and have it spawn agents (in my case they ran in worktrees under .claude/worktrees/).
  4. Look at usage on both accounts.

Expected behavior

Every agent spawned from a session uses the session's account (B). If that is not possible, the agent fails with an explicit error instead of falling back to another account.

Actual behavior

The agents used account A, the default CLI profile. The only workaround that worked was adding this to the repo's .claude/settings.local.json:

"env": { "CLAUDE_CONFIG_DIR": "C:/Users/<user>/.claude-perso" }

This has to be repeated in every repo, and forgetting it brings the problem back.

Impact

  • Billing and limits: tokens and session limits were charged to the wrong account.
  • Confidentiality: personal and potentially confidential content (prompts, tool calls, tool results) went through sessions tied to a Team organization. Depending on the plan and admin settings, the organization's admins may be able to see that content. The user had no warning and no way to notice.

This is a security and privacy issue, not only a configuration inconvenience: a silent fallback to a different account sends data to an organization the user did not choose.

Suggested fix

  1. Propagate the session's identity: the account and organization of the parent session are passed explicitly to every agent, worktree and claude subprocess it spawns.
  2. Fail closed: no implicit fallback to the OS user's default profile when the session's identity can't be resolved.
  3. Per-account isolation on disk: keep user-level, shared config (global CLAUDE.md, skills, hooks, MCP servers) at the root of .claude/, and move account-scoped data (credentials, history, transcripts in projects/, usage) to .claude/accounts/<account-id+org-id>/. The key should be the stable account+organization identifier, not the email, which can belong to several organizations or change over time. The email can be the display name.
  4. Organization selection in the UI for Cowork and Code: reuse the existing organization switcher; the selected org defines the profile used by every session and every agent it spawns.
  5. Visibility: show the active account/organization on every session and agent (badge, /status), and make switching an explicit action. Running sessions keep their original organization.

Error Messages/Logs

Steps to Reproduce

identity_probe.zip

  1. Open a Claude code session
  2. run the identity-probe.py script

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.296

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

Other

Additional Information

_No response_

View original on GitHub ↗