Edit tool applied changes without a permission prompt despite `ask` rules for Edit (Windows, 2.1.278)
Summary
In a long interactive session on Windows, several Edit calls on files inside the project directory were applied without showing the yes/no permission prompt, although Edit was covered by permissions.ask rules in both the user settings and the project settings, the permission mode was default, and no allow rule, hook decision or session grant covered those files. Reading the bundled code, the terminal branch of the write-permission check is behavior: "ask", so a prompt was expected in every case.
Environment
- Claude Code 2.1.278, native install (
~/.local/bin/claude), Windows 10 Pro 19045 - Shell for the Bash tool: Git Bash (MSYS);
CLAUDE_CODE_USE_POWERSHELL_TOOL=1 - Session resumed with
--resumeearlier the same day;~/.claude/settings.jsonwas a symlink to a file in a cloud-synced folder at the time
Configuration at the time
User settings (~/.claude/settings.json):
"permissions": {
"ask": ["Edit(//d/Sync/**)", "NotebookEdit", "Bash(python *)", "..."],
"allow": ["Edit(//c/Users/<user>/AppData/Local/Temp/claude/**)", "Bash(latexmk:*)", "..."],
"defaultMode": "default",
"disableBypassPermissionsMode": "disable",
"additionalDirectories": ["C:\\Users\\<user>\\AppData\\Local\\Temp\\claude"]
}
Project settings (<project>/.claude/settings.json, present since 2026-09-14):
{ "permissions": { "ask": ["Edit", "Write", "NotebookEdit"], "disableAutoMode": "disable" } }
Project settings.local.json: only allow rules for Bash/PowerShell/MCP, none for Edit or Write.~/.claude.json: no allowedTools entry for Edit on this project.
A PreToolUse hook on Edit|Write|NotebookEdit only returns deny for files outside the project and exits 0 (no decision) for files inside it.
What happened
The model called Edit on <project>/letter-a.tex and <project>/letter-b.tex several times (e.g. 12:02:51Z, 12:02:58Z, 12:03:01Z, then 12:04:36Z and 12:04:38Z, only 1.6 s apart). The edits were applied immediately. The user states no prompt was shown and that "don't ask again" was never chosen in this session.
What the session transcript shows
- Every
permission-moderecord around those edits reports"permissionMode": "default"(records immediately before and between the edits). NoacceptEditsorautomode record exists after 2026-09-13. - The tool-result records for those edits carry no permission decision fields (no
permission,approved,decision,bypass). - No
PreToolUse:Edithook record exists for those calls (the two hook records in the whole transcript, on other days, arehook_non_blocking_error, exit code 5, from a Git Bash fork failure). - No
alwaysAllow/updatedPermissions/permissionSuggestionsentries; no refusal ("The user doesn't want to take this action") anywhere in the 20,934-line transcript. ~/.claude/sessions/<pid>.jsonfor the same session later shows"waitingFor": "permission prompt", so prompts do work in general in this session.
Expected
With mode default, an ask rule matching Edit (a bare Edit rule in the project settings, which the bundle itself describes as matching "ANY path"), and no matching allow rule, every Edit inside the project should prompt. In the bundled write-permission check (for (rule of askRules) ... return {behavior:"ask"} first; mode === "acceptEdits" && insideWorkingDirs → allow; allow rule → allow; otherwise return {behavior:"ask"}), there is no path that yields allow for this configuration.
Notes (possibly related, unverified)
- The user-level
askrule was written in MSYS form (Edit(//d/Sync/**)) while thefile_pathcompared is a Windows path (D:\Sync\...); whether that form matches on Windows is not documented. It should not matter here, because the project-level bareEditrule exists as well. ~/.claude.jsoncontains a cached remote feature"tengu_quill_harbor": "acceptEdits"undercachedGrowthBookFeatures; the stringquill_harbordoes not occur in the 2.1.278 bundle, so it appears to be a stale cache entry and is listed only for completeness.
Steps to reproduce (as observed, not yet reproduced in a fresh session)
- Windows, Git Bash as Bash tool shell, user settings with
Edit(//d/<sync-folder>/**)inask, project settings with bareEdit/Writeinask,defaultMode: default. - Long session, resumed with
--resume, manyEditprompts accepted one by one earlier in the day. - Model issues several
Editcalls in a single assistant turn on files inside the project. - Observe whether each call prompts.
Impact
Files were modified without the user's approval, which the user's whole permission setup is designed to prevent.
Related issues (not duplicates, checked before filing)
- #95634 — Desktop app (WSL2): Edit/Read allow rules in project
.claude/settings.jsonnot applied in Manual mode (this report is the terminal CLI on native Windows, and concernsaskrules) - #79300 — Native Windows: working directory does not scope shell-tool filesystem access
- #6527 — ask list is ignored when "Bash" is in allow list (Bash tool; here no bare allow for Edit exists)
Showing cached comments. Read the full discussion on GitHub ↗
3 Comments
Second occurrence, on a different platform and path: Linux, 2.1.284, writes to the auto-memory directory.
Environment: Claude Code 2.1.284, Ubuntu (kernel 6.8).
Configuration:
permissions.askcontains bare"Edit","Write"and"NotebookEdit";defaultModeis"default"; noallowrule matches Edit or Write.PreToolUsehook onEdit|Write|NotebookEditexits 0 with no output (no decision) for paths under~/.claude/projects/<project>/memory/.What happened: the model called
Writeto create~/.claude/projects/<project>/memory/<name>.md, thenEditon~/.claude/projects/<project>/memory/MEMORY.md. Both were applied immediately, with no permission prompt. They were the first Edit/Write calls of the session, so no session-level grant could exist.Transcript: all 57
permissionModerecords of the session are"default".Expected: a prompt with the diff for both calls, since bare
EditandWriteare inpermissions.ask.This may be the other side of #79206 / #79883: on 2.1.284 the memory directory seems to be exempt from permission checks, and the exemption also overrides explicit
askrules. If the exemption is intended, an explicitaskrule should still win, or the exemption should be documented and configurable.Update after a full day of verification (2026-10-05, Claude Code 2.1.289, Windows 10, Git Bash).
1. In manual mode (
default),askrules on Edit/Write are still bypassed. This is the serious one.The configuration is correct by the documentation, and it has been correct in every incident:
permissions.defaultMode: "default"in user settings;ask: ["Edit", "Write", "NotebookEdit"], bare, in user settings and in project settings;disableBypassPermissionsMode: "disable".PreToolUsehook matched onEdit|Write|NotebookEditthat returnspermissionDecision: "ask"for every file inside the project and"deny"for every file outside it.allowrule covering the project, no mod, no plugin, no managed settings.permissions.md says rules are evaluated "deny, then ask, then allow" and that an
askrule "still prompts even when the hook returned allow or ask". permission-modes.md lists "tools matched by an explicit ask rule" among the actions no mode auto-approves, "in any mode". By the documentation, an Edit on a project file in this setup cannot be applied without a prompt. It is.Evidence from the 2026-09-22 session (2.1.278), re-read line by line today:
permissionModeisdefaultfor the entire day: zero occurrences ofacceptEdits,auto,planorExitPlanMode.On 2026-10-03 (2.1.284, then 2.1.288,
defaultmode for the whole session) the same thing: Write and Edit in the auto-memory directory, fourcpcommands for which the hook had returnedask(recorded in the transcript, then ignored), onebashinvocation, all applied without a Yes/No.Nothing in the CHANGELOG up to 2.1.289 addresses this. The only fix ever announced (#42797, 2.1.233) was reported regressed on 2.1.270. Same symptom, all open, no maintainer response: #79771, #81041, #83362, #87639, #88604, #89561, #95741. #79356 and #86754 were closed by the stale bot, not fixed. In every one of these reports
denyrules and hooks exiting with code 2 work;askdoes not. Users are now building deny-based gates to obtain the guarantee the documentedaskpath does not give. A permission system whose "ask" branch cannot be trusted in its default mode is not a permission system.2. In auto mode it gets worse: Claude Code itself instructs the model to bypass Edit/Write
When the session is in auto mode, the harness injects this instruction into the model's context. Received verbatim in the main session and, independently, by a subagent:
A file written with
sed -ior a heredoc from Bash never reaches aPreToolUsehook matched onEdit|Write|NotebookEditand never matches anaskrule onEditorWrite. The whole file-protection layer described in permissions.md and hooks.md is routed around, by design, and nothing in the documentation says so. What is left is prose in CLAUDE.md andaskrules on individual Bash commands, which have to enumeratesed -i,tee,dd,patch, heredoc redirections and every PowerShell alias. That is not a security model, it is a blacklist the user has to maintain against the harness's own instructions.This needs one of two things: a documented statement that auto mode is incompatible with file-level
askrules and Edit/Write hooks, or a change so that in auto mode a Bash command that writes a file goes through the same gate as Edit/Write.3. Two smaller points
PreToolUsehook that crashes with any exit code other than 2 lets the call proceed (hooks.md: "non-blocking error"). On Windows, Git Bash fork failures (exit 5) are not rare, so a protective hook can vanish for one call without a trace. Fail-open is the wrong default for a gate.askrule onWrite. If it is intended, document it.Two direct questions for the maintainers: (1) is there any configuration in which an
askrule onEditis guaranteed to prompt in an interactivedefault-mode session, yes or no; (2) is the auto-mode instruction meant to bypass Edit/Write hooks andaskrules, yes or no?@bcherny sorry to ping you directly, but you are the only person from Anthropic who has answered on this topic (#42797, #79206), and it has been sitting for weeks across a dozen issues.
I'll say it plainly. I use Claude Code on documents where every single change has to be reviewed before it lands: technical reports, legal text, configuration other people depend on. The only reason I can put an LLM on that kind of work is the diff prompt. I read it, I say yes or no. That is the whole contract.
Right now the contract does not hold. With
askrules on Edit and Write, a PreToolUse hook that returns "ask", manual mode, no allow rules, edits still get applied with no prompt. Not every time. Often enough that I cannot trust a session anymore, and "not every time" is useless for this work: one unreviewed change in a document that goes out is one too many. The evidence, including transcripts, is in my comment above.And even when the prompt does work, it only guards two tools. The model has a dozen other ways to write a file, and it knows every one of them:
sed -i, a heredoc,tee,cp,python -c,Set-Contentin PowerShell, a redirection. None of those reach an Edit/Write hook or anaskrule on Edit/Write. In auto mode the harness itself tells the model to use exactly those ("make file changes with sed, heredocs, or short scripts, rather than using the dedicated Read, Edit, or Write tools"). So the user is left writing ask rules and Bash hooks for every command that can touch a file, one by one, and the model will still find the one that was missed. A yes/no gate that the tool on the other side knows how to walk around is not a gate.It happened again while I was writing this: a Stop hook died with
bash: fatal error - add_item ("\??\C:\Program Files\Git", "/", ...) failed, errno 1. Had that been the PreToolUse hook on Edit, the edit would have gone through, because a hook that crashes with anything other than exit 2 is a "non-blocking error". Fail-open is the wrong default for a safety gate.This is not a feature request. It is the one guarantee the permission system exists to give, and it decides whether Claude Code can be used on serious documents at all.
Two questions, yes or no is fine:
Same problem, reported by others, all without a maintainer answer:
claude -pEven a "we know, here is the plan" would help. Silence is what makes people build deny-based workarounds and stop trusting the product.