Why Cursor keeps asking for permission, and which allowlist actually applies
Cursor has two permission systems that do not share settings: the editor's agents and the CLI (the agent command in a terminal). The editor has three Run Modes and a declarative allowlist in permissions.json; the CLI has its own approvalMode and files. The editor also reads two permissions.json files with the same name, and the one in the project does not do what the docs say.
For local editor work, put terminal and MCP allowlists in ~/.cursor/permissions.json. The second file, <workspace>/.cursor/permissions.json, is meant to be committed, but its allowlists are the disputed part; the status line below has the staff detail. Cursor reads MCP (the protocol for external tool servers) from .cursor/mcp.json or ~/.cursor/mcp.json; an approval entry is server:tool in permissions.json.
Run agent --version in the CLI, or open Cursor → About Cursor. The three run modes are build-dependent: the names changed in 3.5 (22 May 2026), Auto-review arrived in 3.6 (29 May 2026), and Read Access in 3.23 (1 October 2026).
Checked against Cursor's documentation on 27 October 2026.
Status, 27 October 2026: the docs say the two permissions.json files are concatenated. A staff reply in the project-file thread (19 June 2026) says per-repo terminalAllowlist and mcpAllowlist are not read or merged; only user-file allowlists apply, and per-repo autoRun is read. It was still open on 12 October 2026. A second staff reply in the Auto-review thread (15 July 2026) confirmed that a non-empty user-file allowlist makes Auto-review unselectable; users reported it again on 15 October 2026. Cursor is closed source; these describe the build at that date.
Start with the surface#
| Surface | What decides | Where to check |
|---|---|---|
| Local editor agents (the agent chat and the Agents Window) | Run Modes, permissions.json, and the separate protections | Settings → Agents → Approvals & Execution |
CLI (agent) | approvalMode, cli-config.json, .cursor/cli.json | /run-everything status, agent about, the file itself |
| Cloud agents | Nothing asks; they run on their own machine | Not these settings |
The mode decides who reviews the call#
A Run Mode is the setting that decides which tool calls run without asking. In the desktop app it is under Settings → Agents → Approvals & Execution. The Run Modes page lists three:
| Mode | What runs without asking | What still asks |
|---|---|---|
| Auto-review | Allowlisted calls; sandboxable shell commands in the sandbox; calls the classifier allows | A call the classifier blocks and the agent still wants; a call that cannot use the sandbox and is blocked; the separate protections |
| Allowlist | Actions on your allowlist. With sandboxing on, supported shell commands can run in the sandbox. | Everything else |
| Run Everything | Every tool call | Browser Protection, File-Deletion Protection, External-File Protection |
Auto-review is the recommended default, not a no-prompt mode. The classifier, a small model on Cursor's backend, reviews the call, and a blocked call can come back as an approval card. The sandbox is an OS boundary, not an approval. A sandboxed command that needs the network or an outside path can fail and be retried outside; that retry is reviewed.
The old names are why the setting looks missing. Ask Every Time was deprecated in 3.5; for the same behaviour, choose Allowlist with no entries and sandboxing off, since sandboxing on lets supported commands run in the sandbox. Run in Sandbox became Allowlist with sandboxing on. Before 3.5, the old names apply and allowlists were not consulted in Ask Every Time.
Two things can make Auto-review unavailable. If team model access controls block the classifier's models, the docs say to allow Claude 4.5 Haiku and reopen Cursor. If ~/.cursor/permissions.json has a non-empty terminalAllowlist or mcpAllowlist, staff confirmed on 15 July 2026 that Auto-review can be visible but not selectable; keep autoRun in the file and move the allowlists into Settings. The docs do not mention the lockout.
The editor's two permission files#
The editor reads two files with the same name and schema; the docs call the second per-repo. It sits at the workspace root, so a multi-root workspace has one file, not one per folder.
| Scope | Path | What it is for |
|---|---|---|
| Per-user | ~/.cursor/permissions.json | Applies in every project; the file staff recommend for allowlists |
| Per-repo | <workspace>/.cursor/permissions.json | Meant to be committed; its autoRun section is read, its allowlists are the disputed part |
The permissions.json reference describes terminalAllowlist, mcpAllowlist, and autoRun.allow_instructions / block_instructions. A key that is present replaces the in-app allowlist for that type; the Settings editor becomes read-only.
The documented precedence is team admin > permissions.json (user and repo concatenated) > IDE settings. The observed one is narrower: per-repo allowlists are ignored, so the user file is the only file-based allowlist that works; per-repo autoRun is read. Until the project-file thread reports a fix, expect a committed allowlist not to reach teammates.
An empty array is another trap. The docs say an empty effective list stays empty, but a reporter's test in the allowlist thread (13 August 2026) found mcpAllowlist: [] fell back to saved IDE entries. In Allowlist mode, an empty list means ask for everything; if the empty-array fallback bites, keep a dummy entry that matches nothing, such as mcpAllowlist: ['dummy:nothing'], as the reporter did.
The docs say both files are re-read when they change. Staff advised (10 August 2026) to fully quit and reopen after creating, editing or deleting the file, because the Settings panel can stay stuck read-only. Do the full quit before deciding the file is ignored.
autoRun is not an allowlist. allow_instructions and block_instructions are plain-English hints to the Auto-review classifier. The reference calls them steering, not enforcement; a call that matches block_instructions can still be approved. They have no effect in Allowlist or Run Everything.
Why an allowed command still asks#
Terminal entries are command prefixes, not command types. Matching is case-sensitive. git covers git status and git diff, but not gitk; git status covers only that command and anything starting with git status ; npm:install* covers the install variants. A chain is split into commands, so every part needs an entry, including cd. A Cursor staff reply in the command-allowlist thread (25 September 2026, reported on 3.21.9) added that PowerShell script blocks, if ($LASTEXITCODE...) checks, and 2>$null redirects always ask even when the inner commands are allowed. A heredoc (a multi-line command fed to a program) after && is a separate known issue, confirmed in the heredoc thread (5 October 2026, reported on 3.23.12).
"Always Run" on the approval card is not Run Everything; it adds an allowlist entry. Staff advised the broadest entry in its dropdown, such as git, not the full command line (25 September 2026).
MCP tool calls ask for approval by default, and each call asks again until it is on the MCP allowlist. Entries are server:tool; * can stand for the whole server or the whole tool. The docs allow a glob inside a name, such as server:list_*, but a staff reply in the allowlist thread (10 August 2026) advised exact entries or whole-part wildcards. If a partial glob prompts, use server:* or *:tool.
Read Access (3.23 and later) is hidden in Run Everything; in every other mode, when set to Workspace, it can ask before an outside-workspace file read. Browser Protection, File-Deletion Protection, and External-File Protection can ask even in Run Everything. sandbox.json is not a third permission file: it controls what a sandboxed command can reach, not whether it runs.
The CLI is a different permission system#
The CLI docs call the command agent; older posts say cursor-agent. Its rules live in ~/.cursor/cli-config.json (all settings) and <project>/.cursor/cli.json (permissions only), a separate permission system from the editor's permissions.json (CLI permissions reference, configuration reference).
permissions.allow and permissions.deny take tokens: Shell(command), Read(path), Write(path), WebFetch(domain), and Mcp(server:tool). Deny wins. Shell(git) allows any git subcommand; Shell(curl:*) allows curl with any arguments. cli-config.json is pure JSON, not JSONC (JSON with comments); a // comment will break it and the CLI will back the file up as .bad, so your rules can disappear.
The config accepts approvalMode values allowlist, auto-review, and unrestricted; the slash menu exposes /run-everything. --force (alias --yolo) forces commands through unless a deny matches; staff note it also covers writes and deletes, so use it only in a trusted workspace. In --print no one can answer a prompt; a call that needs approval is rejected.
Two known gaps, staff-confirmed on 24 September 2026: native Delete always prompts and has no allow token; WebFetch can be rejected in --print even with WebFetch(*) (the CLI allowlist thread). Use interactive mode for WebFetch, or --force in a trusted workspace.
If your organization manages MCP settings, personal Mcp(...) entries may be ignored: staff said in the MCP allowlist thread that MCP approvals come from the team's configuration, and the admin should name the server row to match mcp.json (27 August 2026). agent mcp enable <server> adds a server to the local approved list.
Check it in this order#
- Open Settings → Agents → Approvals & Execution. Read the mode, and whether the allowlist is configured by
permissions.jsonor an admin. If the file owns an allowlist, the editor is read-only and Add to allowlist is gone. If the panel does not say so, the file is not in effect. - Open the file for the surface:
~/.cursor/permissions.jsonfor the editor,~/.cursor/cli-config.jsonfor the CLI. Match the exact command or tool name the card shows; staff ask for the card because it lists what the matcher thinks is missing (25 September 2026). - Run a canary in Allowlist mode: add
echoto the user file'sterminalAllowlist, fully quit, and ask forecho cursor-canary. If it still prompts, the file is not being read. Auto-review could let the classifier allowechowithout the allowlist, so use Allowlist; this tests the matcher, not model obedience. - If the panel says admin-controlled, check the team dashboard instead, including for CLI MCP approvals.
- Do not ask the agent whether it is allowed to run something; it sees the tool call, not the matcher. The Settings panel and the approval card are the evidence.
A hard rule is not an allowlist#
The docs call allowlists and autoRun best-effort convenience, not a security boundary. The IDE file has no deny list; block_instructions only steers the classifier, and a matching call can still be approved. If a command must never run, use a hook (a script Cursor runs at a session or tool event) that denies it, a CLI deny entry, or a team policy. The allowlist cannot express "never".
Where to go next#
- Cursor guides — the rest of the set.
- Why your Cursor rule isn't applied — when the rule is in the prompt but not followed.
- Why your Cursor hook doesn't fire — when the enforcement layer itself fails.
- Cursor says MCP is connected, so why aren't the tools there? — when the tool never reaches the permission gate.