Security: disableAllHooks bypasses managed organization hooks

Resolved 💬 3 comments Opened Feb 18, 2026 by NirAyalon1 Closed Feb 19, 2026

Bug Report: disableAllHooks Bypasses Managed Organization Hooks

Summary

disableAllHooks: true in project-level local settings (.claude/settings.local.json) can bypass managed/organization-level hooks defined in /Library/Application Support/ClaudeCode/managed-settings.json, contradicting documentation and breaking the security model.

Security Impact

HIGH - Organizations relying on managed hooks for security policies (e.g., preventing dangerous commands, enforcing code scanning, blocking secrets) can be bypassed by any user with a single line in their local settings.

Steps to Reproduce

1. Create Managed Hook (Organization Level)

Create /Library/Application Support/ClaudeCode/managed-settings.json:

{
  "hooks": {
    "UserPromptSubmit": [
      {
        "matcher": "",
        "hooks": [
          {
            "type": "command",
            "command": "echo ':no_entry_sign: MANAGED HOOK BLOCKING - This is from managed-settings.json' && exit 2",
            "timeout": 5000
          }
        ]
      }
    ]
  }
}

2. Restart Claude Code

Hooks are loaded at session startup, so restart is required.

3. Test Without Bypass

Send any message - it should be blocked by the managed hook.

4. Add Bypass in Local Settings

Add to .claude/settings.local.json in your project:

{
  "disableAllHooks": true
}

5. Restart Claude Code Again

6. Test With Bypass

Send any message - managed hook is bypassed, message goes through.

Expected Behavior (Per Documentation)

According to the official documentation and the claude-code-guide agent:

Managed settings take absolute precedence: When an organization administrator sets hooks through server-managed or endpoint-managed settings, these hooks operate at the highest tier and cannot be overridden by any user-level configuration.

Settings precedence hierarchy (from docs):

1. Managed Settings (highest - cannot be overridden)  ← Should prevent bypass
   ↓
2. Command Line Arguments
   ↓
3. Local Project Settings (.claude/settings.local.json)  ← disableAllHooks here
   ↓
4. Project Settings
   ↓
5. User Settings (lowest)

The documentation explicitly states that disableAllHooks should NOT affect managed hooks:

While you can set "disableAllHooks": true in your local settings, this will only disable hooks defined at lower precedence levels (project and user settings). It has no effect on managed hooks.

Actual Behavior

disableAllHooks: true in local settings DOES bypass managed hooks, completely contradicting the documented behavior and security model.

Environment

  • Claude Code Version: [Current version]
  • OS: macOS (Darwin 24.6.0)
  • Managed settings location: /Library/Application Support/ClaudeCode/managed-settings.json
  • Local settings location: .claude/settings.local.json

Security Recommendations

  1. Immediate Fix Needed: disableAllHooks should NEVER disable managed hooks regardless of where it's set
  2. Document Correctly: If this is intended behavior, documentation needs urgent correction and organizations should be warned
  3. Consider Alternative: Add separate disableAllHooksExceptManaged: true option, or make managed hooks immune to all disable flags
  4. Audit Trail: Consider logging when disableAllHooks is used to help detect policy bypass attempts

References

Tested By

Date: 2026-02-18
Tester: Nir Ayalon
Verified: Managed hook successfully bypassed using local settings

View original on GitHub ↗

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