diff --git a/.cursor/hooks.json b/.cursor/hooks.json index efd8a19..fa7594e 100644 --- a/.cursor/hooks.json +++ b/.cursor/hooks.json @@ -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": [ diff --git a/.cursor/hooks/_common.py b/.cursor/hooks/_common.py index b5294ae..9e9671b 100755 --- a/.cursor/hooks/_common.py +++ b/.cursor/hooks/_common.py @@ -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)."), diff --git a/.cursor/hooks/guard-mcp.py b/.cursor/hooks/guard-mcp.py index 22f4398..638e4c4 100755 --- a/.cursor/hooks/guard-mcp.py +++ b/.cursor/hooks/guard-mcp.py @@ -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. diff --git a/.cursor/hooks/guard-network.py b/.cursor/hooks/guard-network.py index fda1794..40df8a0 100755 --- a/.cursor/hooks/guard-network.py +++ b/.cursor/hooks/guard-network.py @@ -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 diff --git a/.cursor/hooks/guard-shell.py b/.cursor/hooks/guard-shell.py index 863d747..1f8d8da 100755 --- a/.cursor/hooks/guard-shell.py +++ b/.cursor/hooks/guard-shell.py @@ -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 diff --git a/.cursor/hooks/protect-secrets.py b/.cursor/hooks/protect-secrets.py index 9c5bbca..ea6f84c 100755 --- a/.cursor/hooks/protect-secrets.py +++ b/.cursor/hooks/protect-secrets.py @@ -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. """ diff --git a/.cursor/hooks/scan-prompt.py b/.cursor/hooks/scan-prompt.py index 28b837f..04df7ba 100755 --- a/.cursor/hooks/scan-prompt.py +++ b/.cursor/hooks/scan-prompt.py @@ -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