skills/security-setup/SKILL.md
Configure and manage Claude Code security protections for sensitive files, credentials, and data. Use when the user invokes /security-setup to set up or modify protections against unauthorized file access, credential exposure, or sensitive data leaks.
npx skillsauth add musserlab/lab-claude-skills security-setupInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
When the user invokes /security-setup, configure or update Claude Code security protections. This skill is re-runnable — it detects whether protections are already configured and adjusts its workflow accordingly.
Check if ~/.claude/hooks/protect-sensitive-reads.sh exists:
Also check if ~/.claude/hooks/protect-sensitive-writes.sh exists. If the reads hook exists but the writes hook does not, treat as returning user (Section 2) — the upgrade path in Step 4 will add the missing writes hook.
Tell the user:
Claude Code can read any file on your machine and run any shell command — including accessing saved passwords, API keys, email, cloud storage, and sensitive research data. This skill sets up layered protections:
- Hooks — scripts that intercept Read and Bash operations, blocking access to sensitive locations
- Deny rules — settings.json rules that block access even if a hook has a bug
- Bash scoping — replacing the blanket
Bash(*)permission with specific allowed commandsThe plugin already provides baseline protection. This setup adds personal protections tailored to your machine.
Determine the operating system and shell environment:
uname -s 2>/dev/null # Darwin, Linux, MINGW64_NT-* (Git Bash), or fails on cmd/PowerShell
echo %OS% 2>/dev/null # "Windows_NT" on Windows cmd/PowerShell
$PSVersionTable 2>/dev/null # Non-empty on PowerShell
Platform categories:
uname -s returns Darwinuname -s returns Linux (also check for WSL: grep -qi "microsoft\|wsl" /proc/version 2>/dev/null)uname -s returns MINGW* or CYGWIN* — bash is available, hooks may workuname fails or isn't available — hooks won't work, focus on deny rulesTest hook capability on Windows: If on Windows, test whether bash scripts can execute:
bash -c "echo hook-test" 2>/dev/null
If this succeeds, hooks are viable. If it fails, skip hook generation and note that deny rules are the primary protection.
Use the detected platform to select the appropriate scan paths in Step 2 and determine whether to generate hooks (Step 6).
Detect HPC cluster environment (Linux only):
If Linux is detected, also check for HPC cluster indicators:
command -v module >/dev/null 2>&1 # Environment modules (HPC)
command -v squeue >/dev/null 2>&1 # SLURM scheduler
ls -d /nfs/ 2>/dev/null # NFS mounts (common on HPC)
hostname -f 2>/dev/null # Check for *.ycrc.yale.edu
HPC detection criteria — if 2 or more of these are true, the environment is an HPC cluster:
module command is availablesqueue command is available/nfs/ directory exists*.ycrc.yale.eduIf HPC is detected, note the cluster identity for use in Step 7:
bouchet → Bouchet clustermccleary → McCleary clusterStore the HPC detection result — it affects template selection (Step 7) and bash scoping decisions.
Run discovery commands to check which sensitive locations exist on the user's machine. Use ls -d with 2>/dev/null for each path. Only scan paths relevant to the detected platform. Organize results by category:
Credential stores & config:
~/.ssh/, ~/.aws/, ~/.gnupg/~/.config/gh/, ~/.config/gcloud/, ~/.docker/, ~/.kube/, ~/.azure/~/.config/op/ (1Password CLI)~/.netrc, ~/.npmrc, ~/.pypirc, ~/.git-credentials~/.Renviron (R environment variables, may contain API keys)IDE configs (may contain tokens):
~/.jupyter/~/.ipython/Scattered credential files:
.env files: find ~ -maxdepth 3 -name ".env" -o -name ".env.*" 2>/dev/nullfind ~ -maxdepth 3 -name "credentials.json" -o -name "service-account*.json" 2>/dev/nullPassword managers:
~/Library/Keychains/~/Library/Application Support/1Password/, ~/Library/Containers/com.1password.*~/Library/Application Support/Bitwarden/~/Library/Application Support/KeePassXC/~/Library/Application Support/LastPass/Browser profiles (saved passwords, cookies, sessions):
~/Library/Application Support/Google/Chrome/~/Library/Safari/~/Library/Application Support/Firefox/~/Library/Application Support/Microsoft Edge/Communication apps (email, messages, chat logs):
~/Library/Mail/~/Library/Messages/~/Library/Application Support/Microsoft/Teams/~/Library/Application Support/Slack/~/Library/Application Support/zoom.us/Cloud storage mounts:
~/Library/CloudStorage/OneDrive-*/~/Library/CloudStorage/GoogleDrive-*/, ~/*Google Drive*~/Dropbox/~/Library/Mobile Documents/~/Library/CloudStorage/Box-*/, ~/Box/IDE configs:
~/Library/Application Support/Code/User/~/.positron/Password managers & keyrings:
~/.local/share/keyrings/~/.local/share/kwalletd/~/.config/1Password/~/.config/Bitwarden/~/.config/keepassxc/, ~/.local/share/keepassxc/Browser profiles:
~/.config/google-chrome/~/.config/chromium/~/.mozilla/firefox/~/.config/microsoft-edge/Communication apps:
~/.thunderbird/~/.local/share/evolution/~/.config/Slack/~/.config/teams-for-linux/Cloud storage mounts:
~/Dropbox/mount | grep fuse (Google Drive, rclone-mounted OneDrive, etc.)IDE configs:
~/.config/Code/User/~/.config/Positron/, ~/.positron/Windows-side sensitive locations — scan /mnt/c/Users/*/ for:
AppData/Local/Google/Chrome/AppData/Local/Microsoft/Edge/AppData/Roaming/Mozilla/Firefox/AppData/Local/1Password/AppData/Roaming/keepassxc/.ssh/, .aws/Note: The Windows-side user directory is at /mnt/c/Users/<username>/. Use ls /mnt/c/Users/ to find the right username (skip Public and Default).
On native Windows, $HOME or %USERPROFILE% typically points to C:\Users\<username>. Use echo $HOME or echo %USERPROFILE% to find the home directory, then scan:
Credential stores:
$HOME/.ssh/, $HOME/.aws/, $HOME/.gnupg/$HOME/.config/gh/, $HOME/.config/gcloud/$HOME/.netrc, $HOME/.npmrc, $HOME/.pypirc, $HOME/.git-credentials$HOME/.RenvironBrowser profiles (saved passwords, cookies, sessions):
$HOME/AppData/Local/Google/Chrome/User Data/$HOME/AppData/Roaming/Mozilla/Firefox/$HOME/AppData/Local/Microsoft/Edge/User Data/Password managers:
$HOME/AppData/Local/1Password/$HOME/AppData/Roaming/KeePassXC/$HOME/AppData/Roaming/Bitwarden/Communication apps:
$HOME/AppData/Roaming/Microsoft/Teams/$HOME/AppData/Roaming/Slack/$HOME/AppData/Roaming/Zoom/Cloud storage:
$HOME/OneDrive/ or $HOME/OneDrive - */G:/ or $HOME/Google Drive/ (varies by install)$HOME/Dropbox/IDE configs:
$HOME/AppData/Roaming/Code/User/$HOME/AppData/Roaming/Positron/ (if applicable)$HOME/.jupyter/Windows Credential Manager: Not file-based, but block cmdkey and vaultcmd commands via deny rules.
Show a categorized summary table with "Found" / "Not found" for each item. Group by risk level (Critical / High / Medium).
Use AskUserQuestion:
Depending on mode choice:
Allowlist mode: Ask: "Which directories should Claude be allowed to read? Your current project directory is always allowed automatically."
Suggest common patterns:
Blocklist mode: All scanned sensitive dirs are blocked by default. Ask two questions:
Skip this step on Windows if bash is not available (detected in Step 1b). Instead, tell the user:
Your shell doesn't support bash hooks, so we'll skip hook generation and rely on deny rules (settings.json) as your primary protection. Deny rules are evaluated by Claude Code directly and work on all platforms.
Then proceed to Step 7, which generates comprehensive deny rules.
On macOS, Linux, or Windows with bash available:
Read the template files from the skill's templates/ directory:
templates/protect-sensitive-reads.shtemplates/protect-sensitive-writes.shtemplates/protect-sensitive-bash.shCustomize the templates:
MODE= to the user's choice (same mode for reads and writes)ALLOWED_DIRS or BLOCKED_DIRS with the user's paths — keep reads and writes hooks in syncBLOCKED_DIRS (blocklist mode) or leave them out of ALLOWED_DIRS (allowlist mode)com.1password.1password-launcher) to ALWAYS_BLOCK_DIRSALLOWED_PATH_EXCEPTIONS in the bash hook with the same cloud storage project exceptionsWrite the customized hooks to ~/.claude/hooks/:
~/.claude/hooks/protect-sensitive-reads.sh~/.claude/hooks/protect-sensitive-writes.sh~/.claude/hooks/protect-sensitive-bash.shMake them executable with chmod +x.
Write security version stamp: Read the current SECURITY_VERSION from scripts/SECURITY_VERSION in the plugin root (or use the version in the <!-- Current SECURITY_VERSION: N --> comment at the top of this skill as a fallback). Write the same version number to ~/.claude/hooks/SECURITY_VERSION. This allows project-reminders.sh to detect when personal hooks are outdated relative to the plugin.
Read ~/.claude/settings.json. Make these changes:
Select base template based on platform (first-time setup only):
templates/settings-cluster.json from the lab plugin provides cluster-appropriate defaults — glob-based deny rules, blanket Bash(*), CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC, YCRC WebFetch domains, and extra protections against filesystem destruction and process killing. Suggest using it as the starting point.templates/settings-example.json is appropriate — scoped bash permissions, macOS-specific deny paths.Add deny rules (defense-in-depth) for critical paths found in the scan. Only add deny rules for paths that actually exist. Use the user's actual home directory path (not $HOME).
HPC cluster deny rules: On HPC clusters, prefer glob patterns (**/.ssh/**) over absolute paths, and include cluster-specific protections for shared filesystems and multi-user systems:
"Bash(rm -rf /*)",
"Bash(rm -rf /nfs*)",
"Bash(rm -rf ~*)",
"Bash(kill -9 *)",
"Bash(killall *)",
"Bash(pkill *)",
"Bash(su *)",
"Bash(mkfs *)"
macOS example:
"Read(/Users/username/.ssh/*)",
"Read(/Users/username/.aws/*)",
"Read(/Users/username/Library/Keychains/*)",
"Read(/Users/username/Library/Mail/*)",
"Read(/Users/username/Library/Messages/*)",
"Read(/Users/username/Library/Safari/*)",
"Read(/Users/username/Library/Application Support/1Password/*)",
"Read(/Users/username/Library/Application Support/Google/Chrome/*)"
Linux example:
"Read(/home/username/.ssh/*)",
"Read(/home/username/.aws/*)",
"Read(/home/username/.config/google-chrome/*)",
"Read(/home/username/.mozilla/firefox/*)",
"Read(/home/username/.local/share/keyrings/*)",
"Read(/home/username/.config/1Password/*)",
"Read(/home/username/.thunderbird/*)"
WSL — include both Linux and Windows-side paths:
"Read(/home/username/.ssh/*)",
"Read(/mnt/c/Users/winuser/.ssh/*)",
"Read(/mnt/c/Users/winuser/AppData/Local/Google/Chrome/*)"
Register hooks in the PreToolUse section (if not already registered):
{ "matcher": "Read", "hooks": [{ "type": "command", "command": "~/.claude/hooks/protect-sensitive-reads.sh" }] },
{ "matcher": "Edit", "hooks": [{ "type": "command", "command": "~/.claude/hooks/protect-sensitive-writes.sh" }] },
{ "matcher": "Write", "hooks": [{ "type": "command", "command": "~/.claude/hooks/protect-sensitive-writes.sh" }] }
Add the bash hook to the existing Bash matcher's hooks array.
Ask about Bash scoping (skip on HPC clusters — keep Bash(*)):
On HPC clusters, module load, SLURM commands, and cluster-specific tools are too numerous and variable to scope individually. Keep Bash(*) and rely on hooks and deny rules for safety. Do not prompt the user about bash scoping on HPC.
On macOS/Linux desktops: "The current setting allows all bash commands (Bash(*)). Would you like to replace this with a specific allowlist of commands (more secure but you'll be prompted for unlisted commands)?"
If yes, replace Bash(*) with scoped commands. Collect what tools they commonly use and suggest a starting list:
git, conda, pip, python, Rscript, R, quarto, ls, mkdir, cp, mv, rm, chmod,
wc, diff, head, tail, sort, cut, uniq, which, type, gh, npm
Plus any domain-specific tools (mafft, iqtree, samtools, etc.).
Test that protections work:
~/.ssh/ — should be blockedcat ~/.aws/credentials — should be blockedgit status — should workReport results to the user.
Read ~/.claude/hooks/SECURITY_VERSION (if it exists) to get the personal security version. Read scripts/SECURITY_VERSION from the plugin root to get the current plugin version.
Parse ~/.claude/hooks/protect-sensitive-reads.sh to extract:
MODE (allowlist or blocklist)ALLOWED_DIRS array contentsBLOCKED_DIRS array contentsALWAYS_BLOCK_DIRS array contentsCheck if ~/.claude/hooks/protect-sensitive-writes.sh exists:
MODE, ALLOWED_DIRS, BLOCKED_DIRS, ALWAYS_BLOCK_DIRS (should match reads hook)Parse ~/.claude/hooks/protect-sensitive-bash.sh to extract:
BLOCKED_PATH_KEYWORDS array contentsALLOWED_PATH_EXCEPTIONS array contentsParse ~/.claude/settings.json to extract:
Bash(*))Show a summary organized by:
Bash(*)Use AskUserQuestion with mode-appropriate options:
Allowlist mode options:
Blocklist mode options:
Both modes:
If writes hook is missing (upgrade path):
Generate ~/.claude/hooks/protect-sensitive-writes.sh from templates/protect-sensitive-writes.sh, copying MODE, ALLOWED_DIRS, BLOCKED_DIRS, and ALWAYS_BLOCK_DIRS from the existing reads hook so they stay in sync. Register Edit and Write matchers in settings.json if not already present. Make executable with chmod +x.
For all other changes: Modify the relevant hook script(s) and/or settings.json. When editing hook scripts:
ALLOWED_DIRS or BLOCKED_DIRS change in one, apply the same change to the otherAfter applying changes, update ~/.claude/hooks/SECURITY_VERSION to the current plugin version (the user just re-ran security-setup, so they're now current).
Show the user what changed (before/after for the modified arrays).
Run the same verification tests as first-time setup to confirm changes work.
development
Phylogenetic tree visualization and formatting with ggtree (R) or iTOL (web). Use when rendering a phylogenetic tree as a figure, choosing tree layout, coloring branches or labels by taxonomy, collapsing clades, displaying support values, or adding overlays to a tree. Do NOT load for tree inference (use protein-phylogeny skill) or domain annotation (future separate skill).
development
Script organization for data science analysis projects with numbered scripts, data/outs/ directories, and reproducibility conventions. Use when creating new analysis scripts in projects that follow data science conventions (numbered XX_ prefix scripts, outs/ directories, BUILD_INFO.txt). Do NOT load for documentation projects (Quarto books), infrastructure repos, or projects without data/outs/ directory structure.
testing
R renv package management for data science projects. Use when working with renv (renv.lock, renv::restore, renv::snapshot) in R analysis projects. Do NOT load for projects that do not use R or renv.
development
R ggplot2 plotting conventions and theme. Use when creating, modifying, or styling ggplot2 plots in R, or when adjusting plot themes, colors, labels, or formatting.