Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .cursor/hooks.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@
"beforeShellExecution": [
{
"command": "python3 .cursor/hooks/guard-shell.py",
"failClosed": false
"failClosed": true
},
{
"command": "python3 .cursor/hooks/guard-network.py",
"matcher": "curl|wget|scp|nc ",
"failClosed": false
"failClosed": true
}
],
"beforeMCPExecution": [
{
"command": "python3 .cursor/hooks/guard-mcp.py",
"failClosed": false
"failClosed": true
}
],
"beforeReadFile": [
Expand Down
2 changes: 1 addition & 1 deletion .cursor/hooks/_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ def is_sensitive_file(path: str) -> bool:
# --- Destructive data-layer detection (shared by shell + MCP guards) --------
# Narrow, high-confidence patterns for irreversible data/disk destruction that
# can arrive either as a shell command or as serialized MCP tool arguments
# (e.g. a database MCP running DROP). Fail-open nets, not boundaries.
# (e.g. a database MCP running DROP). Narrow denylists, not product PDPs.
DATA_DESTRUCTIVE: list[tuple[re.Pattern[str], str]] = [
(re.compile(r"\b(drop\s+database|drop\s+table|truncate\s+table)\b", re.IGNORECASE),
"Destructive SQL (DROP / TRUNCATE)."),
Expand Down
2 changes: 1 addition & 1 deletion .cursor/hooks/guard-mcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

Why this exists: MCP tools can mutate real systems (databases, cloud, files)
and their *output* is untrusted data, never instructions. This hook is a
fail-open net (failClosed:false): it logs every MCP call for observability and
fail-closed launch (failClosed:true): if this hook cannot start, the MCP call is denied. It logs every MCP call for observability and
denies only a narrow, high-confidence set of irreversible data-layer actions
(DROP / TRUNCATE / unfiltered DELETE / mkfs / dd-to-device) found in the
serialized tool arguments. It is NOT a security boundary.
Expand Down
2 changes: 1 addition & 1 deletion .cursor/hooks/guard-network.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"""beforeShellExecution: ask before high-confidence outbound exfil patterns.

Matcher-scoped in hooks.json (curl|wget|scp|nc). Returns permission: ask, not deny,
so legitimate API work can proceed after user review. failClosed:false — secondary net.
so legitimate API work can proceed after user review. failClosed:true — launch failure denies the matched command.
"""
from __future__ import annotations

Expand Down
7 changes: 3 additions & 4 deletions .cursor/hooks/guard-shell.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
#!/usr/bin/env python3
"""beforeShellExecution: deny a narrow set of clearly destructive commands.

Secondary denylist net (failClosed:false), NOT the security boundary — Cursor 2.0's
OS sandbox (workspace-scoped, no internet by default on macOS) is primary. This hook
catches a narrow set of high-confidence destructive patterns hooks can see. A
fail-closed launch config would only add brick-risk without closing unlisted commands.
Secondary denylist (failClosed:true on launch). Not the product security boundary —
Cursor's OS sandbox is primary. This hook catches a narrow set of high-confidence
destructive patterns. If the hook cannot start, the shell command is denied.
Tuned to avoid false positives (e.g. `rm -rf node_modules`).
"""
import os
Expand Down
7 changes: 3 additions & 4 deletions .cursor/hooks/protect-secrets.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
#!/usr/bin/env python3
"""beforeReadFile: keep secret files out of the model's context.

Guarded semantics (failClosed:false in hooks.json):
- Missing interpreter / launch failure -> Cursor fails OPEN (a vanished python3
never bricks all file reads).
- A detected secret file -> explicit `deny` (effective fail-closed on detection).
Guarded semantics (failClosed:true in hooks.json):
- Missing interpreter / launch failure -> Cursor denies the read.
- A detected secret file -> explicit `deny`.
- An internal error while deciding -> `deny`, rather than risk leaking a file we
failed to classify.
"""
Expand Down
2 changes: 1 addition & 1 deletion .cursor/hooks/scan-prompt.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
Blocks only on high-confidence secret patterns to avoid friction.
Output uses {"continue": bool} per the beforeSubmitPrompt contract.

Guarded semantics (failClosed:false): launch failure -> fail OPEN; a detected
Guarded semantics (failClosed:true): launch failure denies the prompt; a detected
secret or an internal scan error -> {"continue": false}.
"""
import os
Expand Down