Hooks not firing. Cannot have guardrails

Where does the bug appear (feature/product)?

Cursor CLI

Describe the Bug

On Windows, Cursor CLI 2026.08.11-e8db854 does not run user-level hooks at all in an interactive agent session.

I have a deny-based fence in ~/.cursor/hooks.json (failClosed: true on beforeReadFile, preToolUse, and
beforeShellExecution, plus a sessionStart policy injection). The agent was asked to read files under
%USERPROFILE%.claude. It did: Read, Glob, Grep, and Shell all succeeded. No deny, no failClosed brick, no
sessionStart additional_context in the agent prompt.

This is not a matcher miss and not a broken hook script.

• The same command, given a real preToolUse / Read payload for a path under %USERPROFILE%.claude, returns
{“permission”:“deny”,…} with exit 0 when I invoke it myself from ~/.cursor (the documented user-hook cwd).
• If Cursor had spawned the hook and the process had failed to start, failClosed: true should have blocked the
tools. It did not.
• beforeShellExecution has been listed as working in CLI since January 2026. Shell still went through.

So the host never entered the hook loop. A deny-based guardrail cannot hold if the process is never spawned and/or
permission: deny is not applied.

I already applied the documented workaround from Cursor CLI ignores hooks from marketplace plugin
(Cursor CLI ignores hooks from marketplace plugin): the fence is also in
~/.cursor/hooks.json, not only in a local/marketplace plugin. File-based hooks still did not fire.

This looks like the same class of failure as the related report on Cursor CLI doesn’t send all events defined in hooks
(Cursor CLI doesn't send all events defined in hooks) titled “Cursor-agent CLI never
invokes hooks.json on Linux (2026.08.11) — same version works on macOS.” I am on that exact CLI version, on Windows.

Steps to Reproduce

  1. Install a user hook at ~/.cursor/hooks.json that denies access to %USERPROFILE%.claude on beforeReadFile,
    preToolUse (Read/Grep/Glob/Shell), and beforeShellExecution, with failClosed: true. Also register sessionStart to
    return additional_context with a unique canary string.
  2. Confirm the hook script works outside Cursor: from ~/.cursor, pipe a JSON payload with hook_event_name:
    preToolUse, tool_name: Read, and tool_input.path under %USERPROFILE%.claude. Observe permission: deny.
  3. Start an interactive cursor-agent session in a workspace (mine was a folder that is not itself a git repo).
  4. Ask the agent to read a file under %USERPROFILE%.claude (and/or list that directory with Shell).

Expected Behavior

• sessionStart injects the canary into the agent’s initial context.
• Read / Glob / Grep / Shell targeting %USERPROFILE%.claude are denied.
• If the hook process fails to start or prints invalid JSON, failClosed: true blocks the tool.

Operating System

Windows 10/11

Version Information

Cursor CLI 2026.08.11-e8db854

For AI issues: which model did you use?

grok 4.6 high

Additional Information

Actual Behavior

• No canary / HARD POLICY in the agent context.
• Read, Glob, Grep, and Shell of %USERPROFILE%.claude all succeed and return file contents.
• failClosed: true never trips.
• Manual invoke of the identical command still denies.

That combination means the CLI agent loop never spawned the hook. It is not “the script returned allow.”

Does this stop you from using Cursor

No - Cursor works, but with this issue

I got a fat stack of guard rails I’m trying to enforce for long horizon work. This particular guard rail blocks cursor for peeking at claude’s skills and files. A different issue forced me to abandon using MCP in my guard rail to allow for an actor-critic guard rail and a actor-advisor guard rail.

I want to have cursor reach out to codex and claude while it does coding, so cursor(grok) is forced defend it’s decisions and actions. But the MCP that’s part of the plugin won’t load due to a cursor CLI bug. So the critic and advisor are jammed in an error state don’t function.

Now my advisor\critics are fine, so long as there’s no MCP. Just straight up cli calls out to codex or claude. But I noticed cursor digging into claude’s skills. There’s a busted skill in claude that’s causing cursor to abandon work. It shouldn’t even be loading that skill, but cursor cli just ignore the setting in the cursor UI app that tells it to mind it’s own business. in settings >> agents >> include third-party plugins, skills and other configs.

Cursor is a damned trash panda that keeps breaking in my neighbour’s yard and getting sick off what it finds in the garbage.

I should be irritated right now, but after one shotting everything that whips across my screens for months, spending hours frustrated is nostalgic. I just don’t feel this way with Claude Code.

Hey, thanks for the detailed report (and for the trash panda, I appreciated it).

Good news: your hooks are actually running. Bad news: on Windows the deny rule isn’t applied for a specific reason. The JSON payload that the CLI pipes to the hook via stdin on Windows gets prefixed with a UTF-8 BOM \uFEFF. Because of that, a standard JSON.parse fails, and the defensive catch in the script quietly falls back to allow. That’s why your manual test denies (stdin has no BOM), but the real run doesn’t. This also explains why failClosed behaved inconsistently.

Workaround: strip the BOM before parsing:

const raw = require("fs").readFileSync(0, "utf8").replace(/^\uFEFF/, "");
const payload = JSON.parse(raw);

After this, your deny fence and failClosed should work correctly on Windows. You should apply the same fix to Claude-imported hooks from ~/.claude too, they fail for the same reason.

This is a known issue we’re tracking, detailed in this thread: On Windows, Cursor’s hook stdin JSON payload includes a UTF-8 BOM that breaks standard JSON.parse(), causing security guards to silently degrade to allowing commands across all agent channels. I can’t give an ETA yet, but I shared this with the team as confirmation and from the CLI side too.

The MCP-from-plugin not loading in the CLI, and the “include third-party plugins, skills and other configs” setting being ignored by the CLI, are separate issues and not related to the BOM. To avoid mixing everything in one thread and so each can be tracked, please open separate threads for them with your CLI version and repro steps. We’ll look into each one.

Let me know if stripping the BOM helped.

You absolute legend, thank you Dean!

Workaround: strip the BOM before parsing:

I just watched my cursor agent bonk off the guard rail. This has cut so much stress for me knowing enforcing the rules DOES work, I’m just working with cutting edge software and maturity takes time!

Access to ~/.claude was blocked. Retrying so you can approve it if you want
that fence lifted.

I tried to read C:\Users\Jarry.claude and the environment blocked it.

Listing the directory and globbing its contents were both rejected by a
claude-home-fence-guardrail that bans access to ~/.claude from Cursor. I
retried so you could approve it, and that was rejected too.

I did not fall back to another path, and I did not try a workaround. Claude
Code’s home directory is not readable in this session.

Now I can trust Cursor CLI to supervise work running overnight! (My other guard rails are now working too!)

(sorry for the pollution of the unrelated issue. My intent was to provide context on the what and why of my task)

Glad it worked and the hooks are holding the line now. Overnight supervision with a working deny fence is exactly what this was for.

No worries about the “pollution”, the context was helpful. Just so the two remaining items don’t get lost and we can track them properly, please create separate threads for each one:

  • MCP from the plugin doesn’t load in the CLI
  • The “include third-party plugins, skills and other configs” setting is ignored by the CLI

Please add the CLI version and repro steps there, and we’ll handle each one separately. If anything else comes up, let me know.