Repository Security Scan
Scans the current repository for sensitive information, credentials, and security vulnerabilities. Produces a report and actionable remediation plan.
Invocation
/repo-security-scan # Scan current files only (fast)
/repo-security-scan --history # Include git history (slower)
"scan this repo for security issues"
"check for sensitive data"
"scan history for secrets" # Triggers history scan
"deep security scan" # Triggers history scan
"security audit"
History scanning is opt-in because it's slower. Prompt the user if not specified:
Would you like to scan git history as well?
This finds secrets that were removed but are still in commit history.
(Slower - may take a few minutes on large repos)
Workflow
Step 1: Prepare Output Directory
mkdir -p security
Generate filename with today's date:
security/YYYYMMDD-scan.md
Step 2: Gather Repository Context
# Get repo root
git rev-parse --show-toplevel
# List tracked files (excluding common binary/vendor paths)
git ls-files | grep -v -E '\.(png|jpg|gif|ico|woff|ttf|pdf)$'
# Check .gitignore exists
cat .gitignore 2>/dev/null
Step 3: Scan for Sensitive Information
Search for patterns that indicate secrets or credentials:
High Priority - Hardcoded Secrets
| Pattern | Description |
|---|---|
password\s*[:=]\s*['"][^'"]+['"] | Hardcoded passwords |
api[_-]?key\s*[:=]\s*['"][^'"]+['"] | API keys |
secret[_-]?key\s*[:=]\s*['"][^'"]+['"] | Secret keys |
(aws_)?access[_-]?key[_-]?id\s*[:=] | AWS access keys |
(aws_)?secret[_-]?access[_-]?key\s*[:=] | AWS secret keys |
private[_-]?key | Private keys |
| `-----BEGIN (RSA | DSA |
Bearer\s+[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+ | JWT tokens |
ghp_[A-Za-z0-9]{36} | GitHub personal access tokens |
sk-[A-Za-z0-9]{48} | OpenAI API keys |
xox[baprs]-[A-Za-z0-9-]+ | Slack tokens |
Medium Priority - Potential Secrets
| Pattern | Description |
|---|---|
[A-Za-z0-9]{32,} in config files | Long alphanumeric strings (potential tokens) |
DATABASE_URL.*://.*:.*@ | Database connection strings with credentials |
mongodb(\+srv)?://[^/\s]+:[^/\s]+@ | MongoDB connection strings |
redis://:[^@]+@ | Redis connection strings |
smtp://[^:]+:[^@]+@ | SMTP credentials |
Low Priority - Review Recommended
| Pattern | Description |
|---|---|
.env files tracked in git | Environment files should be gitignored |
TODO.*secret|password|key | TODOs mentioning secrets |
localhost with port in configs | Development URLs in production configs |
Step 4: Scan for Security Vulnerabilities
Code Patterns (by language)
Ruby/Rails:
| Pattern | Risk | Description |
|---|---|---|
eval\( | High | Arbitrary code execution |
send\(params | High | Dynamic method calls with user input |
raw\s+params | High | Unescaped user input in views |
html_safe on user input | Medium | XSS vulnerability |
where\(".*#\{ | Medium | SQL injection risk |
render\s+inline: | Medium | Template injection |
system\(.*params | High | Command injection |
open\(.*params | High | Path traversal |
JavaScript/TypeScript:
| Pattern | Risk | Description |
|---|---|---|
eval\( | High | Arbitrary code execution |
innerHTML\s*= | Medium | XSS if user input |
dangerouslySetInnerHTML | Medium | React XSS risk |
child_process.exec\( with user input | High | Command injection |
new Function\( | High | Dynamic code execution |
Python:
| Pattern | Risk | Description |
|---|---|---|
eval\( | High | Arbitrary code execution |
exec\( | High | Arbitrary code execution |
pickle\.loads?\( | High | Insecure deserialisation |
subprocess.*shell=True | Medium | Shell injection risk |
__import__\( with user input | High | Module injection |
SQL:
| Pattern | Risk | Description |
|---|---|---|
| String concatenation in queries | High | SQL injection |
EXECUTE\s+@ | Medium | Dynamic SQL |
Step 5: Check Configuration Security
| Check | Risk | Description |
|---|---|---|
| Debug mode enabled in production configs | Medium | Information disclosure |
CORS * wildcard | Medium | Overly permissive CORS |
| Missing CSRF protection | High | Cross-site request forgery |
| Weak SSL/TLS configuration | Medium | Man-in-the-middle risk |
| Default credentials in configs | High | Authentication bypass |
Step 6: Check for Sensitive Files
Files that should typically be gitignored:
| File Pattern | Risk |
|---|---|
.env, .env.* | High - Contains secrets |
*.pem, *.key | High - Private keys |
*credentials*.json | High - Cloud credentials |
*.p12, *.pfx | High - Certificates with keys |
id_rsa, id_ed25519 | High - SSH private keys |
.docker/config.json | Medium - Docker registry auth |
*.sqlite, *.db | Medium - May contain sensitive data |
config/master.key | High - Rails credentials key |
config/credentials.yml.enc without master.key | OK - Encrypted |
Step 7: Scan Git History (if requested)
If user requested history scanning (--history or confirmed prompt), scan commit history for secrets.
Option A: Use gitleaks (preferred)
Check if gitleaks is installed:
gitleaks version 2>/dev/null
If installed, run comprehensive scan:
# Scan all commits
gitleaks detect --source . --log-opts="--all" --report-format json --report-path /tmp/gitleaks-report.json
# Parse results
cat /tmp/gitleaks-report.json
Gitleaks output includes:
- Secret type (API key, password, etc.)
- File path
- Commit hash where introduced
- Line number
- Whether still present or removed
Option B: Use trufflehog (alternative)
trufflehog version 2>/dev/null
If installed:
trufflehog git file://. --only-verified --json
Option C: Native git search (fallback)
If no dedicated tools installed, use git directly (slower, less comprehensive):
# Search for high-priority patterns in all commit diffs
git log -p --all -S 'password' --pickaxe-regex -S '["\x27]sk-[A-Za-z0-9]{20,}["\x27]' 2>/dev/null | head -500
# Search for specific patterns
git log -p --all | grep -E "(api[_-]?key|secret[_-]?key|password)\s*[:=]\s*['\"][^'\"]{8,}['\"]" | head -100
# Find commits that touched sensitive files
git log --all --full-history --source -- "*.pem" "*.key" ".env" "*credentials*" "*.p12"
# Check for secrets in deleted files
git log --diff-filter=D --summary --all | grep -E "\.(pem|key|env)$"
Categorise History Findings
Label each finding by location:
| Location | Meaning | Risk |
|---|---|---|
| Current | In current files | High - actively exposed |
| History | Removed from files but in git history | High - still accessible |
| History-only | Never in current files (deleted file) | Medium - requires history access |
Example output:
[H3] AWS Secret Key (HISTORY)
- **Commit:** abc1234 (2024-03-15)
- **File:** config/aws.yml (since removed)
- **Status:** Removed from current files, but remains in git history
- **Risk:** Anyone with repo access can retrieve this from history
- **Recommendation:** Use /repo-security-purge to remove from history, rotate credential
Step 8: Generate Report
Write findings to security/YYYYMMDD-scan.md:
# Security Scan Report
**Repository:** <repo-name>
**Date:** YYYY-MM-DD
**Scanned by:** Claude Code
**History scanned:** Yes/No
## Summary
| Priority | Current | History | Total |
|----------|---------|---------|-------|
| High | X | X | X |
| Medium | X | X | X |
| Low | X | X | X |
## Current File Findings
### High Priority
#### [H1] Hardcoded API Key
- **Location:** Current
- **File:** `config/services.rb:42`
- **Pattern:** `api_key = "sk-..."`
- **Risk:** API key exposed in version control
- **Recommendation:** Move to environment variable or encrypted credentials
### Medium Priority
#### [M1] Potential SQL Injection
- **Location:** Current
- **File:** `app/models/user.rb:87`
- **Pattern:** `where("name = '#{params[:name]}'")`
- **Risk:** User input interpolated into SQL query
- **Recommendation:** Use parameterised queries: `where(name: params[:name])`
## Git History Findings
### High Priority
#### [H2] AWS Secret Access Key (HISTORY)
- **Location:** History (removed from current files)
- **Commit:** `abc1234` (2024-03-15, "Add AWS config")
- **File:** `config/aws.yml` (deleted in `def5678`)
- **Risk:** Credential accessible to anyone with repo access via git history
- **Recommendation:**
1. Rotate this AWS credential immediately
2. Use `/repo-security-purge` to remove from history
#### [H3] Private Key File (HISTORY)
- **Location:** History
- **Commit:** `ghi9012` (2024-01-10)
- **File:** `certs/server.key` (still tracked)
- **Risk:** Private key in version control history
- **Recommendation:**
1. Revoke and regenerate certificate
2. Use `/repo-security-purge` to remove from history
### Low Priority
#### [L1] Development URL in Config
- **Location:** Current
- **File:** `config/settings.yml:12`
- **Pattern:** `api_url: http://localhost:3000`
- **Risk:** Development configuration may be deployed
- **Recommendation:** Use environment-specific configuration
## Scan Details
| Metric | Value |
|--------|-------|
| Current files scanned | X |
| Commits scanned | X (if history enabled) |
| File types | .rb, .js, .py, .yml, .json, ... |
| Scan tool | gitleaks / trufflehog / native git |
## Scan Limitations
- This scan uses pattern matching and may produce false positives
- Manual review recommended for all findings
- Does not scan binary files or dependencies
- History scan may miss secrets in squashed/rebased commits
Step 9: Create Remediation Plan
For issues Medium priority and above, create an actionable plan:
## Remediation Plan
### Immediate Actions (High Priority)
1. **[H1] Remove hardcoded API key** (Current)
- [ ] Add `API_KEY` to `.env` (gitignored)
- [ ] Update `config/services.rb` to read from `ENV['API_KEY']`
- [ ] Rotate the exposed key in the provider dashboard
2. **[H2] AWS credential in history** (History)
- [ ] Rotate AWS credential immediately
- [ ] Run `/repo-security-purge` to remove from git history
- [ ] Verify removal with `/repo-security-scan --history`
### Short-term Actions (Medium Priority)
3. **[M1] Fix SQL injection vulnerability**
- [ ] Refactor to use parameterised queries
- [ ] Add test case for SQL injection attempt
- [ ] Review similar patterns in codebase
### Recommended Improvements
- [ ] Add `gitleaks` or `trufflehog` to CI pipeline
- [ ] Enable GitHub secret scanning
- [ ] Review and update `.gitignore`
- [ ] Set up pre-commit hooks to prevent secret commits
Step 10: Report Results
✓ Security scan complete
Report: security/YYYYMMDD-scan.md
Current files:
High: 1 issue
Medium: 2 issues
Low: 3 issues
Git history: (if scanned)
High: 2 issues
Medium: 0 issues
Total: 8 issues (3 require immediate action)
Remediation plan included for 5 actionable items.
Next steps:
1. Review the full report
2. Address High priority issues immediately
3. Run /repo-security-clean to fix current file issues
4. Run /repo-security-purge to remove secrets from history
Excluding False Positives
If the repo has a security/.scanignore file, respect it:
# Patterns to ignore (one per line)
# Comments start with #
test/fixtures/fake_credentials.yml
docs/examples/
*.test.js
Notes
- This scan uses pattern matching and may produce false positives
- Always manually verify findings before taking action
- History scanning uses gitleaks/trufflehog if installed, falls back to native git
- Secrets in history are just as dangerous as current secrets — assume compromised
- After fixing, use
/repo-security-cleanfor current files,/repo-security-purgefor history - Consider adding gitleaks to CI pipeline to prevent future secret commits
