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.