cc-safe-setup 29.1.0 → 29.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,23 @@
1
+ #!/bin/bash
2
+ # prompt-injection-detector.sh — UserPromptSubmit hook
3
+ # Trigger: UserPromptSubmit
4
+ # Matcher: ""
5
+ #
6
+ # Detects common prompt injection patterns in user prompts.
7
+ # Useful in environments where prompts may come from external sources
8
+ # (API, shared sessions, automated pipelines).
9
+ #
10
+ # See: https://github.com/anthropics/claude-code/issues/34895
11
+
12
+ INPUT=$(cat)
13
+ PROMPT=$(echo "$INPUT" | jq -r '.prompt // empty' 2>/dev/null)
14
+ [ -z "$PROMPT" ] && exit 0
15
+
16
+ # Check for common injection patterns
17
+ if echo "$PROMPT" | grep -qiE 'ignore (all |previous |prior |above )?(instructions|rules|guidelines)|disregard (your|the) (instructions|rules)|you are now|new persona|system prompt|</?system>|forget (your|everything|all)'; then
18
+ echo "⚠ Possible prompt injection detected in input." >&2
19
+ echo " Pattern matched: override/ignore instructions" >&2
20
+ echo " Review the prompt carefully before proceeding." >&2
21
+ fi
22
+
23
+ exit 0
@@ -0,0 +1,22 @@
1
+ #!/bin/bash
2
+ # prompt-length-guard.sh — UserPromptSubmit hook
3
+ # Trigger: UserPromptSubmit
4
+ # Matcher: ""
5
+ #
6
+ # Warns when a user prompt exceeds a character threshold.
7
+ # Very long prompts can consume excessive context and tokens.
8
+ # Adjust THRESHOLD to match your comfort level.
9
+
10
+ INPUT=$(cat)
11
+ PROMPT=$(echo "$INPUT" | jq -r '.prompt // empty' 2>/dev/null)
12
+ [ -z "$PROMPT" ] && exit 0
13
+
14
+ THRESHOLD=5000
15
+ LENGTH=${#PROMPT}
16
+
17
+ if [ "$LENGTH" -gt "$THRESHOLD" ]; then
18
+ echo "⚠ Long prompt detected: ${LENGTH} chars (threshold: ${THRESHOLD})" >&2
19
+ echo " Consider breaking this into smaller, focused instructions." >&2
20
+ fi
21
+
22
+ exit 0
package/index.mjs CHANGED
@@ -463,6 +463,8 @@ function examples() {
463
463
  'session-checkpoint.sh': 'Save session state before context compaction',
464
464
  },
465
465
  'UX': {
466
+ 'prompt-length-guard.sh': 'UserPromptSubmit: warn on long prompts (>5000 chars)',
467
+ 'prompt-injection-detector.sh': 'UserPromptSubmit: detect prompt injection patterns',
466
468
  'notify-waiting.sh': 'Desktop notification when Claude waits for input',
467
469
  'tmp-cleanup.sh': 'Clean up /tmp/claude-*-cwd files on session end',
468
470
  'hook-debug-wrapper.sh': 'Wrap any hook to log input/output/exit/timing',
@@ -604,14 +606,18 @@ async function installExample(name) {
604
606
  let trigger = 'PreToolUse';
605
607
  let matcher = 'Bash';
606
608
 
607
- // Detect trigger from header comments
608
- if (content.includes('TRIGGER: PermissionRequest') || content.match(/^#.*PermissionRequest hook/m)) trigger = 'PermissionRequest';
609
- else if (content.includes('TRIGGER: PostToolUse') || content.includes('PostToolUse')) trigger = 'PostToolUse';
610
- else if (content.includes('TRIGGER: Notification') || content.includes('Notification')) trigger = 'Notification';
611
- else if (content.includes('TRIGGER: Stop') || content.includes('Stop')) trigger = 'Stop';
612
- else if (content.includes('TRIGGER: SessionStart') || content.includes('SessionStart')) trigger = 'SessionStart';
613
- else if (content.includes('TRIGGER: PreCompact') || content.includes('PreCompact')) trigger = 'PreCompact';
614
- else if (content.includes('TRIGGER: SessionEnd') || content.includes('SessionEnd')) trigger = 'SessionEnd';
609
+ // Detect trigger from header comments (case-insensitive for "Trigger:" prefix)
610
+ const triggerMatch = content.match(/^#\s*[Tt]rigger:\s*(\S+)/m);
611
+ if (triggerMatch) {
612
+ const t = triggerMatch[1];
613
+ if (['PermissionRequest','PostToolUse','Notification','Stop','SessionStart','PreCompact','SessionEnd','UserPromptSubmit'].includes(t)) {
614
+ trigger = t;
615
+ }
616
+ } else if (content.match(/^#.*PermissionRequest hook/m)) {
617
+ trigger = 'PermissionRequest';
618
+ } else if (content.match(/^#.*UserPromptSubmit hook/m)) {
619
+ trigger = 'UserPromptSubmit';
620
+ }
615
621
 
616
622
  // Detect matcher from header (JSON format or comment format)
617
623
  const matcherMatch = content.match(/"matcher":\s*"([^"]*)"/);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cc-safe-setup",
3
- "version": "29.1.0",
4
- "description": "One command to make Claude Code safe. 344 hooks (8 built-in + 336 examples). 49 CLI commands. 1024 tests. 5 languages.",
3
+ "version": "29.3.0",
4
+ "description": "One command to make Claude Code safe. 346 hooks (8 built-in + 338 examples). 49 CLI commands. 1030 tests. 5 languages.",
5
5
  "main": "index.mjs",
6
6
  "bin": {
7
7
  "cc-safe-setup": "index.mjs"