[BUG] Invalid settings file silently drops `permissions.deny`/`ask` rules mid-session (fail-open)

Status Open
Reported on v2.1.214
Maintainer reply None cached
Activity 2 comments · opened Jul 18, 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?

While a session is running, if a watched settings file becomes syntactically
invalid (e.g. an intermediate save during hand-editing), the file is rejected
as a whole and its permissions.deny / permissions.ask rules silently stop
being enforced
. A command that was deterministically denied seconds earlier
runs with no prompt and no warning. Enforcement returns only once the file
parses again.

The docs say an invalid settings file is "rejected as a whole and reported",
but do not say the rejection is fail-open, and in print/stream-json mode
nothing is reported at all — the only symptom is that guardrails vanish.

What I observed

During a long interactive session, I had these settings:

  • defaultMode: "auto"
  • permissions.ask including "Bash(git push:*)"
  • model: Fable 5

I made some invalid hand edits to ~/.claude/settings.json. Multiple git push * commands were auto-approved while it was invalid.

The only indicator I had that something was wrong was that my custom spinnerVerbs was not being respected.

What Should Happen?

Either keep enforcing the last-known-good rules until the file parses again (fail-closed), or at minimum surface a prominent, blocking warning that permission rules from that file are no longer in effect (mirroring the error shown when starting a new claude session).

Silent fail-open turns a typo during a settings edit into an enforcement gap for every concurrently running session that watches the file.

Error Messages/Logs

Steps to Reproduce

mkdir -p repro/.claude && cd repro
printf '{"permissions":{"deny":["Bash(uname:*)"]}}' > .claude/settings.json

Drive one session across turns with stream-json input:

claude -p --input-format stream-json --output-format stream-json \
  --verbose --model haiku --max-turns 12

Send this user message (as {"type":"user","message":{"role":"user","content":[{"type":"text","text":"..."}]}})
for each turn, mutating the settings file between turns:

Run this exact bash command: uname — then report what happened. If the tool call is denied or blocked, reply with only BLOCKED plus the denial text. Do not try alternatives or workarounds.

| Turn | settings.json state | Result |
|------|----------------------------------------------|---------------------------------|
| 1 | valid, deny present | denied (correct) |
| 2 | invalid JSON (trailing { appended) | uname executes — fail-open|
| 3 | valid, deny removed | executes (proves hot-reload live)|
| 4 | valid, deny restored | denied (recovery works) |

Claude Model

Other

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.214

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

VS Code integrated terminal

Additional Information

  • #78056 documents the same whole-file-discard behavior. However, that issue is about _how_ the settings file gets corrupted. This issue is about how to securely inform the use of the effects of the corruption.
  • #42797 is about how permissions.ask is applied in auto-mode. But it doesn't address invalid settings.json files.
  • #62506 is similar, but focuses on intentional/malicious, valid changes to settings files.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗