Security for Cursor

Shell commands, MCP tools and file reads in Cursor pass the adapter before they run.

A denial in Cursor

Two messages, one denial
Cursor lets the hook say one thing to the person and another to the agent. The person gets the policy and how to escalate; the agent gets the reason and carries on.
The escalation id
Every denial carries its id, and the person asks for an exception from the record. A retry before approval is denied again.
Named on every event
Cursor sends the person’s email with each hook call, so the record needs no enrolment step to say who ran what.

One command on each machine

Run it once per machine. It enrols the person, starts the adapter and writes hooks.json in the Cursor home directory:

$ specify adapter install cursor
  • beforeShellExecution, beforeMCPExecution and preToolUse on writes: the decision
  • beforeReadFile: the decision for reads, and the input scanner
  • afterFileEdit: the finished edit onto the record
  • beforeSubmitPrompt: attachments checked for secrets before they leave
  • sessionStart: inventory. stop: the event spool flushes
# ~/.cursor/hooks.json
{ "version": 1, "hooks": {
    "beforeShellExecution": [{ "command": "specify-hook" }],
    "beforeMCPExecution":   [{ "command": "specify-hook" }],
    "preToolUse":           [{ "command": "specify-hook", "matcher": "Write|Delete" }],
    "beforeReadFile":       [{ "command": "specify-hook" }]
} }

What is checked in Cursor

Shell commandsChecked
With the working directory they run in.
File edits and writesChecked
preToolUse on Write and Delete, decided before the edit lands.
File readsChecked
By path, with the input scanner on the content.
MCP tool callsChecked
With the server name and the tool input.
Web search and fetchThrough an MCP server only
Cursor’s built-in web search does not fire a hook. A fetch through an MCP server is checked like any other tool call.
SubagentsChecked
subagentStart is recorded.
IdentitySent by Cursor
The person’s email arrives with every event.

What the org can pin

Cursor reads enterprise and team hooks that a person cannot remove, on cloud agents too.

# enterprise hooks.json
macOS    /Library/Application Support/Cursor/hooks.json
Linux    /etc/cursor/hooks.json
Windows  C:\ProgramData\Cursor\hooks.json
  • Enterprise hooks live at the system path, delivered by device management. Team hooks are set in the dashboard on Enterprise plans and apply to every member.
  • Cursor has no native rules layer, so the pinned hook is the layer, and the shim answers when the adapter is down.

When something is missing

If the hook does not answer in time
Cursor proceeds. A hook fails open on timeout and on any exit code other than 2; that is Cursor’s design, and it is why the adapter decides from the cached bundle on the machine and never waits on the network to answer.
If the adapter is not running
The shim answers from the last signed bundle: the org’s flagged classes are denied, everything else is allowed, and an adapter-down event is logged.
If the person removes the hook entry
An enterprise or team hook cannot be removed by the person. On a personal install, inventory shows hooks removed and when the adapter was last seen.