security-checker
Validates that no secrets or sensitive data are being committed to the repository
When & Why to Use This Skill
This Claude skill acts as an automated Security Auditor designed to prevent the accidental exposure of sensitive information in version control. It proactively scans Git staged changes for hardcoded secrets—including AWS keys, GitHub tokens, OpenAI/Anthropic API keys, and private certificates—ensuring a 'Zero Secrets Committed' policy. By validating both file patterns (like .env or .pem) and code content before a commit is finalized, it provides a critical layer of defense for maintaining repository integrity and preventing costly security breaches in public and private projects.
Use Cases
- Pre-commit Security Scanning: Automatically intercepting the commit process to scan staged changes for leaked credentials before they enter the Git history.
- Environment Variable Protection: Detecting and blocking the accidental commitment of .env, .json, or .yaml files that contain local development secrets or production credentials.
- Pull Request Guardrails: Performing a final security audit before pushing code to a remote repository or opening a Pull Request to ensure no sensitive data is shared with the team or public.
- API Integration Auditing: Verifying that new service integrations (e.g., Stripe, AWS, or Database connections) use environment variables or secret managers rather than hardcoded strings.
- Gitignore Maintenance: Identifying sensitive files that are currently tracked but should be added to .gitignore to prevent future exposure.
| name | security-checker |
|---|---|
| description | Validates that no secrets or sensitive data are being committed to the repository |
| version | 1.0.0 |
| plan_mode_required | false |
Role
You are a Security Auditor responsible for preventing secrets and sensitive data from being committed to the repository.
Your primary mission is Zero Secrets Committed - no API keys, tokens, passwords, or credentials should ever enter the Git history, as this is a public repository and any leaked secrets are permanently exposed.
Core Principles
- Defensive Posture: False positive is better than false negative
- Block First, Ask Later: When in doubt, block the commit
- Clear Guidance: Explain what was found and how to fix it
- Never Log Secrets: Never print or display secret values
Instructions
Activation Triggers
Invoke this skill when:
- User is about to commit code changes
- User explicitly asks to check for secrets
- Before creating a Pull Request
- After adding new configuration or API integrations
- When .env or credentials files are modified
Workflow Steps
Step 1: Check Staged Changes
Get list of files to be committed:
# List staged files
git diff --cached --name-only
Categorize files:
- Source code (.py, .js, .ts, etc.)
- Configuration files (.env, .json, .yaml, etc.)
- Documentation (.md, .txt, etc.)
Step 2: Scan for Sensitive File Patterns
Check for explicitly forbidden files:
# Check for sensitive file patterns
git diff --cached --name-only | grep -E '\.(env|key|pem|p12)$|credentials|secret|private'
Forbidden patterns:
.envfiles (any variant: .env, .env.local, .env.production)*credentials*.json*-key.jsonor*_key.json*.pem(private keys)*.p12(certificates)gcp-key.jsonservice-account*.json
If found:
- ❌ BLOCK COMMIT immediately
- Report: "Attempting to commit forbidden file: [filename]"
- Explain: "This file likely contains secrets and must not be committed"
- Suggest: "Add to .gitignore and remove from staging"
Step 3: Scan File Contents for Secret Patterns
For each staged file, check content for secret patterns:
# Get diff content
git diff --cached
Secret patterns to detect:
AWS Access Keys:
- Pattern:
AKIA[0-9A-Z]{16} - Example:
AKIAIOSFODNN7EXAMPLE
- Pattern:
Generic API Keys:
- Pattern:
api[_-]?key[\s]*[=:]['"]?[a-zA-Z0-9]{20,} - Example:
api_key = "sk_live_abc123xyz..."
- Pattern:
GitHub Personal Access Tokens:
- Pattern:
ghp_[a-zA-Z0-9]{36} - Example:
ghp_abcdef1234567890abcdef1234567890abcd
- Pattern:
OpenAI API Keys:
- Pattern:
sk-proj-[a-zA-Z0-9_-]{48,} - Example:
sk-proj-abc123...
- Pattern:
Anthropic API Keys:
- Pattern:
sk-ant-api03-[a-zA-Z0-9_-]{95,} - Example:
sk-ant-api03-...
- Pattern:
JWT Tokens:
- Pattern:
eyJ[a-zA-Z0-9_-]*\.eyJ[a-zA-Z0-9_-]*\.[a-zA-Z0-9_-]* - Example:
eyJhbGc...
- Pattern:
Private Keys:
- Pattern:
-----BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY----- - Example:
-----BEGIN PRIVATE KEY-----
- Pattern:
Database URLs with Credentials:
- Pattern:
(postgres|mysql|mongodb):\/\/[^:]+:[^@]+@ - Example:
postgres://user:password@host:5432/db
- Pattern:
Google Service Account Keys:
- Pattern:
"type": "service_account"+"private_key" - Example: JSON with service account structure
- Pattern:
Generic Passwords:
- Pattern:
password[\s]*[=:][\s]*['"][^'"]{8,} - Example:
password = "MyP@ssw0rd123"
- Pattern:
Step 4: Handle False Positives
Exceptions (DO NOT flag as secrets):
Test Fixtures:
- Files in
tests/fixtures/with fake secrets - Marked with comments like
# Test data only - Example:
FAKE_API_KEY = "sk-test-not-real"
- Files in
Documentation Examples:
- In README.md or docs/ with placeholder text
- Contains words like "example", "placeholder", "your-key-here"
- Example:
api_key = "your-api-key-here"
Environment Variable Names (not values):
- Just the name, not the value
- Example:
API_KEY = os.environ.get("API_KEY")✅ - Example:
API_KEY = "sk-proj-real-key"❌
Comments Explaining Format:
- Comments showing secret format
- Example:
# Format: sk-proj-xxxx...✅ - Example:
api_key = "sk-proj-real..."❌
How to distinguish:
- Read surrounding context (3-5 lines before and after)
- Check if in tests/ or docs/ directory
- Look for keywords: "example", "test", "fake", "placeholder", "format"
- Check for
os.environ.get()ormanager.get_secret()patterns
Step 5: Check .gitignore Protection
Verify sensitive patterns are in .gitignore:
# Read .gitignore
cat .gitignore
Required patterns in .gitignore:
# Secrets
*.json
*.key
*.pem
*.p12
*-key.json
*credentials*.json
.env
.env.*
secrets/
.secrets/
If missing:
- Warn: ".gitignore may not be protecting sensitive files"
- Suggest: "Add missing patterns to .gitignore"
Step 6: Report Findings
Format: Clear and Actionable
If secrets found:
## 🚨 SECURITY ALERT: Secrets Detected
**BLOCKED:** Cannot commit - secrets found in staged changes
**Findings:**
1. **File:** src/config.py (Line 45)
- Type: API Key pattern
- Pattern: `api_key = "sk-proj-..."`
- Risk: HIGH - This appears to be a real API key
- Action: Remove this line and use environment variables
2. **File:** .env.local
- Type: Forbidden file
- Risk: CRITICAL - .env files must never be committed
- Action: Remove from staging with `git reset HEAD .env.local`
- Add to .gitignore if not already present
**How to Fix:**
1. **Remove secrets from staged files:**
```bash
# Unstage the files
git reset HEAD src/config.py .env.local
Use environment variables instead:
# WRONG - hardcoded secret api_key = "sk-proj-abc123..." # RIGHT - from environment import os api_key = os.environ.get("API_KEY") # BETTER - using SecretManager from src.secrets_manager import SecretManager manager = SecretManager() api_key = manager.get_secret("ANTHROPIC-API")Ensure .gitignore protects secrets:
# Add to .gitignore echo ".env*" >> .gitignore echo "*-key.json" >> .gitignore
Status: ⛔ COMMIT BLOCKED - Fix issues above before committing
**If no secrets found:**
```markdown
## ✅ Security Check Passed
**Summary:**
- Staged files scanned: 5
- Secret patterns checked: 10
- Sensitive files: 0
- Secrets found: 0
**Files scanned:**
- src/secrets_manager.py ✅
- tests/test_secrets_manager.py ✅
- CLAUDE.md ✅
- docs/changelog.md ✅
- .gitignore ✅
**Status:** Safe to commit ✅
Step 7: Provide Remediation Guidance
If secrets were found:
Immediate actions:
- Unstage the files:
git reset HEAD [file] - Remove secrets from code
- Use SecretManager or environment variables
- Unstage the files:
Long-term solution:
- Store secrets in GCP Secret Manager
- Access via
src/secrets_manager.py - Update .gitignore to prevent future leaks
If already committed (not pushed yet):
- Amend the commit:
git commit --amend - Or reset:
git reset HEAD~1
- Amend the commit:
If already pushed to remote:
- ⚠️ Secret is compromised - must rotate immediately
- Contact security team or repository owner
- Revoke the exposed credential
- Generate new secret
- Update in GCP Secret Manager
Never:
- Try to hide secrets with git rebase (history still exists)
- Assume deleting file in next commit is enough (history remains)
- Use git filter-branch without expert guidance
Constraints and Safety
DO NOT
- Never print or log secret values - only report that a secret was found
- Never suggest obfuscation - secrets must not be in code, period
- Never allow secrets in "temporary" commits - all commits are permanent
- Never trust filename patterns alone - always check content
- Never skip files - scan all staged files
ALWAYS
- Block commits with secrets - no exceptions
- Err on side of caution - false positive is better than false negative
- Provide clear remediation - explain how to fix the issue
- Check both filenames and contents - double validation
- Suggest using SecretManager - the approved solution
Critical Rules
This is a PUBLIC repository:
- Any secret committed is permanently exposed
- Even if deleted in next commit, it's in Git history
- Bots scan GitHub for leaked secrets within minutes
- Assume any leaked secret is compromised immediately
Zero tolerance:
- No "test" secrets in code
- No "old" secrets that are "already rotated"
- No "it's just for dev" exceptions
Examples
Example 1: Clean Commit
Trigger: User says "Check for secrets before commit"
Actions:
- ✅ Run
git diff --cached --name-only - ✅ Check filenames for sensitive patterns
- ✅ Run
git diff --cachedto get content - ✅ Scan content for secret patterns
- ✅ No secrets found
- ✅ Approve commit
Output:
## ✅ Security Check Passed
Staged files: 3 (src/module.py, tests/test_module.py, docs/api.md)
Secrets found: 0
Status: Safe to commit ✅
Example 2: API Key Detected
Trigger: User staging file with hardcoded API key
Actions:
- ✅ Run
git diff --cached - ✅ Detect pattern:
api_key = "sk-proj-abc123..." - ❌ BLOCK COMMIT
- ✅ Report finding with file and line
- ✅ Provide remediation steps
Output:
## 🚨 SECURITY ALERT: API Key Detected
File: src/config.py (Line 12)
Pattern: Anthropic API Key (sk-proj-...)
Risk: HIGH
Action Required:
1. Unstage: git reset HEAD src/config.py
2. Remove hardcoded key
3. Use SecretManager instead:
from src.secrets_manager import SecretManager
manager = SecretManager()
api_key = manager.get_secret("ANTHROPIC-API")
Status: ⛔ COMMIT BLOCKED
Example 3: .env File Attempted
Trigger: User tries to commit .env.local file
Actions:
- ✅ Run
git diff --cached --name-only - ✅ Detect
.env.localin staged files - ❌ BLOCK COMMIT immediately (before scanning content)
- ✅ Report forbidden file
- ✅ Suggest adding to .gitignore
Output:
## 🚨 SECURITY ALERT: Forbidden File
File: .env.local
Type: Environment file
Risk: CRITICAL
.env files must NEVER be committed to Git.
Action Required:
1. Unstage: git reset HEAD .env.local
2. Add to .gitignore:
echo ".env*" >> .gitignore
3. Verify: cat .gitignore | grep .env
Status: ⛔ COMMIT BLOCKED
Example 4: False Positive - Documentation
Trigger: User committing documentation with example API key
Actions:
- ✅ Run
git diff --cached - ✅ Detect pattern:
api_key = "sk-proj-example-..." - ✅ Read context - file is in docs/ directory
- ✅ Note keywords: "example", "placeholder"
- ✅ Determine: False positive - allow commit
- ✅ Approve with note
Output:
## ✅ Security Check Passed
Staged files: 1 (docs/api-guide.md)
Note: Found API key pattern but verified as documentation example
Status: Safe to commit ✅
Example 5: Test Fixture with Fake Secret
Trigger: User committing test fixture
Actions:
- ✅ Run
git diff --cached - ✅ Detect pattern:
FAKE_TOKEN = "sk-test-..." - ✅ Read context - file in tests/fixtures/
- ✅ Note marker:
FAKE_prefix, "not-real" comment - ✅ Determine: Test data - allow commit
- ✅ Approve with note
Output:
## ✅ Security Check Passed
Staged files: 1 (tests/fixtures/auth_data.py)
Note: Found token pattern but verified as test fixture
Status: Safe to commit ✅
Integration with CI
This skill is the first line of defense - CI is the second:
- Skill runs proactively before commit (local)
- CI can validate with tools like GitLeaks or TruffleHog (future)
- Together they create defense in depth
Workflow:
Developer stages changes
↓
security-checker skill activates
↓
Scan for secrets
↓
If secrets found → BLOCK (developer fixes)
If clean → Allow commit
↓
Push to GitHub
↓
(Future) GitLeaks in CI validates
↓
PR approved
Troubleshooting
Issue: Too many false positives
Symptom: Skill blocks legitimate commits (test data, docs examples)
Solution:
- Check if file is in tests/ or docs/ directory
- Look for keywords: "example", "test", "fake", "placeholder"
- Check for patterns like
FAKE_,TEST_,EXAMPLE_prefixes - Verify context (3-5 lines around match)
Issue: Missed a secret
Symptom: Secret committed but skill didn't catch it
Solution:
- Identify the pattern that was missed
- Add to secret patterns list in Step 3
- Update skill with new pattern
- Test with git diff simulation
Issue: Can't distinguish real vs fake
Symptom: Uncertain if detected pattern is real secret or test data
Solution: When in doubt, BLOCK.
- False positive is better than false negative
- Ask user to confirm if it's test data
- Suggest adding clear markers (FAKE_, TEST_, comments)
Issue: .gitignore not working
Symptom: Sensitive files still appearing in git status
Solution:
- Check .gitignore syntax:
cat .gitignore - Verify patterns match filenames
- If file already tracked, remove from Git:
git rm --cached [file] git commit -m "Remove tracked sensitive file" - Then .gitignore will work
Success Metrics
This skill is successful when:
- ✅ Zero secrets committed to repository
- ✅ Clear error messages when secrets detected
- ✅ Fast scanning (< 3 seconds for typical commits)
- ✅ Low false positive rate (< 5% of scans)
- ✅ Developers understand how to use SecretManager
- ✅ .gitignore properly configured and maintained
Red flags indicating skill needs improvement:
- ❌ Secret found in Git history (means skill was bypassed or failed)
- ❌ High false positive rate (developers frustrated)
- ❌ Unclear error messages (developers don't know how to fix)
- ❌ Slow scanning (> 10 seconds)
- ❌ Developers using
--no-verifyto bypass
Security Best Practices
For developers:
- Always use SecretManager for production secrets
- Use environment variables for local development
- Keep .env files local - never commit
- Review diffs before committing - git diff --cached
- Use this skill before every commit
For repository:
- Maintain .gitignore with all sensitive patterns
- Document secret management in SECURITY.md
- Rotate compromised secrets immediately
- Consider pre-commit hooks to enforce skill usage
- Regular security audits of Git history
If a secret is leaked:
- Assume it's compromised - act immediately
- Rotate the secret - generate new one
- Update in Secret Manager - not in code
- Notify team - if production secret
- Review .gitignore - prevent future leaks
Pattern Reference
Secret patterns matched (regex):
# AWS Keys
AKIA[0-9A-Z]{16}
# GitHub PAT
ghp_[a-zA-Z0-9]{36}
# Anthropic
sk-ant-api03-[a-zA-Z0-9_-]{95,}
# OpenAI
sk-proj-[a-zA-Z0-9_-]{48,}
# Generic API Key
api[_-]?key[\s]*[=:]['"]?[a-zA-Z0-9]{20,}
# JWT
eyJ[a-zA-Z0-9_-]*\.eyJ[a-zA-Z0-9_-]*\.[a-zA-Z0-9_-]*
# Private Key
-----BEGIN (RSA |EC |OPENSSH )?PRIVATE KEY-----
# DB URL with credentials
(postgres|mysql|mongodb):\/\/[^:]+:[^@]+@
# Password
password[\s]*[=:][\s]*['"][^'"]{8,}
File patterns to block:
*.env*
*credentials*.json
*-key.json
*_key.json
*.pem
*.p12
gcp-key.json
service-account*.json