Skip to content

All posts

AI

Cursor rules vs enforced policy: what stops an agent

Ritesh Patel

AI: Cursor rules vs enforced policy: what stops an agent

Cursor rules are guidance, so an agent can ignore them. What stops an agent is a control the harness applies to each action: a hook that returns deny, a sandbox network policy, an admin-set run mode, or an Enterprise MCP allowlist. Team Rules become mandatory only with “Enforce this rule” turned on.

Why a rules file is not a control

Cursor rules shape what the agent tries to do. Project rules live in .cursor/rules as .mdc files, and an AGENTS.md in the project root works as an alternative. Team Rules are managed in the dashboard and have no file. A plain .md file in .cursor/rules is ignored, because the rules system reads only files with frontmatter.

Cursor’s rules documentation is direct about the limit: AI guidance should not be your only security control. A rule can make the agent less likely to run rm -rf, but a rule cannot make a shell command fail. Treat rules as the first layer and put a blocking control under them.

Advisory and enforced controls side by side

The table lists each Cursor control we found in the docs, who sets it, and whether it can stop a call. Rows that answer “Yes” or name a restriction are the ones that act on a call. The rest only advise or remove a prompt.

Control Who sets it Advisory or enforced Can it stop a tool call?
Project rules (.cursor/rules/*.mdc, AGENTS.md) Developer, in the repo Advisory No
Team Rules, not enforced Admin, in the dashboard Advisory. A member can turn it off in Customize No
Team Rules, “Enforce this rule” on Admin, in the dashboard Required for every member. Still guidance No
permissions.json allowlists Developer, or the repo Not a security boundary. Skips approval prompts No. It removes a prompt
Run mode set in the team dashboard Admin Enforced. Overrides permissions.json and the IDE allowlist Sets which calls run without approval
Sandbox networkPolicy Developer files, plus team-admin policy Team-admin policy cannot be weakened by either file Limits what sandboxed commands can reach
Hooks in hooks.json Developer, or IT through MDM Blocking when the hook exits with code 2 or returns deny Yes
MCP allowlist (MCP Configuration) Admin, in the dashboard Enterprise only Restricts which servers members may use

Sources checked on 2026-11-03: Cursor’s rules, permissions, sandbox, hooks, run modes, MCP configuration, and enterprise model and integration management documentation.

Enforce Team Rules for guidance everyone must follow

An admin can make a Team Rule mandatory. Turn on “Enforce this rule” in the dashboard, and the rule is required for every team member and cannot be disabled in Customize. Team Rules need a Team or Enterprise plan, and they take precedence over Project and User Rules when guidance conflicts.

Enforcement changes whether a member can switch the rule off. It does not change whether the model follows it, so pair a rule with a hook or sandbox policy for anything that must never run. For how Team Rules compare with the Claude Code and Copilot controls, see governing Claude Code, Cursor and Copilot with one policy.

Use permissions.json for convenience, not for blocking

permissions.json takes three top-level keys: mcpAllowlist, terminalAllowlist and autoRun. The first two list calls that run without an approval prompt. The third holds instructions that steer the Auto-review classifier. Terminal entries are prefix strings matched case-sensitively, and a colon separates the base command from an argument glob, as in npm:install*.

The file can be per-user or per-repo, and both are optional. Admin settings sit above it, then permissions.json, then IDE settings. A key in permissions.json replaces the IDE allowlist for that type. The docs say the allowlists are not a security guarantee, so do not use this file to stop a command.

{
  "mcpAllowlist": ["github:*", "linear:*", "notion:search"],
  "terminalAllowlist": ["git", "npm", "cargo build", "cargo test"]
}

Block tool calls with a hook

Hooks are the control in Cursor that can refuse an action outright. A command hook is a script the harness runs for an event, and the script’s exit code or JSON output decides the result. The first section covers writing a blocking hook, and the second covers where hooks are read from on each machine.

Write a blocking hook

  1. Write a script that prints the JSON the docs describe, with permission, user_message and agent_message. Exit code 2 blocks the action, which the docs treat as equivalent to returning permission: "deny".
  2. Add the script to hooks.json, using an event such as beforeShellExecution for terminal commands or beforeMCPExecution for MCP calls.
  3. Set failClosed to true on security-critical hooks. The per-script option makes a crash, timeout or non-zero exit block the action instead of letting it through.
{
  "version": 1,
  "hooks": {
    "beforeShellExecution": [
      { "command": "./hooks/block-git.sh", "failClosed": true }
    ]
  }
}

The version key must be 1, and failClosed sits beside command in each script entry.

The hook receives the full command, the working directory and a sandbox flag on stdin. Its output for a deny looks like this:

{
  "permission": "deny",
  "user_message": "Git command blocked. Use the GitHub CLI (gh) instead.",
  "agent_message": "Git is blocked by policy. Use gh for this task."
}

Permission hooks also block when their output is invalid JSON or does not match the expected format, even when failClosed is false. Test the script’s output as well as its exit code.

Deploy hooks to developer machines

Cursor reads hooks from several sources, and every matching hook from every source runs. The highest-priority source is the enterprise file, which MDM places at /Library/Application Support/Cursor/hooks.json on macOS, /etc/cursor/hooks.json on Linux and WSL, and C:\ProgramData\Cursor\hooks.json on Windows. On Enterprise, team hooks are set in the web dashboard and synced to members. Project hooks live at <project-root>/.cursor/hooks.json, user hooks at ~/.cursor/hooks.json, and plugin hooks run after all of these. When hooks disagree, a deny from any hook wins over ask.

The docs do not say whether a user can disable enterprise hooks, so ask Cursor before you treat them as fixed. Test the MDM path on one clean developer machine before a wider rollout, and confirm that a blocked command fails there.

Limit commands and network with the sandbox

Run modes decide when a tool call runs without asking. Auto-review is the recommended default and runs shell commands in the sandbox when it can. Allowlist runs only the actions on your list, and sandboxing is optional there. Run Everything runs every call with no sandbox and no classifier. An admin can override which modes are available, and team settings take precedence over individual and project configuration.

The sandbox reads sandbox.json from ~/.cursor/sandbox.json and from <workspace>/.cursor/sandbox.json. Its networkPolicy defaults to deny, and deny entries win over allow entries. A team-admin policy sits above both files and cannot be weakened by either one.

{
  "type": "workspace_readwrite",
  "networkPolicy": {
    "default": "deny",
    "allow": ["registry.npmjs.org"],
    "deny": ["*.example.net"]
  }
}

On Linux, the sandbox needs kernel 6.2 or later with Landlock v3 support and unprivileged user namespaces. If those are missing, Cursor falls back to asking for approval before commands run. Some commands need full system access and bypass the sandbox, and Cursor asks before running them.

Use the MCP allowlist and per-server network modes

On Enterprise, an admin lists approved MCP servers under MCP Configuration in the team dashboard. Command entries match the full command string, and URL entries match the URL, and both support *. The allowlist approves a configuration and does not install it on developer machines.

Each local server also has a network mode: Allow all, Allowlist, Deny all or No sandbox. Remote URL servers are limited to their URL entry pattern. That limits where Cursor connects. It does not limit where the remote service sends traffic after it runs. The full allowlist procedure is in how to allowlist MCP servers in Cursor, so this post does not repeat the steps.

Gotchas that let an agent through

  • An unenforced Team Rule is a suggestion. Members can switch it off in Customize.
  • Auto-review is not a security boundary. Its classifier can make mistakes, and the docs say so.
  • Run Everything has no sandbox and no classifier. Read access does not apply in that mode either.
  • Cloud Agents do not use Run Modes. They run on their own machine and never ask for approval, so check their settings separately.
  • Hooks fail open by default. A non-zero exit other than 2 lets the action proceed unless failClosed is true.
  • ask is not enforced for preToolUse. Use deny if a rule must hold.
  • Allowlists match strings. A changed argument or install path stops an entry from matching, and a wildcard can match more than you meant.

A checklist for a policy that holds

Write the policy as a list of decisions, then map each one to a control that blocks, not to a rule that advises.

  1. Put every “must never happen” decision in a hook with failClosed set, and test it with a command that should be denied.
  2. Set the team run mode and the sandbox network policy from the dashboard and sandbox.json, so a developer’s permissions.json cannot widen them.
  3. Use Team Rules with “Enforce this rule” for the guidance everyone must read, and do not count it as a control.
  4. On Enterprise, set the MCP allowlist and record the entries in one written list.
  5. Test each control on a developer machine with the Cursor build you deploy. The docs name features by version, so note the build next to the result.

Enforcing this with AIControls

AIControls has confirmed support for Claude Code through the gateway, in the CLI and in VS Code, and for Copilot in VS Code, with per-user tokens. Cursor is not on that list, so this post makes no AIControls claim for Cursor. To see what AIControls covers for coding agents, start with the coding agents page, then download AIControls or request a demo. For the Claude Code side of the same policy, read the managed settings guide.

Frequently asked questions

Does a Cursor rule stop an agent from running a command?

No. A rule is text the model reads, so the model can still pick a different action. Admins can make Team Rules mandatory, which only stops a member from switching them off. To stop a specific call, use a hook that denies it, a sandbox network policy, or a run mode an admin sets. Match the control to the call you need to stop.

What does Enforce this rule change in Cursor Team Rules?

It makes the rule required for every team member, and members cannot disable it in Customize. Team Rules need a Team or Enterprise plan. Enforcement changes whether a member can turn the rule off, not whether the model follows it. Team Rules also win over Project and User Rules when guidance conflicts.

Is permissions.json a security control in Cursor?

No. Cursor's permissions reference says the file is not a security boundary and calls its allowlists best-effort convenience. It can list MCP tools and terminal commands that run without an approval prompt. If an admin has set run mode controls in the team dashboard, those take effect, and neither permissions.json nor the IDE allowlist can add entries.

What happens when a hook script crashes or times out?

The action goes ahead unless the hook sets failClosed to true, which makes a crash, timeout or missing output block it. A permission hook behaves differently: invalid JSON or an invalid response blocks the action even when failClosed is false. Test the failure path on purpose before you depend on a hook, and check the hooks reference for the events your Cursor version supports.

Ritesh Patel, Founder & VP Product, Nirmata

Ritesh Patel is a founder of Nirmata and leads its products. He writes about governing AI coding agents, MCP security and Kubernetes policy as code.

LinkedIn

Govern AI agents with AIControlsControl what AI agents do, and prove it.
ShareXLinkedIn

Stay up-to-date with the latest in AI, governance, and infrastructure

Subscribe to our free monthly newsletter to get industry news, DevOps tips, and articles right to your inbox on Kyverno, containerization, Kubernetes deployment & management and more.