cc-safe-setup 29.6.13 → 29.6.15
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.
- package/examples/cloud-cli-guard.sh +47 -0
- package/examples/db-connect-guard.sh +56 -0
- package/examples/firewall-guard.sh +53 -0
- package/examples/kill-process-guard.sh +50 -0
- package/examples/registry-publish-guard.sh +65 -0
- package/examples/sensitive-file-read-guard.sh +57 -0
- package/examples/systemd-service-guard.sh +44 -0
- package/package.json +2 -2
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# cloud-cli-guard.sh — Block destructive GCP/Azure CLI operations
|
|
3
|
+
#
|
|
4
|
+
# Solves: Claude Code running destructive cloud operations via gcloud/az CLI.
|
|
5
|
+
# Deleting VMs, storage, or databases in cloud environments can
|
|
6
|
+
# cause irreversible data loss and significant costs.
|
|
7
|
+
#
|
|
8
|
+
# Note: AWS is covered by aws-production-guard.sh
|
|
9
|
+
#
|
|
10
|
+
# Detects:
|
|
11
|
+
# gcloud compute instances delete
|
|
12
|
+
# gcloud sql instances delete
|
|
13
|
+
# gcloud storage rm
|
|
14
|
+
# gcloud projects delete
|
|
15
|
+
# az vm delete
|
|
16
|
+
# az storage account delete
|
|
17
|
+
# az sql db delete
|
|
18
|
+
# az group delete
|
|
19
|
+
#
|
|
20
|
+
# Does NOT block:
|
|
21
|
+
# gcloud compute instances list/describe
|
|
22
|
+
# az vm list/show
|
|
23
|
+
# gcloud/az read-only operations
|
|
24
|
+
#
|
|
25
|
+
# TRIGGER: PreToolUse MATCHER: "Bash"
|
|
26
|
+
|
|
27
|
+
INPUT=$(cat)
|
|
28
|
+
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
29
|
+
|
|
30
|
+
[ -z "$COMMAND" ] && exit 0
|
|
31
|
+
|
|
32
|
+
# Block destructive gcloud operations
|
|
33
|
+
if echo "$COMMAND" | grep -qE '\bgcloud\s+.*(delete|destroy|remove|reset)\b'; then
|
|
34
|
+
echo "BLOCKED: Destructive Google Cloud operation detected." >&2
|
|
35
|
+
echo " Command: $COMMAND" >&2
|
|
36
|
+
echo " Use 'gcloud ... describe' or 'gcloud ... list' to check first." >&2
|
|
37
|
+
exit 2
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# Block destructive az (Azure) operations
|
|
41
|
+
if echo "$COMMAND" | grep -qE '\baz\s+.*(delete|destroy|remove)\b'; then
|
|
42
|
+
echo "BLOCKED: Destructive Azure operation detected." >&2
|
|
43
|
+
echo " Command: $COMMAND" >&2
|
|
44
|
+
exit 2
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
exit 0
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# db-connect-guard.sh — Warn on direct database connections
|
|
3
|
+
#
|
|
4
|
+
# Solves: Claude Code connecting to databases directly via CLI clients
|
|
5
|
+
# and running queries without understanding the environment.
|
|
6
|
+
# Production database connections should go through application
|
|
7
|
+
# code, not direct CLI access.
|
|
8
|
+
#
|
|
9
|
+
# Real incidents:
|
|
10
|
+
# #36183 — prisma db push --force-reset on production
|
|
11
|
+
# #33183 — prisma db push against production database
|
|
12
|
+
# #27063 — destructive db command wiped production
|
|
13
|
+
#
|
|
14
|
+
# Detects:
|
|
15
|
+
# mysql -h <host> (MySQL direct connection)
|
|
16
|
+
# psql -h <host> (PostgreSQL direct connection)
|
|
17
|
+
# mongo <connection-string> (MongoDB direct connection)
|
|
18
|
+
# redis-cli -h <host> (Redis direct connection)
|
|
19
|
+
# prisma db push (Prisma schema push)
|
|
20
|
+
# prisma migrate deploy (Prisma migration)
|
|
21
|
+
#
|
|
22
|
+
# Does NOT block:
|
|
23
|
+
# mysql (local, no -h flag — likely development)
|
|
24
|
+
# psql (local connection)
|
|
25
|
+
# prisma generate (code generation, not DB change)
|
|
26
|
+
#
|
|
27
|
+
# TRIGGER: PreToolUse MATCHER: "Bash"
|
|
28
|
+
|
|
29
|
+
INPUT=$(cat)
|
|
30
|
+
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
31
|
+
|
|
32
|
+
[ -z "$COMMAND" ] && exit 0
|
|
33
|
+
|
|
34
|
+
# Block remote database connections
|
|
35
|
+
if echo "$COMMAND" | grep -qE '\b(mysql|psql|mongo(sh)?)\s+.*(-h\s+|--host[= ])'; then
|
|
36
|
+
echo "BLOCKED: Direct remote database connection detected." >&2
|
|
37
|
+
echo " Remote DB connections should use application code, not CLI." >&2
|
|
38
|
+
echo " Command: $COMMAND" >&2
|
|
39
|
+
exit 2
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
# Block redis remote connections
|
|
43
|
+
if echo "$COMMAND" | grep -qE '\bredis-cli\s+.*(-h\s+|--host)'; then
|
|
44
|
+
echo "BLOCKED: Direct remote Redis connection detected." >&2
|
|
45
|
+
exit 2
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
# Block Prisma destructive operations
|
|
49
|
+
if echo "$COMMAND" | grep -qE '\bprisma\s+(db\s+push|migrate\s+deploy|migrate\s+reset)'; then
|
|
50
|
+
echo "BLOCKED: Prisma database modification detected." >&2
|
|
51
|
+
echo " prisma db push/migrate can destroy production data." >&2
|
|
52
|
+
echo " Verify DATABASE_URL points to the correct environment." >&2
|
|
53
|
+
exit 2
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
exit 0
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# firewall-guard.sh — Block firewall rule modifications
|
|
3
|
+
#
|
|
4
|
+
# Solves: Claude Code modifying firewall rules (iptables, ufw, nftables)
|
|
5
|
+
# which can lock users out of servers or expose services.
|
|
6
|
+
# A single wrong iptables rule can make a remote server
|
|
7
|
+
# permanently inaccessible.
|
|
8
|
+
#
|
|
9
|
+
# Detects:
|
|
10
|
+
# iptables -A/-D/-I/-F (add/delete/insert/flush rules)
|
|
11
|
+
# ufw allow/deny/delete (uncomplicated firewall changes)
|
|
12
|
+
# nft add/delete/flush (nftables changes)
|
|
13
|
+
# firewall-cmd --add/--remove (firewalld changes)
|
|
14
|
+
#
|
|
15
|
+
# Does NOT block:
|
|
16
|
+
# iptables -L/-S (listing rules — read-only)
|
|
17
|
+
# ufw status (checking status)
|
|
18
|
+
# nft list (listing rules)
|
|
19
|
+
#
|
|
20
|
+
# TRIGGER: PreToolUse MATCHER: "Bash"
|
|
21
|
+
|
|
22
|
+
INPUT=$(cat)
|
|
23
|
+
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
24
|
+
|
|
25
|
+
[ -z "$COMMAND" ] && exit 0
|
|
26
|
+
|
|
27
|
+
# Block iptables modifications
|
|
28
|
+
if echo "$COMMAND" | grep -qE '\biptables\s+(-A|-D|-I|-F|-X|-P|--append|--delete|--insert|--flush)'; then
|
|
29
|
+
echo "BLOCKED: iptables modification can lock you out of the server." >&2
|
|
30
|
+
echo " Use 'iptables -L' to view rules safely." >&2
|
|
31
|
+
exit 2
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# Block ufw modifications
|
|
35
|
+
if echo "$COMMAND" | grep -qE '\bufw\s+(allow|deny|delete|disable|reset|route)'; then
|
|
36
|
+
echo "BLOCKED: ufw firewall modification." >&2
|
|
37
|
+
echo " Use 'ufw status' to view rules safely." >&2
|
|
38
|
+
exit 2
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
# Block nftables modifications
|
|
42
|
+
if echo "$COMMAND" | grep -qE '\bnft\s+(add|delete|flush|insert)'; then
|
|
43
|
+
echo "BLOCKED: nftables modification." >&2
|
|
44
|
+
exit 2
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
# Block firewalld modifications
|
|
48
|
+
if echo "$COMMAND" | grep -qE '\bfirewall-cmd\s+--(add|remove|set|reload)'; then
|
|
49
|
+
echo "BLOCKED: firewalld modification." >&2
|
|
50
|
+
exit 2
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
exit 0
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# kill-process-guard.sh — Block dangerous process termination commands
|
|
3
|
+
#
|
|
4
|
+
# Solves: Claude Code killing important system processes or user processes
|
|
5
|
+
# without understanding their purpose. kill -9 is especially dangerous
|
|
6
|
+
# as it prevents graceful shutdown and can cause data corruption.
|
|
7
|
+
#
|
|
8
|
+
# Detects:
|
|
9
|
+
# kill -9 <pid> (forced termination, no cleanup)
|
|
10
|
+
# killall <name> (kills ALL matching processes)
|
|
11
|
+
# pkill <pattern> (pattern-based kill, can be too broad)
|
|
12
|
+
# kill -KILL (same as -9)
|
|
13
|
+
#
|
|
14
|
+
# Does NOT block:
|
|
15
|
+
# kill <pid> (graceful SIGTERM, allows cleanup)
|
|
16
|
+
# kill -15 <pid> (explicit SIGTERM)
|
|
17
|
+
# kill -INT (Ctrl+C equivalent)
|
|
18
|
+
#
|
|
19
|
+
# TRIGGER: PreToolUse MATCHER: "Bash"
|
|
20
|
+
|
|
21
|
+
INPUT=$(cat)
|
|
22
|
+
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
23
|
+
|
|
24
|
+
[ -z "$COMMAND" ] && exit 0
|
|
25
|
+
|
|
26
|
+
# Block kill -9 (SIGKILL — no cleanup, potential data corruption)
|
|
27
|
+
if echo "$COMMAND" | grep -qE '\bkill\s+-(9|KILL)\b'; then
|
|
28
|
+
echo "BLOCKED: kill -9 forces immediate termination without cleanup." >&2
|
|
29
|
+
echo " Data corruption is possible. Use 'kill <pid>' (SIGTERM) instead." >&2
|
|
30
|
+
echo " Command: $COMMAND" >&2
|
|
31
|
+
exit 2
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# Block killall (kills ALL matching processes)
|
|
35
|
+
if echo "$COMMAND" | grep -qE '\bkillall\s'; then
|
|
36
|
+
echo "BLOCKED: killall terminates ALL processes matching the name." >&2
|
|
37
|
+
echo " This may kill unrelated processes. Use 'kill <specific-pid>' instead." >&2
|
|
38
|
+
echo " Command: $COMMAND" >&2
|
|
39
|
+
exit 2
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
# Block pkill (pattern-based, can be overly broad)
|
|
43
|
+
if echo "$COMMAND" | grep -qE '\bpkill\s'; then
|
|
44
|
+
echo "BLOCKED: pkill uses pattern matching which may kill unintended processes." >&2
|
|
45
|
+
echo " Find the specific PID with 'pgrep' first, then use 'kill <pid>'." >&2
|
|
46
|
+
echo " Command: $COMMAND" >&2
|
|
47
|
+
exit 2
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
exit 0
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# registry-publish-guard.sh — Block publishing to package registries
|
|
3
|
+
#
|
|
4
|
+
# Solves: Claude Code accidentally publishing packages to npm, PyPI,
|
|
5
|
+
# RubyGems, crates.io, or other registries. Publishing is
|
|
6
|
+
# irreversible for many registries (npm unpublish has a 72h limit).
|
|
7
|
+
#
|
|
8
|
+
# Note: npm-publish-guard.sh covers npm specifically.
|
|
9
|
+
# This hook covers ALL package registries.
|
|
10
|
+
#
|
|
11
|
+
# Detects:
|
|
12
|
+
# gem push (RubyGems)
|
|
13
|
+
# twine upload (PyPI)
|
|
14
|
+
# pip upload (PyPI alternative)
|
|
15
|
+
# cargo publish (crates.io)
|
|
16
|
+
# dotnet nuget push (.NET NuGet)
|
|
17
|
+
# docker push (Docker Hub)
|
|
18
|
+
# helm push (Helm charts)
|
|
19
|
+
#
|
|
20
|
+
# TRIGGER: PreToolUse MATCHER: "Bash"
|
|
21
|
+
|
|
22
|
+
INPUT=$(cat)
|
|
23
|
+
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
24
|
+
|
|
25
|
+
[ -z "$COMMAND" ] && exit 0
|
|
26
|
+
|
|
27
|
+
# Block gem push (RubyGems)
|
|
28
|
+
if echo "$COMMAND" | grep -qE '\bgem\s+push\b'; then
|
|
29
|
+
echo "BLOCKED: RubyGems publish detected." >&2
|
|
30
|
+
echo " Publishing to RubyGems is irreversible. Verify version and credentials." >&2
|
|
31
|
+
exit 2
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# Block PyPI upload (twine/pip)
|
|
35
|
+
if echo "$COMMAND" | grep -qE '\b(twine|pip)\s+upload\b'; then
|
|
36
|
+
echo "BLOCKED: PyPI upload detected." >&2
|
|
37
|
+
exit 2
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# Block cargo publish (crates.io)
|
|
41
|
+
if echo "$COMMAND" | grep -qE '\bcargo\s+publish\b'; then
|
|
42
|
+
echo "BLOCKED: crates.io publish detected." >&2
|
|
43
|
+
exit 2
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# Block dotnet nuget push
|
|
47
|
+
if echo "$COMMAND" | grep -qE '\bdotnet\s+nuget\s+push\b'; then
|
|
48
|
+
echo "BLOCKED: NuGet publish detected." >&2
|
|
49
|
+
exit 2
|
|
50
|
+
fi
|
|
51
|
+
|
|
52
|
+
# Block docker push
|
|
53
|
+
if echo "$COMMAND" | grep -qE '\bdocker\s+push\b'; then
|
|
54
|
+
echo "BLOCKED: Docker image push detected." >&2
|
|
55
|
+
echo " Verify the image tag and registry before pushing." >&2
|
|
56
|
+
exit 2
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# Block helm push
|
|
60
|
+
if echo "$COMMAND" | grep -qE '\bhelm\s+(push|package.*push)\b'; then
|
|
61
|
+
echo "BLOCKED: Helm chart push detected." >&2
|
|
62
|
+
exit 2
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
exit 0
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# sensitive-file-read-guard.sh — Block reading sensitive system/user files
|
|
3
|
+
#
|
|
4
|
+
# Solves: Claude Code reading private keys, credentials, password files
|
|
5
|
+
# via the Read tool. Even reading these files exposes secrets in
|
|
6
|
+
# the conversation context, which persists in transcripts.
|
|
7
|
+
#
|
|
8
|
+
# Detects (via Read tool):
|
|
9
|
+
# ~/.ssh/id_rsa, id_ed25519 (private keys)
|
|
10
|
+
# ~/.gnupg/ (GPG keys)
|
|
11
|
+
# ~/.aws/credentials (AWS credentials)
|
|
12
|
+
# /etc/shadow (password hashes)
|
|
13
|
+
# *.pem, *.key (certificate private keys)
|
|
14
|
+
# .env.production (production secrets)
|
|
15
|
+
#
|
|
16
|
+
# Does NOT block:
|
|
17
|
+
# ~/.ssh/config (SSH config, no secrets)
|
|
18
|
+
# ~/.ssh/id_rsa.pub (public keys are fine)
|
|
19
|
+
# /etc/passwd (no secrets, world-readable)
|
|
20
|
+
# Regular project files
|
|
21
|
+
#
|
|
22
|
+
# TRIGGER: PreToolUse MATCHER: "Read"
|
|
23
|
+
|
|
24
|
+
INPUT=$(cat)
|
|
25
|
+
FILE=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
|
|
26
|
+
|
|
27
|
+
[ -z "$FILE" ] && exit 0
|
|
28
|
+
|
|
29
|
+
# Block private key files
|
|
30
|
+
if echo "$FILE" | grep -qiE '(id_rsa|id_ed25519|id_ecdsa|id_dsa)$'; then
|
|
31
|
+
# Allow .pub files
|
|
32
|
+
echo "$FILE" | grep -qiE '\.pub$' && exit 0
|
|
33
|
+
echo "BLOCKED: Reading private key file: $FILE" >&2
|
|
34
|
+
echo " Private keys should never be read into conversation context." >&2
|
|
35
|
+
exit 2
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
# Block certificate private keys
|
|
39
|
+
if echo "$FILE" | grep -qiE '\.(pem|key)$' && echo "$FILE" | grep -qiE '(private|server|ssl|tls)'; then
|
|
40
|
+
echo "BLOCKED: Reading certificate private key: $FILE" >&2
|
|
41
|
+
exit 2
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# Block credential files
|
|
45
|
+
if echo "$FILE" | grep -qiE '\.aws/credentials|\.gcloud/credentials|\.azure/|/etc/shadow|\.gnupg/'; then
|
|
46
|
+
echo "BLOCKED: Reading credential/secret file: $FILE" >&2
|
|
47
|
+
exit 2
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# Block production env files
|
|
51
|
+
if echo "$FILE" | grep -qiE '\.env\.(production|prod|staging)$'; then
|
|
52
|
+
echo "BLOCKED: Reading production environment file: $FILE" >&2
|
|
53
|
+
echo " Production secrets should not be in conversation context." >&2
|
|
54
|
+
exit 2
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
exit 0
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# systemd-service-guard.sh — Block dangerous systemd service operations
|
|
3
|
+
#
|
|
4
|
+
# Solves: Claude Code stopping/restarting system services without
|
|
5
|
+
# understanding the impact. Stopping nginx kills all connections,
|
|
6
|
+
# stopping postgresql causes data loss if not cleanly shut down.
|
|
7
|
+
#
|
|
8
|
+
# Detects:
|
|
9
|
+
# systemctl stop <service>
|
|
10
|
+
# systemctl restart <service>
|
|
11
|
+
# systemctl disable <service>
|
|
12
|
+
# systemctl mask <service>
|
|
13
|
+
# service <name> stop
|
|
14
|
+
#
|
|
15
|
+
# Does NOT block:
|
|
16
|
+
# systemctl status <service>
|
|
17
|
+
# systemctl start <service> (starting is generally safe)
|
|
18
|
+
# systemctl list-units
|
|
19
|
+
# journalctl
|
|
20
|
+
#
|
|
21
|
+
# TRIGGER: PreToolUse MATCHER: "Bash"
|
|
22
|
+
|
|
23
|
+
INPUT=$(cat)
|
|
24
|
+
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty' 2>/dev/null)
|
|
25
|
+
|
|
26
|
+
[ -z "$COMMAND" ] && exit 0
|
|
27
|
+
|
|
28
|
+
# Block systemctl stop/restart/disable/mask
|
|
29
|
+
if echo "$COMMAND" | grep -qE '\bsystemctl\s+(stop|restart|disable|mask)\b'; then
|
|
30
|
+
ACTION=$(echo "$COMMAND" | grep -oE 'systemctl\s+(stop|restart|disable|mask)\s+\S+')
|
|
31
|
+
echo "BLOCKED: Dangerous systemd operation: $ACTION" >&2
|
|
32
|
+
echo " Stopping/restarting services can cause downtime and data loss." >&2
|
|
33
|
+
echo " Use 'systemctl status <service>' to check before acting." >&2
|
|
34
|
+
exit 2
|
|
35
|
+
fi
|
|
36
|
+
|
|
37
|
+
# Block legacy service command
|
|
38
|
+
if echo "$COMMAND" | grep -qE '\bservice\s+\S+\s+(stop|restart)\b'; then
|
|
39
|
+
echo "BLOCKED: Dangerous service operation." >&2
|
|
40
|
+
echo " Command: $COMMAND" >&2
|
|
41
|
+
exit 2
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
exit 0
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cc-safe-setup",
|
|
3
|
-
"version": "29.6.
|
|
4
|
-
"description": "One command to make Claude Code safe.
|
|
3
|
+
"version": "29.6.15",
|
|
4
|
+
"description": "One command to make Claude Code safe. 434 example hooks + 8 built-in. 52 CLI commands. 5800 tests. Works with Auto Mode.",
|
|
5
5
|
"main": "index.mjs",
|
|
6
6
|
"bin": {
|
|
7
7
|
"cc-safe-setup": "index.mjs"
|