Install
npx skillscat add hitoshura25/claude-devtools/skills-security-check Install via the SkillsCat registry.
Security Check Skill
Run security scans on code changes and address all findings before marking work complete.
Purpose
Ensure code changes don't introduce security vulnerabilities. This is a mandatory quality gate - work is never complete with unaddressed critical/high security issues.
Prerequisites
- Security tools must be configured (use
security-setupskill if needed) - Semgrep and OSV-Scanner should be available
Scope of Responsibility
CRITICAL DISTINCTION: Modified Files vs Unchanged Files
Files You Modify
When you touch a file, you own ALL security issues in that file:
- ✓ CRITICAL/HIGH findings: MUST fix before merge, no exceptions
- ✓ MEDIUM findings: MUST fix OR create tracking issue with justification
- ✓ LOW findings: Fix if trivial, otherwise document
"Documentation" is NOT a substitute for fixing issues you can control.
Example:
You modify src/auth.ts to add a new function:
- File has pre-existing HIGH finding: SQL injection in another function
- YOU MUST FIX IT even though you didn't introduce it
- Rationale: You're already touching the file and ensuring it's secureFiles You Don't Touch
For files not in your changeset:
- CRITICAL/HIGH: Create tracking issue, not required to fix now
- MEDIUM/LOW: Acknowledge but not your responsibility
How to check:
# Files in your changeset
git diff --name-only main
# Only fix issues in these filesWhy This Matters
Bad practice:
✗ "I added authentication to auth.ts, but there's a pre-existing
SQL injection. I'll document it and move on."Good practice:
✓ "I'm modifying auth.ts, so I'm fixing ALL critical/high issues
in this file, including the pre-existing SQL injection."Process
1. Run Security Scans
Execute security tools appropriate for the project:
All Projects:
# Semgrep (static analysis)
semgrep --config=auto .
# OSV-Scanner (dependency vulnerabilities)
osv-scanner --recursive .TypeScript/JavaScript:
# npm audit (dependency check)
npm audit
# Or all at once
npm run security:scanPython:
# pip-audit (dependency vulnerabilities)
pip-audit
# bandit (code analysis)
bandit -r . -c .bandit
# safety (vulnerability database)
safety check
# Or unified script
./scripts/security-scan.shKotlin/Android:
# OWASP dependency check + Android lint
./gradlew securityScan
# Or individually
./gradlew dependencyCheckAnalyze
./gradlew lint2. Review Scan Results
Understand the security findings:
Example Semgrep Output:
Findings:
src/auth.ts
⚠️ Detected hardcoded JWT secret
> token = jwt.sign(payload, "my-secret-key-123")
Impact: Anyone who decompiles can extract the secret
Fix: Use environment variable: process.env.JWT_SECRET
src/api.ts
❌ SQL injection vulnerability
> db.query("SELECT * FROM users WHERE id = " + userId)
Impact: Attacker can execute arbitrary SQL
Fix: Use parameterized query: db.query("SELECT * FROM users WHERE id = ?", [userId])
2 findings: 1 error, 1 warningExample OSV-Scanner Output:
Scanning dir:
package-lock.json:
❌ axios@0.21.1 - CVE-2021-3749 (HIGH)
Fixed in: 0.21.2
Impact: Unsafe handling of special characters
⚠️ lodash@4.17.19 - CVE-2020-8203 (MODERATE)
Fixed in: 4.17.21
Impact: Prototype pollution
2 vulnerabilities found3. Triage Findings by Severity
Prioritize issues based on severity:
CRITICAL/HIGH - Must Fix:
- SQL injection, XSS, command injection
- Hardcoded secrets/credentials
- Authentication bypasses
- Remote code execution vulnerabilities
- Critical dependency vulnerabilities with exploits
MEDIUM - Should Fix (or Document Exception):
- Weak cryptography
- Information disclosure
- Moderate dependency vulnerabilities
- Security misconfigurations
LOW/INFO - Optional (Document if Deferred):
- Style and best practice suggestions
- Low-risk dependencies
- Informational findings
4. Fix Code Issues (Semgrep Findings)
Address static analysis findings:
Hardcoded Secrets:
// Before (CRITICAL)
const API_KEY = "sk_live_abc123xyz789";
const jwt = jwt.sign(payload, "my-secret-key");
// After (FIXED)
const API_KEY = process.env.API_KEY;
const jwt = jwt.sign(payload, process.env.JWT_SECRET);
// Add to .env.example (never commit .env)
// API_KEY=your_api_key_here
// JWT_SECRET=your_jwt_secret_hereSQL Injection:
// Before (CRITICAL)
const query = `SELECT * FROM users WHERE id = ${userId}`;
db.query(query);
// After (FIXED) - Use parameterized queries
const query = 'SELECT * FROM users WHERE id = ?';
db.query(query, [userId]);Path Traversal:
# Before (HIGH)
def read_file(filename):
return open(f"/data/{filename}").read()
# After (FIXED) - Validate and sanitize
import os
def read_file(filename):
# Prevent directory traversal
safe_path = os.path.normpath(os.path.join("/data", filename))
if not safe_path.startswith("/data/"):
raise ValueError("Invalid file path")
return open(safe_path).read()Insecure Randomness:
// Before (MEDIUM)
const token = Math.random().toString(36);
// After (FIXED) - Use crypto
const crypto = require('crypto');
const token = crypto.randomBytes(32).toString('hex');5. Fix Dependency Vulnerabilities
Address vulnerable dependencies:
Direct Dependencies (Preferred):
# TypeScript/JavaScript - Update to fixed version
npm update axios
npm audit fix
# Python - Update to fixed version
pip install --upgrade axios
pip-audit --fixTransitive Dependencies (Tricky):
# If vulnerability is in a dependency's dependency:
# Option 1: Update parent package
npm update parent-package
# Option 2: Use resolutions (package.json)
{
"resolutions": {
"lodash": "^4.17.21"
}
}
# Python: Use constraints
pip install "parent-package>=2.0" --constraint constraints.txtNo Fix Available:
If vulnerability has no patch yet:
- Check if you actually use the vulnerable code path
- Document the risk and monitoring plan
- Consider alternative packages
- Set up alerts for when patch is released
// .security-exceptions.json
{
"vulnerabilities": [
{
"package": "vulnerable-lib@1.0.0",
"cve": "CVE-2024-12345",
"reason": "We don't use the vulnerable function (parseUntrustedXML)",
"mitigation": "Code review confirmed safe usage",
"review_date": "2024-12-03",
"owner": "security-team"
}
]
}6. Re-Run Security Scans
After fixes, verify all issues are resolved:
# Run scans again
semgrep --config=auto .
osv-scanner --recursive .
npm audit # or appropriate commandExpected output:
✓ No security vulnerabilities foundOr with documented exceptions:
⚠️ 1 medium finding (documented exception)
✓ No critical or high findings7. Document Exceptions
For any security findings you can't fix immediately, document thoroughly:
Create issue in tracker:
# Security Finding: Lodash Prototype Pollution
**Severity:** Medium
**CVE:** CVE-2020-8203
**Package:** lodash@4.17.19 (transitive via webpack-dev-server)
**Risk Assessment:**
- Only used in dev dependencies
- Not exposed to production
- Vulnerability requires specific attack vector not present in our usage
**Mitigation:**
- Monitoring for lodash updates
- Dev environment is isolated
- Will upgrade with webpack-dev-server@5.0 (Q1 2025)
**Accept Risk:** ✓ (approved by security team)Add inline suppression with explanation:
// semgrep: disable=detect-dangerous-api-usage
// Risk accepted: This is admin-only endpoint with rate limiting
function dangerousAdminOperation() {
// ...
}Severity-Based Response
CRITICAL Findings
STOP WORK until resolved:
- Remote code execution
- Authentication bypass
- Hardcoded production secrets
Actions:
- Fix immediately
- Review all recent changes for similar issues
- Update security baseline
- Consider hotfix release if in production
HIGH Findings
Must fix before merge:
- SQL injection
- XSS vulnerabilities
- Insecure cryptography
- High-severity CVEs with exploits
Actions:
- Fix in current PR/branch
- Add tests to prevent regression
- Document what was vulnerable
MEDIUM Findings
Fix or document exception:
- Moderate CVEs
- Security misconfigurations
- Weak cryptography
Actions:
- Evaluate risk vs effort
- If deferring, create tracking issue
- Document mitigation strategy
LOW/INFO Findings
Optional - document if deferring:
- Best practice violations
- Low-risk dependencies
- Style recommendations
Actions:
- Fix if easy
- Otherwise, acknowledge and move on
Common Security Issues and Fixes
Secrets in Code
Detection:
# Semgrep detects
semgrep --config=p/secrets .Fix:
// Use environment variables
const apiKey = process.env.API_KEY;
// Use secret management
import { SecretManager } from '@google-cloud/secret-manager';
const secret = await secretManager.accessSecretVersion(secretName);Rotate compromised secrets:
- Generate new secret
- Update in secret manager
- Deploy with new secret
- Revoke old secret
Injection Vulnerabilities
SQL Injection:
# Use parameterized queries
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))Command Injection:
// Don't use shell interpolation
const { spawn } = require('child_process');
spawn('convert', ['-resize', '100x100', inputPath, outputPath]);LDAP Injection:
// Escape special characters
String safeUsername = LdapEncoder.filterEncode(username);Insecure Deserialization
# Don't use pickle with untrusted data
# Use JSON instead
import json
data = json.loads(untrusted_input)Weak Cryptography
// Use strong algorithms
const crypto = require('crypto');
// Bad: MD5, SHA1
// Good: SHA256, SHA512
const hash = crypto.createHash('sha256').update(data).digest('hex');
// Bad: DES, 3DES
// Good: AES-256
const cipher = crypto.createCipheriv('aes-256-gcm', key, iv);Output Confirmation
Before proceeding:
✓ Security scans completed
✓ No critical or high vulnerabilities in ANY file
✓ Medium findings in modified files: fixed OR tracked with issue
✓ Medium findings in other files: acknowledged/tracked
✓ Dependencies updated to secure versions
✓ Code changes reviewed for security issues
✓ Scope of changes clearly documented (files touched vs files untouched)Integration with CI/CD
Security checks should block merges:
GitHub Actions:
- name: Security Scan
run: |
semgrep --config=auto --error --severity=ERROR .
osv-scanner --recursive .
# Fails if critical/high issues foundFail Fast:
# Exit on first critical finding
semgrep --config=auto --error .NEVER Do These Things
Shortcuts that undermine security:
- ✗ NEVER say "I'll document this issue" to avoid fixing critical/high findings in files you modify
- ✗ NEVER disable security rules project-wide to make checks pass
- ✗ NEVER skip security scans because "it's just a small change"
- ✗ NEVER blame pre-existing issues for not fixing them in files you touch
- ✗ NEVER use "documentation" as blanket escape hatch for issues you can control
What TO do instead:
- ✓ Fix issues in files you modify (incremental improvement)
- ✓ Use inline suppressions sparingly with detailed justification
- ✓ All changes go through security scans (no exceptions for size)
- ✓ Take ownership: "I touched it, I ensure it's secure"
- ✓ Document exceptions with issue links + justification only when fix is impossible
Pre-Existing Issues: What to Fix
Common confusion: "I didn't introduce this issue, why should I fix it?"
The Rule
If you modify a file, you own its security posture.
Examples
Scenario 1: Adding feature to existing file
// You're adding a new function to auth.ts
// Semgrep reports: Existing function has hardcoded secret (HIGH)
❌ WRONG: "I didn't add that secret, I'll document it."
✅ RIGHT: "I'm touching this file, I'll fix the secret AND add my feature."Scenario 2: Bug fix in file with vulnerabilities
# You're fixing a bug in parser.py
# Semgrep reports: SQL injection in another function (CRITICAL)
❌ WRONG: "My bug fix doesn't touch that function, not my problem."
✅ RIGHT: "I'm modifying this file, I'll fix the SQL injection too."Scenario 3: Unrelated file has issues
# You modified auth.js
# Semgrep reports: XSS in admin.js (which you didn't touch)
✅ RIGHT: "Not in my changeset, I'll create a tracking issue but won't fix now."Why This Policy Exists
- Context is loaded: You're already reviewing/understanding the file
- Testing is active: You're running tests, can verify fixes
- Review is happening: PR reviewers can validate security improvements
- Incremental improvement: Each change makes codebase more secure
- Ownership culture: Encourages taking responsibility
CRITICAL RULE
NEVER merge code with unaddressed critical/high security issues IN FILES YOU MODIFY.
For files in your changeset:
- Fix ALL vulnerabilities (critical/high/medium)
- Update dependencies
- Only document if fix is genuinely impossible (rare)
- Re-run until clean
For files outside your changeset:
- Create tracking issues for critical/high findings
- Include in PR description: "Known issues in X, Y - see issues #123, #124"
- Don't block on these (but make them visible)
Never use "documentation" as excuse to skip fixing issues you can control.
But always end with acceptable security posture for files you modify.
Emergency Procedures
If production secret is leaked:
- Revoke/rotate immediately
- Audit access logs
- Check for unauthorized access
- Update all instances with new secret
- Post-mortem: How did it leak?
If critical CVE affects production:
- Assess if vulnerability is exploitable
- Apply patch immediately if available
- If no patch: Apply workaround or take offline
- Monitor for exploitation attempts
- Communicate with security team
Next Steps
After security checks pass:
- All quality gates complete (testing → linting → security)
- Code is ready for review/merge
- Consider additional security reviews for sensitive changes