Security scan
Production-grade configuration management for Claude Code. Hooks, agents, skills, multi-project orchestration.
npx -y skills add claude-hangar/claude-hangar --skill security-scanAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Security scan for Claude Code projects (secrets, MCP permissions, hook safety, dependencies). Use when: "security scan", "check security", "is this secure", "before deploy security", "scan for secrets".
SKILL.md
17.1 KB, as published. Nobody here has run it
/security-scan — Security Scan
Security scanner for Claude Code projects. Checks for hardcoded secrets, MCP server permissions, hook safety, dependency vulnerabilities, and configuration anti-patterns. Read-only — analyzes but never modifies.
Problem
Claude Code projects have a unique attack surface: MCP servers with broad permissions, hook scripts that execute automatically, and configuration files that can disable safety checks. Standard security scanners miss these Claude Code-specific vectors entirely.
Modes
| Mode | Trigger | Scope |
|---|---|---|
scan | /security-scan (default) | All 5 phases |
secrets | /security-scan secrets | Phase 1 only |
mcp | /security-scan mcp | Phase 2 only |
hooks | /security-scan hooks | Phase 3 only |
deps | /security-scan deps | Phase 4 only |
config | /security-scan config | Phase 5 only |
Phase 1: Secret Detection
Scan for hardcoded secrets in source files, configs, and environment handling.
1.1 Hardcoded Secret Patterns
Search all tracked files (respect .gitignore) for these pattern categories.
NOTE: Use the same detection patterns defined in the project's
secret-leak-check.shhook as a baseline. The hook file is the canonical source of secret patterns — do not duplicate regexes here. Instead, reference the hook and add these additional categories:
| Category | What to detect | Severity |
|---|---|---|
| Cloud provider access keys | AWS key ID prefixes, cloud secret key assignments | CRITICAL |
| Generic API keys | Variables named api_key/apikey assigned string values 20+ chars | HIGH |
| Generic secrets | Variables named secret/passwd assigned non-placeholder values 8+ chars | HIGH |
| Private keys | PEM-format private key headers (RSA, EC, DSA, OPENSSH) | CRITICAL |
| Platform tokens | GitHub ghp_/gho_/ghs_/ghr_ prefixed tokens, Slack xox* prefixed tokens | CRITICAL/HIGH |
| JWTs | Base64url-encoded three-segment eyJ... strings | MEDIUM |
| Connection strings | Database URIs with embedded credentials (user:pass@host format) | CRITICAL |
| Bearer tokens | Literal bearer token values in code | HIGH |
Exclusions: Skip node_modules/, .git/, dist/, build/, lock files, and binary files.
Skip patterns inside comments that are clearly examples (e.g. YOUR_KEY_HERE, xxx, changeme).
Finding: SEC-S-{NN}: Hardcoded {type} found in {file}:{line}
1.2 Environment File Safety
| Check | Pass | Fail |
|---|---|---|
.env in .gitignore | .gitignore contains .env pattern | Missing — CRITICAL |
.env not committed | git ls-files .env returns empty | .env is tracked — CRITICAL |
.env.example exists | File present with placeholder values | Missing — LOW |
.env.local in .gitignore | Pattern present | Missing — MEDIUM |
Finding: SEC-S-{NN}: {description}
1.3 Gitignore Completeness
Check .gitignore for these security-relevant patterns:
| Pattern | Purpose | Severity if missing |
|---|---|---|
.env | Environment variables | CRITICAL |
*.pem / *.key | Private keys | HIGH |
.claude/credentials* | Claude credentials | HIGH |
*.sqlite / *.db | Local databases | MEDIUM |
.security-scan-state.json | Scan state | INFO |
Finding: SEC-S-{NN}: .gitignore missing pattern for {pattern}
Phase 2: MCP Server Audit
Analyze MCP server configurations for permission and trust issues.
2.1 Locate MCP Config
Read MCP server configs from these locations (in priority order):
.claude/settings.json(project-level)~/.claude/settings.json(user-level)
Parse with node -e (cross-platform). Extract mcpServers object.
2.2 Permission Analysis
For each MCP server, check:
| Check | Condition | Severity |
|---|---|---|
| File system access | Server has filesystem or fs capabilities | HIGH |
| Network access | Server has fetch, http, or network capabilities | HIGH |
| Shell execution | Server can run bash, exec, or command | CRITICAL |
| Broad permissions | Server has * or all in permission list | CRITICAL |
| Write permissions | Server has write access to project files | MEDIUM |
Finding: SEC-M-{NN}: MCP server "{name}" has {permission} — {risk description}
2.3 Trust Assessment
| Check | Condition | Severity |
|---|---|---|
| Unknown source | Server not from npm/official registry, no GitHub link | HIGH |
| No version pinning | Server uses latest or unpinned version | MEDIUM |
| Local file server | Server points to local script (check script exists and content) | MEDIUM |
| Excessive server count | More than 10 MCP servers configured | LOW |
Finding: SEC-M-{NN}: {description}
2.4 Known Safe Servers
Maintain a list of recognized MCP servers (do not flag these as unknown):
@anthropic-ai/*— Official Anthropic servers@modelcontextprotocol/*— Official MCP serversplaywright— Browser automationgithub— GitHub integrationcontext7— Documentation lookup
Servers not on this list get an INFO finding, not automatic HIGH.
Phase 3: Hook Safety
Analyze hook scripts for dangerous patterns that could indicate supply-chain attacks or accidental security holes.
3.1 Locate Hooks
Search for hook definitions in:
.claude/settings.json>hooksobject.claude/hooks/directory (all.sh,.js,.mjsfiles)
3.2 Dangerous Patterns
Scan each hook script/command for:
| Pattern | What to look for | Severity | Rationale |
|---|---|---|---|
| eval usage | The eval keyword in shell/JS | HIGH | Arbitrary code execution |
| exec with variable | exec followed by unresolved variable | HIGH | Command injection |
| Unquoted variables | Shell variables expanded without quotes | MEDIUM | Word splitting, globbing |
| curl to external host | curl targeting non-localhost URLs | HIGH | Data exfiltration |
| wget to external host | wget targeting non-localhost URLs | HIGH | Data exfiltration |
| Base64 decode piped to shell | Decoded base64 piped into bash/sh/node | CRITICAL | Obfuscated payload |
| Network send with data | curl/wget with POST data flags | CRITICAL | Data exfiltration |
| Environment dumping | Commands that dump all env vars to file | HIGH | Credential leak |
| Write to system dirs | Writes to /usr/bin/, /usr/sbin/, etc. | HIGH | System modification |
| Download and execute | curl/wget piped directly into shell | CRITICAL | Remote code execution |
Finding: SEC-H-{NN}: Hook "{name}" contains {pattern} — {risk}
3.3 Hook Structure Checks
| Check | Pass | Fail |
|---|---|---|
Uses node -e for JSON parsing | Correct pattern | Uses jq or custom parsing — INFO |
| Hook has clear purpose | Descriptive name/comment | Unnamed or obfuscated — LOW |
| Hook modifies files | Acceptable if documented | Undocumented modification — MEDIUM |
| Hook runs external commands | Acceptable if local | Calls external services — HIGH |
Finding: SEC-H-{NN}: {description}
Phase 4: Dependency Audit
Check project dependencies for known vulnerabilities and risk signals.
4.1 npm Audit (if applicable)
If package.json exists:
npm audit --json 2>/dev/null | node -e "
const data = JSON.parse(require('fs').readFileSync(0,'utf8'));
const meta = data.metadata || {};
const vulns = meta.vulnerabilities || {};
console.log(JSON.stringify({
total: meta.totalDependencies || 0,
critical: vulns.critical || 0,
high: vulns.high || 0,
moderate: vulns.moderate || 0,
low: vulns.low || 0
}));
"
Map results to findings:
| npm severity | Scan severity | Finding |
|---|---|---|
| critical | CRITICAL | SEC-D-{NN}: {count} critical vulnerabilities in dependencies |
| high | HIGH | SEC-D-{NN}: {count} high vulnerabilities in dependencies |
| moderate | MEDIUM | SEC-D-{NN}: {count} moderate vulnerabilities in dependencies |
| low | LOW | SEC-D-{NN}: {count} low vulnerabilities in dependencies |
If npm audit is unavailable or fails, note it as INFO and continue.
4.2 Dependency Risk Signals
Check package.json for:
| Check | Condition | Severity |
|---|---|---|
| No lock file | Neither package-lock.json nor yarn.lock nor pnpm-lock.yaml | HIGH |
| Wildcard versions | "*" or "" in dependency versions | HIGH |
| Git dependencies | "dep": "git+..." or "dep": "github:..." | MEDIUM |
| File dependencies | "dep": "file:..." | MEDIUM |
| Excessive dependencies | >100 direct dependencies in a single package.json | LOW |
| No dev/prod separation | All deps in dependencies, none in devDependencies | LOW |
Finding: SEC-D-{NN}: {description}
4.3 Python Audit (if applicable)
If requirements.txt or pyproject.toml exists:
- Check for pinned versions (== vs >=)
- Flag unpinned dependencies as MEDIUM
- If
pip-auditis available, run it
4.4 Outdated Major Versions
If package.json exists, check for major version staleness:
npm outdated --json 2>/dev/null | node -e "
const data = JSON.parse(require('fs').readFileSync(0,'utf8'));
Object.entries(data).forEach(([pkg, info]) => {
const curr = (info.current || '').split('.')[0];
const latest = (info.latest || '').split('.')[0];
if (curr && latest && curr !== latest) {
console.log(pkg + ': ' + info.current + ' -> ' + info.latest);
}
});
"
Finding: SEC-D-{NN}: {package} is {N} major versions behind ({current} -> {latest}) — LOW
Phase 5: Configuration Review
Check Claude Code and project configuration for security anti-patterns.
5.1 CLAUDE.md Security Review
Read project CLAUDE.md (if present) and flag:
| Pattern | What to look for | Severity |
|---|---|---|
| Disabled checks | Instructions to skip/disable/ignore/bypass security, auth, or validation | HIGH |
| Force push instructions | Mentions of force push, --force, or --no-verify | MEDIUM |
| Hardcoded credentials | Same categories as Phase 1 | CRITICAL |
| Overly permissive instructions | "always approve", "auto-approve", "no review needed" | HIGH |
| Debug mode | Debug or development mode enabled in non-dev context | MEDIUM |
Finding: SEC-C-{NN}: CLAUDE.md contains {pattern} — {risk}
5.2 Settings Security
Check .claude/settings.json for:
| Check | Condition | Severity |
|---|---|---|
| Allow-all permissions | Permissions set to * or allow_all | HIGH |
| Disabled safety features | Any safety/guard feature explicitly disabled | CRITICAL |
| Unrestricted file access | No file path restrictions configured | MEDIUM |
Finding: SEC-C-{NN}: {description}
5.3 Production Config Leaks
Check for development/debug settings that should not be in production:
| Check | File(s) | Condition | Severity |
|---|---|---|---|
| Debug mode in prod config | docker-compose.yml, Dockerfile | NODE_ENV=development or DEBUG=* | HIGH |
| Source maps in production | Build config | sourcemap: true in prod build | MEDIUM |
| Verbose logging | App config | LOG_LEVEL=debug in prod | LOW |
| Dev dependencies in prod | Dockerfile | npm install without --production or --omit=dev | MEDIUM |
Finding: SEC-C-{NN}: {description}
Grading System
After all phases complete, calculate a letter grade based on weighted findings.
Point Deductions
| Severity | Points per finding |
|---|---|
| CRITICAL | -20 |
| HIGH | -10 |
| MEDIUM | -3 |
| LOW | -1 |
| INFO | 0 |
Grade Thresholds
Start at 100 points, subtract per finding:
| Score | Grade | Assessment |
|---|---|---|
| 95-100 | A | Excellent — minimal risk |
| 85-94 | A- | Strong — minor improvements possible |
| 75-84 | B | Good — some issues to address |
| 65-74 | B- | Acceptable — notable gaps |
| 55-64 | C | Fair — significant issues |
| 40-54 | C- | Weak — multiple serious issues |
| 25-39 | D | Poor — immediate action needed |
| 0-24 | F | Failing — critical vulnerabilities present |
Grade Caps
Regardless of total score, the grade is capped if:
| Condition | Max grade |
|---|---|
| Any CRITICAL finding open | D |
| 3+ HIGH findings open | C |
| No .gitignore for .env | D |
| Secrets committed to git | F |
Output Format
Security Scan: {project-name}
====================================
Grade: {letter} ({score}/100)
Phase 1: Secret Detection
{OK | FINDINGS}
- SEC-S-01 [CRITICAL] Hardcoded credential in src/config.ts:42
- SEC-S-02 [HIGH] .env not in .gitignore
Phase 2: MCP Server Audit
{OK | FINDINGS}
- SEC-M-01 [HIGH] MCP server "custom-fs" has unrestricted file system access
Phase 3: Hook Safety
{OK | FINDINGS}
Phase 4: Dependency Audit
{OK | FINDINGS}
- SEC-D-01 [CRITICAL] 2 critical vulnerabilities (npm audit)
- SEC-D-02 [LOW] express is 2 major versions behind (4.x -> 5.x)
Phase 5: Configuration Review
{OK | FINDINGS}
- SEC-C-01 [HIGH] CLAUDE.md contains "skip security checks"
------------------------------------
Summary: {total} findings
CRITICAL: {n} HIGH: {n} MEDIUM: {n} LOW: {n} INFO: {n}
{grade_explanation}
State File (.security-scan-state.json)
Written after every scan. Enables trend tracking across sessions.
{
"version": "1.0",
"scanDate": "2026-04-04",
"project": "my-project",
"grade": "B",
"score": 78,
"phases": {
"secrets": { "status": "done", "findings": 2 },
"mcp": { "status": "done", "findings": 1 },
"hooks": { "status": "done", "findings": 0 },
"deps": { "status": "done", "findings": 3 },
"config": { "status": "done", "findings": 1 }
},
"findings": [
{
"id": "SEC-S-01",
"phase": "secrets",
"severity": "CRITICAL",
"title": "Hardcoded credential in src/config.ts:42",
"file": "src/config.ts",
"line": 42,
"status": "open"
}
],
"history": [
{ "date": "2026-03-20", "grade": "C", "score": 58, "findings": 12 },
{ "date": "2026-04-04", "grade": "B", "score": 78, "findings": 7 }
]
}
Smart Next Steps
After the scan completes, recommend follow-up actions based on findings:
| Condition | Recommendation |
|---|---|
| CRITICAL secrets found | Remove secrets immediately, rotate affected credentials, add to .gitignore |
| MCP permission issues | Review .claude/settings.json, restrict server permissions to minimum needed |
| Hook safety concerns | Review flagged hooks, replace dangerous patterns with safe alternatives |
| Dependency vulnerabilities | Run npm audit fix, update outdated packages, review breaking changes |
| Config anti-patterns | Update CLAUDE.md, remove debug settings from production configs |
| Grade D or F | Run /security-scan again after fixes to verify improvement |
| Grade A or B | Run /deploy-check to verify deployment readiness |
| Any findings | Run /adversarial-review code for deeper code-level security review |
| Auth detected | Run /auth-audit for authentication-specific security checks |
| Always | Add security scan to CI pipeline (pre-commit or PR check) |
Rules
- Read-only — Never modify project files, only analyze and report
- No false confidence — If a check cannot be performed (tool missing, file inaccessible), report as INFO, do not skip silently
- Cross-platform — Use
node -efor JSON parsing, notjq. Avoid platform-specific commands - Respect .gitignore — Do not scan
node_modules/,.git/,dist/,build/, or other excluded directories - No network calls — Do not send project data anywhere. All analysis is local
- Severity accuracy — Do not inflate or deflate severity. Follow the definitions exactly
- Idempotent — Running the scan twice produces the same result (unless project changed)
- Example detection — Do not flag obvious placeholder values (
YOUR_KEY_HERE,changeme,xxx) as real secrets - Privacy — Never log or display actual secret values. Show only pattern match and file location
- Anti-rationalization — Do not skip checks or reduce severity because the project "seems fine". See
_shared/anti-rationalization.md
Files
security-scan/
├── SKILL.md <- This file
└── skill.json <- Skill metadata and triggers