auto mode: environment setup pins an absolute trusted-repo path into user-global settings, so every other project inherits the wrong trust boundary

Status Open
Reported on v2.1.226
Maintainer reply None cached
Activity 3 comments · opened Sep 10, 2026

Summary

autoMode.environment is written to user-global ~/.claude/settings.json by the auto-mode environment setup. One of its entries is **Trusted repo**, and it is stored as an absolute path to whichever project happened to run the setup:

"autoMode": {
  "environment": [
    "...",
    "**Trusted repo**: The git repository the agent started in (C:\\Users\\me\\ProjectA) — no remotes configured, so scope is limited to this local working directory",
    "..."
  ]
}

Because the file is user-global, that path then applies to every other project on the machine. Starting Claude Code in D:\ProjectB leaves the classifier believing the trusted repo is still ProjectA, so ordinary work inside ProjectB — reading its own files, writing its own config — is classified as reaching outside the trust boundary.

Impact

The failure is silent and the symptom is far from the cause. What the user sees is a flood of permission prompts and classifier denials in a project that is plainly trusted; nothing names the stale path, and /config, the permission allowlist, and additionalDirectories all look correct because none of them is the thing that is wrong.

In our case this cost a full day of troubleshooting and ended in an unnecessary rollback to an older release, on the theory that a recent version had regressed permissions. It had not — a months-old entry from an unrelated project was still in effect.

The entry is also stale in a second way: it records facts about that repo ("no remotes configured", visibility, protected branches) which are simply wrong for the project actually open.

Reproduce

  1. Run the auto-mode environment setup in project A (C:\Users\me\ProjectA). Note the absolute path written into ~/.claude/settings.json under autoMode.environment.
  2. Start Claude Code in an unrelated project B (D:\ProjectB), with its own git repo and its own .claude/settings.local.json.
  3. Ask it to edit a file inside project B, or inside the user's own ~/.claude/.
  4. The classifier reasons from project A's trust boundary. Expected-routine actions are denied or escalated, with no indication that a stale path is responsible.

Expected

Any one of these would have prevented the day:

  1. Resolve the trusted repo per session from the actual working directory, rather than freezing an absolute path at setup time. The entry already says "the git repository the agent started in" — it should mean that literally, not a snapshot of where it was first run.
  2. Write the environment block project-scoped — into that project's .claude/settings.local.json — and keep only genuinely machine-wide facts (org, cloud provider, network posture) in the user-global file. The project-specific half and the org-wide half currently live in one array with one scope.
  3. Warn on mismatch. If autoMode.environment names a trusted repo that is not the current working directory, say so once at startup. A single line — "auto mode trust boundary names C:\Users\me\ProjectA, but you are in D:\ProjectB" — turns a day into a minute.
  4. Surface it in /config or /status, so the effective trust boundary is inspectable without reading raw JSON.

Workaround

Correction (2026-09-10): the project-scoped half of this workaround does not work and never did - autoMode is read only from user, --settings and managed settings, and a block in a repo's .claude/settings.json or .claude/settings.local.json is parsed and then ignored as repo-controllable. Details, and the consequence for Expected item 2, in this comment. Only the de-pinning half of the paragraph below holds.

Setting autoMode.environment in the project's own .claude/settings.local.json appears to override the user-global copy, since project settings load after user settings and autoMode carries none of the "only honored from user/managed settings" restrictions that other keys document. Every project then needs its own block, and the user-global entry has to be manually de-pinned so it stops naming a specific repo — neither is discoverable.

Environment

  • Claude Code 2.1.226 and 2.1.267 (behaviour identical; the rollback between them was chasing the wrong cause)
  • Windows 11, native installer
  • Auto mode enabled

View original on GitHub ↗

3 Comments

ASUSROG-WIN-11 · 1 month ago

Correction: the workaround in the description does not work

Setting autoMode.environment in a project's .claude/settings.json or .claude/settings.local.json has no effect. The claim in the Workaround section that autoMode "carries none of the only-honored-from-user/managed settings restrictions" is wrong, and I would rather it did not mislead the next person who finds this issue.

Auto mode collects classifier rules from exactly three sources:

Kce = ["userSettings", "flagSettings", "policySettings"];
// ...
for (let E of Kce) {
  let P = ye(E); if (!P) continue;
  let O = schema.safeParse(P.autoMode);
  if (O.success) { /* allow / soft_deny / hard_deny / environment collected here */ }
}

Project and local settings are parsed only to be refused, with a warn-level log and a telemetry event:

settings autoMode in ${source} ignored — only user/flag/managed settings may set classifier rules
(projectSettings and localSettings are repo-controllable)

Both the three-element source list and that message are present in 2.1.226, 2.1.267 and 2.1.268 alike, so the project-scoped block never took effect on any of the versions named in the original report.

The restriction is also correct, and that changes one of the asks above. Expected item 2 (write the environment block project-scoped) should not be implemented as stated: a file inside the repository must not be able to describe its own trust boundary, or a hostile repo widens its own. Items 1 (resolve the trusted repo per session from the working directory), 3 (warn on mismatch) and 4 (surface the effective boundary in /config or /status) stand unchanged, and item 3 remains by far the cheapest fix for the day this cost.

What actually helped

Only the other half of the original workaround: de-pinning the absolute path from the user-global entry, so the generic rule reads "the git repository the agent started in" and resolves per session. Anything a single project needs beyond that has to live in the same user-global file, written conditionally so it applies only when the session's working directory is inside that project and falls back to the generic rule everywhere else. That is a workaround for the absence of item 1, not a design anyone should have to discover.

For a deterministic escape hatch, claude --settings <file> works, since flagSettings is honoured.

The general lesson, which is really the reason for this comment: a settings workaround is not verified by the write succeeding. The binary has to be shown to read the key from that source.

crespire · 24 days ago

For those of us with public dotfiles, this is also an exposure vector. Really not a great decision here by the team.

aspiers · 15 days ago

Adding a case that makes the user-global storage more than a trust-boundary
problem: it can publish the environment profile.

Setup: ~/.claude/settings.json is a GNU Stow symlink into a public
dotfiles repo. That's a common way to share Claude Code config across
machines, and it means the user-global file is version-controlled and
published.

What happened (2.1.285, Linux): /auto-mode-setup added a 25-entry
autoMode.environment block to that file. It included:

  • the absolute path of the repo it ran in, as **Trusted repo**
  • the names of every git remote configured for that repo
  • the repo's .gitignore patterns for private key files under ~/.config
  • a list of frequently used local CLIs

None of it is a credential. It is still a machine-specific inventory that
doesn't belong in a public repo, and the next routine settings commit would
have published it.

Why the existing options don't cover this:

  • Project .claude/settings.json and .claude/settings.local.json are

ignored for autoMode. The reason for that makes sense.

  • --settings <file> only applies to sessions started through a wrapper.

Sessions launched by an IDE or another tool never see it.

  • There's no untracked user-level layer. #81990 asked for

~/.claude/settings.local.json and was closed as stale, not declined.

Any one of these would fix it:

  1. Read autoMode from a user-scoped file that is never checked in, such as

~/.claude/settings.local.json. It stays outside any repo, so the
injection concern behind ignoring project settings doesn't apply.

  1. Key the setup output by repository in user scope, as #87312 proposes, so

one repo's facts don't apply everywhere.

  1. At minimum, warn before saving when ~/.claude/settings.json is a

symlink or sits inside a git work tree.