claude-code - 💡(How to fix) Fix Feature request: per-repo hook-approval prompt for ./.claude/settings.json (parallel to tool permissions)

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

When Claude Code starts in a repository containing a ./.claude/settings.json, any SessionStart (and related) hooks declared there execute unconditionally. There is currently no approval gate for repo-local hook autoload. --dangerously-skip-permissions governs tool execution, but hook autoload is a separate path not covered by the permission system. Cloning and opening an untrusted repository can therefore run arbitrary commands on the developer machine before the user takes any action.

Root Cause

When Claude Code starts in a repository containing a ./.claude/settings.json, any SessionStart (and related) hooks declared there execute unconditionally. There is currently no approval gate for repo-local hook autoload. --dangerously-skip-permissions governs tool execution, but hook autoload is a separate path not covered by the permission system. Cloning and opening an untrusted repository can therefore run arbitrary commands on the developer machine before the user takes any action.

Fix Action

Fix / Workaround

This mitigation belongs in the product, not in per-user shell wrappers. Users today can only protect themselves with bespoke shell aliases that hash settings.json before launch — which break on IDE integrations, raw-binary invocation, and CI. A first-class per-repo hook-approval prompt closes the vector for every invocation path and benefits the whole user base.

RAW_BUFFERClick to expand / collapse

Summary

When Claude Code starts in a repository containing a ./.claude/settings.json, any SessionStart (and related) hooks declared there execute unconditionally. There is currently no approval gate for repo-local hook autoload. --dangerously-skip-permissions governs tool execution, but hook autoload is a separate path not covered by the permission system. Cloning and opening an untrusted repository can therefore run arbitrary commands on the developer machine before the user takes any action.

Threat model

  • Vector: a repository ships a malicious ./.claude/settings.json with a SessionStart hook (command / script).
  • Trigger: developer clones the repo (PR review, CTF, supply-chain audit, sample project) and starts Claude Code in that directory.
  • Result: hook command executes with the developer's privileges. On a typical workstation that exposes SSH keys, credential-manager sessions, and browser cookies — a full local compromise from a single clone-and-open.
  • Public PoC (May 2026): https://github.com/s0ld13rr/claude-code-backdoor demonstrates the malicious-repo → RCE chain.

Proposed UX

The first time Claude Code encounters a ./.claude/settings.json that declares hooks in a given repo path:

  1. Render the hook definitions (commands, matchers, scripts) for the user to read.
  2. Prompt: Trust hooks for this repo? [y/N/diff]. Default No. diff shows the full hook content or a diff against the last-approved version.
  3. Persist the trust decision keyed by repo path plus a content hash, so re-approval is only required when the hook set changes.
  4. Until approved, hooks do not run — fail closed, matching the principle already used for tool permissions.

Why at the CLI layer

This mitigation belongs in the product, not in per-user shell wrappers. Users today can only protect themselves with bespoke shell aliases that hash settings.json before launch — which break on IDE integrations, raw-binary invocation, and CI. A first-class per-repo hook-approval prompt closes the vector for every invocation path and benefits the whole user base.

Alternatives considered

  • Disabling hooks globally: loses the feature's value.
  • Shell-wrapper hashing (user-side): partial; misses non-shell invocation paths.
  • Treating hooks under the existing tool-permission flow: viable if the permission model is extended to cover hook autoload as a distinct, fail-closed capability.

Request

Add a per-repo hook-approval gate parallel to the existing tool-permission prompts — fail-closed by default, with persisted per-repo trust. Scope this initial request to repo-local hooks (./.claude/settings.json). As a follow-up, the same fail-closed approval principle is worth considering for other repo-local autoexec surfaces — for example project-scoped MCP server configs and repo-local skills — since they share the same clone-and-open trust boundary. Happy to provide additional repro detail; suggest CC to the security team.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING