Hooks returning deny do not seem to block tool execution (possible security concern)

Where does the bug appear (feature/product)?

Cursor IDE

Describe the Bug

I am currently experimenting with Cursor hooks to enforce a strict security rule:
the agent should never read files outside of the current workspace root.

My intention was to implement this as a hard guardrail via hooks. As a first step, I created a minimal test that simply returns {"decision":"deny"} for every read attempt.

However, the read operation still proceeds, even though the hook clearly executes and returns deny.

This surprised me quite a bit, because it suggests that hook decisions might not actually be enforced.

Hook log output (excerpt)

The logs clearly show that:

  • the hook is executed
  • the response is parsed successfully
  • the decision returned is deny

Example:

Hook step requested: preToolUse
Found 1 hook(s) to execute for step: preToolUse
Executing hook 1/1 from project config

INPUT:
{
  "tool_name": "Read",
  "tool_input": {
    "file_path": "/projects/another-project/pom.xml"
  },
  "workspace_roots": [
    "/projects/my-project"
  ]
}

OUTPUT:
{
  "decision": "deny"
}

Hook 1 executed successfully and returned valid response
Merged 1 valid response(s) for step preToolUse

The same happens for beforeReadFile, which also returns:

{
  "decision": "deny"
}

Despite this, the read still proceeds.

Why this seems problematic

My expectation was that hooks could be used to enforce hard restrictions, especially for security-related policies like preventing access outside the workspace.

If a deny decision is ignored even in such a minimal setup, it raises some concerns about whether hooks can actually be relied upon to enforce security boundaries.

This matters in practice because:

  • LLM agents can be misled or manipulated via prompts
  • accidental tool usage can happen
  • organizations may want to enforce strict access policies

In such environments, hooks appear to be the natural mechanism for enforcing guardrails.

Questions

  1. Is this the expected behavior?
  2. Are hook decisions currently advisory rather than enforced?
  3. Is there any reliable way to prevent the agent from reading files outside the workspace?

Steps to Reproduce

.cursor/hooks/block-external-reads.sh

echo '{"decision":"deny"}'

.cursor/hooks/hooks.json

{
  "version": 1,
  "hooks": {
    "beforeReadFile": [
      {
        "command": "bash .cursor/hooks/block-external-reads.sh"
      }
    ],
    "preToolUse": [
      {
        "matcher": "Read",
        "command": "bash .cursor/hooks/block-external-reads.sh"
      }
    ]
  }
}

Prompt something like

read "../another-project/pom.xml". Name the projects current version.

Expected Behavior

Access should be prevented

Operating System

MacOS

Version Information

Version: 2.6.18
VSCode Version: 1.105.1
Commit: 68fbec5aed9da587d1c6a64172792f505bafa250
Date: 2026-03-10T02:01:17.430Z
Build Type: Stable
Release Track: Default
Electron: 39.6.0
Chromium: 142.0.7444.265
Node.js: 22.22.0
V8: 14.2.231.22-electron.0
OS: Darwin arm64 25.3.0

Does this stop you from using Cursor

Yes - Cursor is unusable

Hey, thanks for the report. This is a known issue. The hooks do fire and correctly return deny, but right now the agent doesn’t apply that decision for file read operations. The same bug is reported here: Hook beforeReadFile does not work in the agent

The team is aware. Sadly, there’s no ETA for a fix yet.

As a workaround to prevent reading files outside the workspace, you can use .cursorignore. The agent won’t be able to see files you add there. This doesn’t fully cover your use case (you can’t block arbitrary paths outside the project via .cursorignore), but it works for specific files and directories.

On your questions:

  1. No, this isn’t expected behavior. deny should block the operation.
  2. By design, hooks aren’t advisory, but enforcement for file reads is currently broken.
  3. The only reliable option right now is .cursorignore, but it only works for files inside the workspace tree.

Your report helps with prioritization, especially with the security angle for team and enterprise use cases.

Thanks for the clarification and for confirming that this is a known issue, @deanrie

However, I have to admit that the current situation is somewhat concerning from my perspective.

First, .cursorignore unfortunately does not really address the use case I described. It only applies to files inside the workspace, while the core problem here is preventing access to paths outside the workspace. For that scenario, it doesn’t provide a meaningful safeguard.

Second, the lack of an ETA is worrying given that this appears to affect a security-relevant mechanism. Hooks seem to be the only built-in mechanism intended to enforce guardrails around agent behavior. If a deny decision is currently ignored for file reads, that significantly limits their usefulness for enforcing security policies.

From the outside, this creates a somewhat uncomfortable situation: hooks are presented as a way to control or restrict agent behavior, but in practice one of the most critical enforcement paths does not currently work.

I completely understand that fixing bugs takes time, but issues that impact the reliability of security controls tend to be quite high priority in many environments.

Thanks again for the clarification, and I hope this helps highlight why the issue may be particularly important for teams trying to run Cursor in more security-sensitive setups.

1 Like