Specify Work · Security · Cursor
Security for Cursor.
One install writes Cursor’s hooks. Shell commands, MCP tools and file reads pass the adapter before they run, and every event already names the person.
A denial in Cursor
- Ship release 24.3 and deploy it to production.
- Shell: deploy 24.3 --env production
- Denied by Specify · Production changes · logged as d_4f81
- To you: Production deploys need an exception from your org admin. Ask from the record, or run: specify escalate d_4f81
- To the agent: Denied by policy. Carry on with the rest of the task.
- Skipping the deploy. Continuing with the changelog and the release notes.
- Four hours later, after D. Marsh grants the exception
- Shell: deploy 24.3 --env production
- Allowed by exception e_812 · D. Marsh · once · logged
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 prints its id and the one command that escalates it. The person can do the same from the record, and a retry before approval is denied again and counted.
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.
$ specify adapter install cursorRun it once per machine. It enrols the person, starts the adapter and writes hooks.json in the Cursor home directory:
- 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 commands — covered
With the working directory they run in.
File edits and writes — covered
preToolUse on Write and Delete, decided before the edit lands.
File reads — covered
By path, with the input scanner on the content.
MCP tool calls — covered
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.
Subagents — covered
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.
Hold the line without slowing the team.
Standard policies come with every plan. Your own policies, simulation and exceptions come with Org.
See pricing