PreToolUse hooks are not invoked for schema-invalid edits to .claude/settings.json — security hooks get no observability of settings-tamper attempts

Open 💬 1 comment Opened Jul 15, 2026 by AstraSyncAI

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?

The hooks documentation says PreToolUse fires "before a tool call executes" with no documented exceptions. Empirically, when the agent uses the Edit tool on a .claude/settings.json file and the resulting content fails settings-schema validation, Claude Code rejects the edit itself ("Claude Code settings.json validation failed after edit: ...") without ever invoking PreToolUse hooks — our hook process is not spawned and writes no trace entry. Schema-valid edits to the same file DO invoke PreToolUse normally.

The result: hook-based security/audit tooling cannot observe schema-invalid tamper attempts against the settings file. The attempt leaves no hook-visible record at all, and the "validation failed after edit" wording suggests the edit is applied before validation, i.e. the tool call executed without its PreToolUse gate.

Reproduction

Setup: register a PreToolUse command hook (matcher Edit|Write) that denies edits matching **/.claude/settings.json and **/.env, and logs every invocation to a trace file.

  1. Control (hook works): ask the agent to edit a scratch .env → hook fires, denies, trace entry written. ✅
  2. Schema-INVALID settings edit: ask the agent to Edit .claude/settings.json adding an unrecognized top-level key (e.g. "probeBaseline": true) → Edit tool returns "Claude Code settings.json validation failed after edit: ... Unrecognized field: probeBaseline". The hook is never invoked (no process spawn, no trace entry). File ends up unchanged. ❌ hook bypassed
  3. Schema-VALID settings edit: ask the agent to Edit the same file removing an entry from permissions.deny (schema-valid) → hook fires and denies as expected, trace entry written. ✅

Observed identically with forward-slash paths on Linux (not a Windows path-separator issue). Steps 2/3 run headless (claude -p ... --permission-mode acceptEdits) with a should-pass control edit in the same session to rule out permission-layer false positives. (Note re: the closed headless-hooks issue #36071: in these headless probes hooks fired and blocked correctly, so this is not a headless artifact.)

Not a duplicate of the environment-wide hook failures (#53254, #26962, #24346 — all closed): in our repro, hooks fire and deny correctly in the same session (step 1 control); only Edit calls on .claude/settings.json whose result fails schema validation skip the hook (step 2), while schema-valid edits to the same file invoke it (step 3). Related but distinct: #44482 (closed — pre-approved permission bypass of hooks, a different trigger), #30519 (permissions-matching umbrella; relevant only to the Write() rule footnote below).

Expected

Either (a) PreToolUse fires for every Edit/Write tool call including those targeting settings files, with schema validation happening after the hook gate; or (b) the special-casing is documented in the hooks docs so security tooling authors know settings-file edits can bypass PreToolUse observation when schema-invalid.

Impact

  • Hook-based governance/audit tools (ours governs tool calls against a local policy) have a blind spot: settings-tamper attempts that happen to be schema-invalid are invisible to them.
  • The error text implies apply-then-validate ordering for a security-sensitive file.

What works (for anyone else building on this)

permissions.deny rules ARE evaluated for settings self-edits, before hooks, and block them — including the edit that would remove the deny rules themselves (verified on 2.1.210: "deny": ["Edit(**/.claude/settings.json)"] blocks Edit and Write tools; note the session-start warning is correct that Write(path) rules are never matched by file permission checks, Edit rules cover all file-editing tools). So native deny rules are a viable mitigation; the remaining issue is hook observability of the schema-invalid class.

Questions

  1. Is the pre-hook rejection of schema-invalid settings edits intentional?
  2. Is the ordering (edit applied → validated → reverted?) what the "validation failed after edit" message implies, and is the file ever transiently modified on disk?
  3. Could schema-invalid settings edits emit PreToolUse (or at least PostToolUseFailure-style) events so audit hooks see the attempt?

Environment Info

  • Platform: linux (WSL2, Ubuntu) — also observed on Windows 11 desktop app, 2026-07-11
  • Version: 2.1.210
  • Hook: PreToolUse command hook matching Edit|Write|... (AstraSync Local Guard, registered in ~/.claude/settings.json)

Errors

[]

View original on GitHub ↗

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