[BUG] 2.1.232 Cygwin-symlink check false-positives on a symlink-free repo and disables auto-mode classifier approval for most commands (Windows/Git Bash)

Status Fixed / completed
Reported on v2.1.232
Maintainer reply None cached
Activity 1 comment · opened Aug 14, 2026 · closed Aug 14, 2026

Summary

2.1.232's new Windows Cygwin-symlink check fires on a repository that contains no symlinks of any kind, and its classifierApprovable: false flag removes auto mode's classifier approval for a very large fraction of commands. On this machine it turned a near-prompt-free defaultMode: auto session into a manual approval on most tool calls.

Changelog entry this comes from (2.1.232):

Fixed a Windows permission bypass where Git Bash followed Cygwin-style symlinks that path validation saw as regular files; writes through them now require permission approval

Environment

  • Claude Code 2.1.232 (native install), auto-updated from 2.1.229 → 2.1.232. 2.1.229 and 2.1.231 do not exhibit this; the string Cygwin-emulated symlink is absent from both binaries and present in 2.1.232.
  • Windows 11 Pro 26200, Git Bash (MINGW64) as the Bash tool shell.
  • ~/.claude/settings.json: "permissions": {"defaultMode": "auto"}, "skipAutoPermissionPrompt": true.
  • Project checkout on a normal NTFS volume under C:\<dir>\<project>, no junctions or reparse points anywhere in the path.

The repository has no symlinks

  • git ls-files -s returns zero entries with mode 120000, repo-wide.
  • git config core.symlinks is false, so git never materialised any symlink.
  • dir /AL /S under the reported subtree returns File Not Found (no reparse points).
  • Every path segment of the reported file resolves to a plain directory or plain file under ls -ld.

Reproductions

Paths, hostnames and container names below are placeholders; the shapes are verbatim.

1. False positive on the cookie scan. Denied with Path traverses a Cygwin-emulated symlink (Git Bash follows it, Node does not) — manual approval required:

git add path/to/file.pm && git commit -q -F - <<'MSG' && git log --oneline -1 | cat
<multi-line commit message>
MSG

Bash(git:*) is present in the project allowlist and does not suppress it.

2 and 3. Loss of classifier delegation. These two get a pre-existing static-analysis bail-out as the first half of the message, and the new sentence appended as the second half:

docker exec -e MYSQL_PWD="$(az keyvault secret show --subscription <id> --vault-name <vault> --name <secret> --query value -o tsv)" <container> mariadb -h <host> -P 3306 --ssl -u <user> -e "SELECT ..." 2>&1 | tail -12
Contains shell syntax (string) that cannot be statically analyzed On Windows with Git Bash, the final working directory of this cd-compound cannot be statically determined, so relative write targets cannot be checked for Cygwin-emulated symlinks and this request cannot be delegated to the auto-approval classifier.
cd C:/<dir>/<project> && python - <<'PY'
...
PY
MSYS_NO_PATHCONV=1 docker exec <container> sh -c 'cd /app && perl -Ilib t/some_test.t | head -8'
Contains brace with quote character (expansion obfuscation) On Windows with Git Bash, ... cannot be delegated to the auto-approval classifier.

Identical commands were being approved silently on 2.1.229, and the transcript still shows Allowed by auto mode classifier on commands of the same shape from earlier in the same session.

Why this is disproportionate

From the 2.1.232 bundle, the Windows branch runs the cookie scan on every resolved path in every command, unconditionally, before the path's allow rules are evaluated, and returns a non-classifier-approvable safety check:

if (Yt() === "windows") {
  let c, u = Yun(br(), i, { onCookieRemainder: (d) => c = d });
  if (u !== void 0) {
    ...
    return { allowed: false, resolvedPath: u,
             decisionReason: { type: "safetyCheck", reason: u8s(p.displayTarget),
                               classifierApprovable: false } };
  }
}

and the appended-suffix branch does the same for any cd-compound with a write target:

let k = t.floorEligible && t.compoundCommandHasCd && v.some((C) => C.isWrite && luS(...));
if (e.behavior === "ask" && t.atFinalResultSeam && e.decisionReason?.type !== "rule" && k) {
  ... classifierApprovable: false
}

Because classifierApprovable: false opts the command out of the auto-approval classifier rather than merely adding a prompt, a single false positive doesn't cost one approval — it drops the command out of auto mode entirely. Combined with how common cd X && ..., sh -c '...', $(...) and heredocs are in agent-issued shell commands, this is most of a session.

Requests

  1. Fix the cookie scan's false positive on repositories with no symlinks (reproduction 1).
  2. Consider whether the cd-compound branch needs classifierApprovable: false, or whether the classifier can still be consulted with the unresolved-cwd caveat.
  3. Provide a supported opt-out. I checked the 2.1.232 binary for one: there is no setting and no CLAUDE_CODE_* env var that gates either branch.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗