The short answer
A Cursor agent deletes files by running a terminal command such as rm -rf, git clean -fdx or Remove-Item. That only happens without a prompt when the command is on your allowlist, when you run in a mode that runs everything, or when a classifier decides it looks fine. The setting many people expect to help, External-File Protection, doesn’t apply to terminal commands: in Cursor’s forum, a reply on 25 April 2026 says it “only limits file editing and writing tools” and doesn’t cover rm.2
What does cover it: File-Deletion Protection, which Cursor’s docs say stops automatic file deletion including rm commands; the sandbox, which limits writes to the workspace; and a hook that asks before any deleting command.1 Back up anything you can’t lose before you let any agent run commands.
Deedglass
A tool call meets your rules before it runs
Asks to run
DELETE FROM visits;
Deletes every row in visits
Deedglass checks your rules
- Reading dataAllowed
- Deleting a whole table (DROP, TRUNCATE)Never
- Changing or deleting rows without saying which (WHERE)This one
- Other changesWait for a person
First, recover what you can
If it has just happened, stop the agent and stop writing to that disk.
- Check version control. Files tracked in Git can come back with
git checkout -- <path>orgit restore.git clean -fdxremoves untracked files, which Git can’t restore. - Check the trash.
rmdoesn’t use it, but some agents call the editor’s delete, which may. - Check backups and sync. Time Machine, File History, or a cloud sync folder’s version history.
- Read the agent’s transcript. It shows the exact command and the directory it ran from, which tells you what else it reached.
Then work out how the command got through, because the same path is still open.
How the delete got through
Cursor has three run modes, set in Settings > Agents > Approvals & Execution:1
| Mode | What runs without asking |
|---|---|
| Auto-review (recommended) | Allowlisted calls; other shell commands in the sandbox when possible; the rest goes to an LLM classifier |
| Allowlist | Only what’s on your list; sandboxing optional |
| Run Everything | Every tool call, with no sandbox |
The old Ask Every Time mode was deprecated in 3.5; an Allowlist with an empty list does the same.1
Each mode has its own way for a delete to slip past:
- Run Everything runs it, full stop.1
- Allowlist runs it if something on the list matches. A broad entry such as
rmorgitis enough. The forum reply says destructive commands run without confirmation when Auto-Run is on or the command is allowlisted.2 - Auto-review asks a classifier. Cursor’s own docs say “Auto-review is not a security boundary” and that the classifier can allow a call you would have blocked.1
Commands often reach outside the project without looking like they do. cd .. followed by a cleanup, a path built from a variable that turned out empty, or ~ expanded in the wrong place: each turns a project cleanup into a home-folder cleanup.
Which setting covers what
This is the table to check against your own settings. It comes from Cursor’s current docs and the forum reply.
| Control | Covers rm in the terminal? |
Notes |
|---|---|---|
| External-File Protection | No | Limits Cursor’s file editing and writing tools only2 |
| File-Deletion Protection | Yes | Stops automatic file deletion, including rm commands1 |
| Sandbox | Mostly | Read and write inside the workspace by default; commands that need full access bypass it after asking1 |
| Allowlist | Only if you keep deletes off it | Every entry runs unreviewed |
| Auto-review classifier | Sometimes | Not a security boundary, by Cursor’s own description1 |
A beforeShellExecution hook |
Yes, for commands it matches | Fails open by default3 |
Two details about the sandbox. On Linux it needs kernel 6.2 or newer with Landlock; otherwise Cursor falls back to asking before commands. And by default it still lets the agent read outside the workspace, though writes stay inside.1
A hook that asks before deleting
Cursor hooks run a script before a shell command. The beforeShellExecution hook receives command, cwd and sandbox, and returns permission (allow, deny or ask) with a user_message and an agent_message.3 A matcher in hooks.json runs the hook only for commands that match a regular expression.3 Using the matcher means the script only ever answers “ask”, so it never has to decide to allow anything.
.cursor/hooks.json:
Code Data in JSON, the format software uses to pass records and settings.
{
"version": 1,
"hooks": {
"beforeShellExecution": [
{
"command": ".cursor/hooks/ask-delete.sh",
"matcher": "(^|[;&| ])(rm|rmdir|Remove-Item|shred) |git +clean +-[a-z]*f|find .*-delete",
"failClosed": true,
"timeout": 10
}
]
}
}
.cursor/hooks/ask-delete.sh (needs jq):
Code Commands typed in a terminal. The text around it says what happens.
#!/usr/bin/env bash
# runs only for commands the matcher picked out
cmd=$(jq -r '.command // ""')
jq -n --arg c "$cmd" '{
permission: "ask",
user_message: ("This command deletes files: " + $c),
agent_message: "Deleting files needs the user to approve it first."
}'
We checked the pattern against six commands. It matched rm -rf ~/Documents/old, git clean -fdx, find . -name x -delete and cd .. && rm -r dist, and left npm run build and echo firm alone. Piped the first command’s JSON, the script answered {"permission":"ask", ...}.
Why failClosed: true: by default a hook that crashes, times out or exits non-zero other than 2 lets the action through. With failClosed on, those failures block it.3 For a delete guard, a false block is cheaper than a silent pass. The same goes for output: invalid JSON from a permission hook blocks the action.3
The limits are the same as any text check. A deletion inside a script, a Makefile target or a python -c call doesn’t contain rm in the command Cursor sees. Our Claude Code hook post lists the common ways around a pattern.
A safe setup in six steps
- Back up first. Git for code, a real backup for everything else in your home folder.
- Use Auto-review or Allowlist, never Run Everything on a machine with files you care about.1
- Turn on File-Deletion Protection.1
- Keep delete, move and Git cleanup commands off the allowlist, as the forum reply suggests.2
- Add the ask hook with
failClosedon.3 - Run risky work somewhere disposable: a dev container, a VM or a cloud agent, so the worst case is a rebuilt container.2
The order matters. Steps 1 and 6 hold even when every check in between misfires; the rest reduce how often you need them.
What none of this fixes
None of these settings make an agent understand which files matter to you. They narrow what can run without a person. If your answer to every prompt is yes, a prompt won’t help; keep prompts rare enough to read.
They also don’t cover the database. An agent can wipe a table with one psql command that deletes no files at all. For that, deedglass guard shell installs as Cursor’s before-a-command hook from the same table it uses for Claude Code, Codex CLI, Gemini CLI and GitHub Copilot, and asks first on commands that would destroy database data.4 It is a second check, not a sandbox: if it can’t run, the command goes ahead unchecked.4 How the five clients’ hooks compare is in our hooks comparison, and the order of controls before production is in the checklist. The idea underneath both is the blast radius: what the agent can reach decides how bad a bad command gets. To try the checks without installing anything, open the playground; to grade what an agent can reach on your own machine, run npx deedglass scan (the grade, explained).
Written with AI assistance and checked against our claims register.