Skip to content

Commit f9ad85f

Browse files
committed
refactor(security): Change default behavior to block dangerous operations
By default, dangerous operations are now blocked silently without prompting. Previously, all operations were allowed by default (relying on client-side permission handling). The blocklist is now always enforced. Setting `mcp-server-security-prompt-for-permissions` to t enables minibuffer prompts to approve dangerous operations case-by-case instead of blocking them. Error messages now provide clearer guidance on how to allow blocked operations.
1 parent 36894c7 commit f9ad85f

File tree

2 files changed

+29
-17
lines changed

2 files changed

+29
-17
lines changed

CLAUDE.md

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -293,18 +293,27 @@ Current tool annotations:
293293

294294
### Permission Handling
295295

296-
By default, permission decisions are delegated to the MCP client. The client
297-
uses tool annotations to decide whether to prompt users. This means:
296+
The security model has two layers:
298297

299-
- **No Emacs minibuffer prompts** by default
300-
- Clients like Claude Code handle allow/deny decisions
301-
- Tools provide accurate hints so clients can make informed decisions
298+
1. **MCP client prompting** - Clients like Claude Code use tool annotations
299+
(`destructiveHint`, etc.) to decide whether to prompt users for tool access.
302300

303-
To enable Emacs-side prompting (extra security layer):
301+
2. **Emacs blocklist** - Dangerous functions (e.g., `delete-file`, `shell-command`)
302+
are always blocked, regardless of whether the tool was allowed by the client.
303+
304+
By default (`mcp-server-security-prompt-for-permissions` = `nil`):
305+
- Dangerous operations are **blocked silently** (no minibuffer prompt)
306+
- Safe operations are allowed
307+
- The blocklist is always enforced
308+
309+
To enable Emacs-side prompting (approve dangerous operations case-by-case):
304310
```elisp
305311
(setq mcp-server-security-prompt-for-permissions t)
306312
```
307313

314+
This prompts in the minibuffer instead of blocking, letting users approve
315+
dangerous operations individually.
316+
308317
### Permission Caching
309318
- Permission decisions are cached per session
310319
- Comprehensive audit trail of all actions

mcp-server-security.el

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -90,10 +90,11 @@ Use this to whitelist specific functions you trust the LLM to use freely."
9090

9191
(defcustom mcp-server-security-prompt-for-permissions nil
9292
"Whether to prompt user in Emacs for dangerous operations.
93-
When nil (the default), tool permission decisions are delegated to the
94-
MCP client, which uses tool annotations to determine whether to prompt.
95-
Set to t to require explicit Emacs minibuffer confirmation for dangerous
96-
operations (useful for extra security or when using untrusted clients)."
93+
When nil (the default), dangerous operations are blocked without prompting.
94+
The MCP client uses tool annotations to determine whether to prompt for
95+
tool-level permission, but the blocklist is always enforced.
96+
Set to t to prompt in the Emacs minibuffer instead of blocking, allowing
97+
users to approve dangerous operations on a case-by-case basis."
9798
:type 'boolean
9899
:group 'mcp-server)
99100

@@ -152,11 +153,11 @@ Returns t if permitted, nil otherwise."
152153
('no
153154
(mcp-server-security--log-audit operation data nil)
154155
nil)))
155-
;; When not prompting, allow all operations - client handles permission
156-
;; via tool annotations (readOnlyHint, destructiveHint, etc.)
157-
(puthash cache-key t mcp-server-security--permission-cache)
158-
(mcp-server-security--log-audit operation data t)
159-
t))
156+
;; When not prompting, still block dangerous operations
157+
(let ((granted (not (mcp-server-security--is-dangerous-operation operation))))
158+
(puthash cache-key granted mcp-server-security--permission-cache)
159+
(mcp-server-security--log-audit operation data granted)
160+
granted)))
160161

161162
(defun mcp-server-security--prompt-permission (operation data)
162163
"Prompt user for permission for OPERATION with DATA.
@@ -262,7 +263,8 @@ Returns the input if safe, signals an error otherwise."
262263
(when (and (member form mcp-server-security-dangerous-functions)
263264
(not (member form mcp-server-security-allowed-dangerous-functions)))
264265
(unless (mcp-server-security-check-permission form)
265-
(error "Permission denied for function: %s" form))))
266+
(error "Security: `%s' is blocked. Add it to `mcp-server-security-allowed-dangerous-functions' \
267+
to allow, or set `mcp-server-security-prompt-for-permissions' to t to prompt" form))))
266268

267269
;; Check lists (function calls)
268270
((listp form)
@@ -274,7 +276,8 @@ Returns the input if safe, signals an error otherwise."
274276
(when (and (member func mcp-server-security-dangerous-functions)
275277
(not (member func mcp-server-security-allowed-dangerous-functions)))
276278
(unless (mcp-server-security-check-permission func args)
277-
(error "Permission denied for function: %s" func)))
279+
(error "Security: `%s' is blocked. Add it to `mcp-server-security-allowed-dangerous-functions' \
280+
to allow, or set `mcp-server-security-prompt-for-permissions' to t to prompt" func)))
278281

279282
;; Special checks for file access functions
280283
(when (memq func '(find-file find-file-noselect view-file insert-file-contents))

0 commit comments

Comments
 (0)