anthropics / anthropics/claude-code

[BUG] Windows: path-guard hook shared with Linux denies every Edit/Write, even on its own settings file (tool_input.file_path is D:\... but hook shell $PWD/$HOME are POSIX /d/...)

オープン
#94,256 コメント 1 件 リアクション 0 件 担当者 0 名 GitHub で見る
area:hooks bug has repro platform:windows
主要言語
Python
スター
145k
フォーク
23.1k
PR マージ指標
PR 指標を取得中

説明

### Environment
- Claude Code 2.1.270, native Windows 10 Pro (10.0.19045); hook commands run in Git Bash
- The same project is also used on Ubuntu. The folder is synced between the machines, so `.claude/settings.json` (permissions + hooks) is shared.

### What's wrong
The project settings contain a PreToolUse guard for `Edit|Write|NotebookEdit` that only allows files inside the project, the memory dir and the scratchpad (deny message abridged):

```json
"command": "jq -r '.tool_input.file_path // .tool_input.notebook_path // empty' | { read -r f; case \"$f\" in \"$PWD\"/*|\"$HOME\"/.claude/*|/tmp/claude-*) exit 0;; *) printf '%s' '{\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"BLOCKED: file outside the project\"}}';; esac; }"
```

It works on Linux. On Windows it denies **every** Edit/Write, because the two sides of the comparison use different path formats:

| value | on Windows |
|---|---|
| `tool_input.file_path` | `D:\Dropbox\project\doc.tex` |
| `$PWD` in the hook shell (Git Bash) | `/d/Dropbox/project` |
| memory file vs `$HOME` | `C:\Users\\.claude\projects\...` vs `/c/Users/` |
| scratchpad | `C:\Users\\AppData\Local\Temp\claude\...` (Git Bash sees `/tmp/claude/...`, not `/tmp/claude-*`) |

Consequences:
1. The guard fails **closed**: every file inside the project is reported as "outside the project".
2. It also denies edits to `.claude/settings.json` itself, so the session cannot repair it. Claude is locked out, and the user has to edit the JSON by hand (or explicitly authorize a shell write that bypasses the Edit/Write diff prompt).
3. The only feedback is the hook's own deny message; nothing points to a path-format mismatch, so it looks like a permissions failure.

Because the settings are shared across machines, path rules can only be portable if they are relative to the project, and a hook is the natural place to express that. On Windows, however, the hook sees paths in a different format than its own shell.

### Related
- #83877 (closed, docs): documents that `file_path` is backslash-separated on Windows and mentions the `$PWD` trap as a fail-*open* case. The mismatch itself remains; with allow-list guards it fails closed and self-locks.
- #76490, #64432: permission rules not matching Windows paths, i.e. the same missing path normalization on Windows.

### What should happen
A settings file that works on Linux/macOS should not silently change meaning on Windows. For example:
- pass hooks paths in the format of the shell that runs them (POSIX under Git Bash), or add normalized fields next to the raw ones (e.g. `file_path_posix`, `cwd_posix`);
- expose the project and scratchpad dirs (e.g. `CLAUDE_PROJECT_DIR`) in a form directly comparable with `tool_input.file_path`;
- offer a recovery path (e.g. from `/hooks`) when a hook blocks edits to the settings file that defines it.

### Steps to reproduce
1. Native Windows, Git Bash as hook shell.
2. Put the hook above in `/.claude/settings.json`.
3. Ask Claude to edit any file in the project: denied ("outside the project").
4. Ask Claude to fix `.claude/settings.json`: denied as well.

### Workaround
Normalize both sides with `cygpath` (on Linux it does not exist and the path is used as is):

```sh
f=$(jq -r '.tool_input.file_path // .tool_input.notebook_path // empty')
u() { cygpath -u "$1" 2>/dev/null || printf '%s' "$1"; }
f=$(u "$f"); p=$(u "${CLAUDE_PROJECT_DIR:-$PWD}")
case "$f" in "$p"/*|"$HOME"/.claude/*|/tmp/claude-*|/tmp/claude/*|/c/Users/*/AppData/Local/Temp/claude/*) exit 0;; *) printf '%s' '';; esac
```

Checked on Windows: project, memory and scratchpad paths are allowed; `D:\Dropbox\other\x.tex` and `D:\Dropbox\project-other\x.tex` are denied; POSIX-style paths behave the same.

コントリビューションガイド

このリポジトリのコントリビューションガイドは索引されていません

調査の方向性

Reproduce with the PreToolUse command in /.claude/settings.json under native Windows with Git Bash, then compare the Windows tool_input paths with the hook's $PWD/$HOME values. Check the /hooks recovery path described in the issue. Done means shared settings allow project, memory, and scratchpad edits while denying the two out-of-scope examples on Windows and Linux without locking edits to settings.json.

索引モデルが issue の本文から書いたものです。

評価

技術スタック
bash
領域
cli, tooling
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
活発
明瞭さ
おおむね明確
初心者へのやさしさ
48/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。