Overview
Security is not a feature you add — it is a property you maintain. Most security failures are not sophisticated attacks; they are missing input validation, exposed secrets, misconfigured permissions, and unpatched dependencies. This skill systematically eliminates these before they reach production.
When to Use
- Before merging any PR that touches auth, data storage, user input, or external APIs
- When adding a new endpoint, form, or data type
- When setting up or modifying infrastructure
- As part of the
/review workflow
Process
Step 1: Threat model the change
Ask: what can an attacker do with this change? What data does it touch? What systems does it connect to? Who has access? Threat model in 10 minutes with STRIDE:
- Spoofing — Can someone impersonate a legitimate user?
- Tampering — Can someone modify data they shouldn't?
- Repudiation — Can someone deny they took an action?
- Information Disclosure — Can someone read data they shouldn't?
- Denial of Service — Can someone block legitimate access?
- Elevation of Privilege — Can someone gain permissions they shouldn't have?
Step 2: Input validation
- Validate all inputs at the boundary (before processing or storage)
- Validate type, length, format, and range
- Reject invalid inputs — don't sanitize and continue
- Parameterize all database queries (no string concatenation)
- Encode all outputs for their context (HTML, SQL, shell, JSON)
Step 3: Authentication and authorization
- Verify authentication on every request (don't cache auth state across requests)
- Check authorization on every resource access (not just at the route level)
- Use principle of least privilege: request only the permissions you need
- Implement rate limiting on auth endpoints
- Ensure session tokens are invalidated on logout
Step 4: Secrets management
- No secrets in code, commits, or logs
- Use environment variables or a secrets manager
- Rotate secrets after any exposure (assume exposure if committed to git)
- Verify:
git log --all -p | grep -i "password\|secret\|token\|key" — if anything shows, rotate immediately
Step 5: Dependency audit
- Run
npm audit, pip-audit, or equivalent
- Address all high/critical CVEs before merging
- Pin dependency versions; use lock files
- Review new dependencies before adding them
Step 6: Data handling
- Encrypt sensitive data at rest and in transit
- Never log PII, passwords, tokens, or credit card numbers
- Apply data minimization: only collect what you need
- Implement proper deletion (GDPR right-to-erasure)
- Separate authentication tokens from data queries in logs
Step 7: Error handling
- Never expose stack traces or internal details to users
- Log errors server-side with context; return generic messages to clients
- Don't reveal whether a user exists on login failure ("Invalid credentials" not "User not found")
Step 8: Headers and transport
- Set security headers: CSP, HSTS, X-Frame-Options, X-Content-Type-Options
- TLS everywhere; no HTTP
- No sensitive data in URLs or query parameters
Anti-Rationalizations
"This is an internal API — we don't need auth"
Internal APIs are reached by internal attackers and misconfigured external clients. Every API needs auth.
"We'll add security hardening after launch"
Security retrofitted onto an insecure design is more expensive and less effective than security built in from the start.
"The secret is only in the git history, not the current code"
Git history is accessible to everyone who can clone the repo. Rotate the secret now.
Verification Requirements
1---2name: security-and-hardening3description: Apply security controls, threat modeling, and hardening to code and infrastructure4---56## Overview78Security is not a feature you add — it is a property you maintain. Most security failures are not sophisticated attacks; they are missing input validation, exposed secrets, misconfigured permissions, and unpatched dependencies. This skill systematically eliminates these before they reach production.910## When to Use1112- Before merging any PR that touches auth, data storage, user input, or external APIs13- When adding a new endpoint, form, or data type14- When setting up or modifying infrastructure15- As part of the `/review` workflow1617## Process1819### Step 1: Threat model the change20Ask: what can an attacker do with this change? What data does it touch? What systems does it connect to? Who has access? Threat model in 10 minutes with STRIDE:21- **S**poofing — Can someone impersonate a legitimate user?22- **T**ampering — Can someone modify data they shouldn't?23- **R**epudiation — Can someone deny they took an action?24- **I**nformation Disclosure — Can someone read data they shouldn't?25- **D**enial of Service — Can someone block legitimate access?26- **E**levation of Privilege — Can someone gain permissions they shouldn't have?2728### Step 2: Input validation29- Validate all inputs at the boundary (before processing or storage)30- Validate type, length, format, and range31- Reject invalid inputs — don't sanitize and continue32- Parameterize all database queries (no string concatenation)33- Encode all outputs for their context (HTML, SQL, shell, JSON)3435### Step 3: Authentication and authorization36- Verify authentication on every request (don't cache auth state across requests)37- Check authorization on every resource access (not just at the route level)38- Use principle of least privilege: request only the permissions you need39- Implement rate limiting on auth endpoints40- Ensure session tokens are invalidated on logout4142### Step 4: Secrets management43- No secrets in code, commits, or logs44- Use environment variables or a secrets manager45- Rotate secrets after any exposure (assume exposure if committed to git)46- Verify: `git log --all -p | grep -i "password\|secret\|token\|key"` — if anything shows, rotate immediately4748### Step 5: Dependency audit49- Run `npm audit`, `pip-audit`, or equivalent50- Address all high/critical CVEs before merging51- Pin dependency versions; use lock files52- Review new dependencies before adding them5354### Step 6: Data handling55- Encrypt sensitive data at rest and in transit56- Never log PII, passwords, tokens, or credit card numbers57- Apply data minimization: only collect what you need58- Implement proper deletion (GDPR right-to-erasure)59- Separate authentication tokens from data queries in logs6061### Step 7: Error handling62- Never expose stack traces or internal details to users63- Log errors server-side with context; return generic messages to clients64- Don't reveal whether a user exists on login failure ("Invalid credentials" not "User not found")6566### Step 8: Headers and transport67- Set security headers: CSP, HSTS, X-Frame-Options, X-Content-Type-Options68- TLS everywhere; no HTTP69- No sensitive data in URLs or query parameters7071## Anti-Rationalizations7273**"This is an internal API — we don't need auth"**74Internal APIs are reached by internal attackers and misconfigured external clients. Every API needs auth.7576**"We'll add security hardening after launch"**77Security retrofitted onto an insecure design is more expensive and less effective than security built in from the start.7879**"The secret is only in the git history, not the current code"**80Git history is accessible to everyone who can clone the repo. Rotate the secret now.8182## Verification Requirements8384- [ ] STRIDE threat model completed for the change85- [ ] All user inputs validated at the boundary86- [ ] All database queries parameterized87- [ ] No secrets in code or commit history88- [ ] Authorization checked on every resource access89- [ ] Dependency audit passed (no high/critical CVEs)90- [ ] No PII in logs91- [ ] Security headers configured92- [ ] Error messages don't expose internals