2026-02-15 14:28:33 -08:00
|
|
|
# Security Checklist
|
|
|
|
|
|
|
|
|
|
Quick reference for web application security. Use alongside the `security-and-hardening` skill.
|
|
|
|
|
|
2026-03-31 22:41:45 +02:00
|
|
|
## Table of Contents
|
|
|
|
|
|
2026-06-05 21:57:15 -07:00
|
|
|
- [Threat Modeling (Start Here)](#threat-modeling-start-here)
|
2026-03-31 22:41:45 +02:00
|
|
|
- [Pre-Commit Checks](#pre-commit-checks)
|
|
|
|
|
- [Authentication](#authentication)
|
|
|
|
|
- [Authorization](#authorization)
|
|
|
|
|
- [Input Validation](#input-validation)
|
|
|
|
|
- [Security Headers](#security-headers)
|
|
|
|
|
- [CORS Configuration](#cors-configuration)
|
|
|
|
|
- [Data Protection](#data-protection)
|
|
|
|
|
- [Dependency Security](#dependency-security)
|
2026-06-05 21:57:15 -07:00
|
|
|
- [AI / LLM Security](#ai--llm-security)
|
2026-03-31 22:41:45 +02:00
|
|
|
- [Error Handling](#error-handling)
|
|
|
|
|
- [OWASP Top 10 Quick Reference](#owasp-top-10-quick-reference)
|
2026-06-05 21:57:15 -07:00
|
|
|
- [OWASP Top 10 for LLMs Quick Reference](#owasp-top-10-for-llms-quick-reference)
|
|
|
|
|
|
|
|
|
|
## Threat Modeling (Start Here)
|
|
|
|
|
|
|
|
|
|
Before reaching for controls, spend five minutes thinking like an attacker:
|
|
|
|
|
|
|
|
|
|
- [ ] Trust boundaries mapped (requests, uploads, webhooks, third-party APIs, LLM output)
|
|
|
|
|
- [ ] Assets named (credentials, PII, payment data, admin actions, money movement)
|
|
|
|
|
- [ ] STRIDE run per boundary (Spoofing, Tampering, Repudiation, Info disclosure, DoS, Elevation)
|
|
|
|
|
- [ ] Abuse cases written next to use cases ("how would I misuse this?")
|
2026-03-31 22:41:45 +02:00
|
|
|
|
2026-02-15 14:28:33 -08:00
|
|
|
## Pre-Commit Checks
|
|
|
|
|
|
|
|
|
|
- [ ] No secrets in code (`git diff --cached | grep -i "password\|secret\|api_key\|token"`)
|
|
|
|
|
- [ ] `.gitignore` covers: `.env`, `.env.local`, `*.pem`, `*.key`
|
|
|
|
|
- [ ] `.env.example` uses placeholder values (not real secrets)
|
|
|
|
|
|
|
|
|
|
## Authentication
|
|
|
|
|
|
|
|
|
|
- [ ] Passwords hashed with bcrypt (≥12 rounds), scrypt, or argon2
|
|
|
|
|
- [ ] Session cookies: `httpOnly`, `secure`, `sameSite: 'lax'`
|
|
|
|
|
- [ ] Session expiration configured (reasonable max-age)
|
|
|
|
|
- [ ] Rate limiting on login endpoint (≤10 attempts per 15 minutes)
|
|
|
|
|
- [ ] Password reset tokens: time-limited (≤1 hour), single-use
|
|
|
|
|
- [ ] Account lockout after repeated failures (optional, with notification)
|
|
|
|
|
- [ ] MFA supported for sensitive operations (optional but recommended)
|
|
|
|
|
|
|
|
|
|
## Authorization
|
|
|
|
|
|
|
|
|
|
- [ ] Every protected endpoint checks authentication
|
|
|
|
|
- [ ] Every resource access checks ownership/role (prevents IDOR)
|
|
|
|
|
- [ ] Admin endpoints require admin role verification
|
|
|
|
|
- [ ] API keys scoped to minimum necessary permissions
|
|
|
|
|
- [ ] JWT tokens validated (signature, expiration, issuer)
|
|
|
|
|
|
|
|
|
|
## Input Validation
|
|
|
|
|
|
|
|
|
|
- [ ] All user input validated at system boundaries (API routes, form handlers)
|
|
|
|
|
- [ ] Validation uses allowlists (not denylists)
|
|
|
|
|
- [ ] String lengths constrained (min/max)
|
|
|
|
|
- [ ] Numeric ranges validated
|
|
|
|
|
- [ ] Email, URL, and date formats validated with proper libraries
|
|
|
|
|
- [ ] File uploads: type restricted, size limited, content verified
|
|
|
|
|
- [ ] SQL queries parameterized (no string concatenation)
|
|
|
|
|
- [ ] HTML output encoded (use framework auto-escaping)
|
|
|
|
|
- [ ] URLs validated before redirect (prevent open redirect)
|
2026-06-05 21:57:15 -07:00
|
|
|
- [ ] Server-side URL fetches allowlisted; private/reserved IPs blocked (prevent SSRF)
|
2026-02-15 14:28:33 -08:00
|
|
|
|
|
|
|
|
## Security Headers
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
Content-Security-Policy: default-src 'self'; script-src 'self'
|
|
|
|
|
Strict-Transport-Security: max-age=31536000; includeSubDomains
|
|
|
|
|
X-Content-Type-Options: nosniff
|
|
|
|
|
X-Frame-Options: DENY
|
|
|
|
|
X-XSS-Protection: 0 (disabled, rely on CSP)
|
|
|
|
|
Referrer-Policy: strict-origin-when-cross-origin
|
|
|
|
|
Permissions-Policy: camera=(), microphone=(), geolocation=()
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## CORS Configuration
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
// Restrictive (recommended)
|
|
|
|
|
cors({
|
|
|
|
|
origin: ['https://yourdomain.com', 'https://app.yourdomain.com'],
|
|
|
|
|
credentials: true,
|
|
|
|
|
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
|
|
|
|
|
allowedHeaders: ['Content-Type', 'Authorization'],
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// NEVER use in production:
|
|
|
|
|
cors({ origin: '*' }) // Allows any origin
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## Data Protection
|
|
|
|
|
|
|
|
|
|
- [ ] Sensitive fields excluded from API responses (`passwordHash`, `resetToken`, etc.)
|
|
|
|
|
- [ ] Sensitive data not logged (passwords, tokens, full CC numbers)
|
|
|
|
|
- [ ] PII encrypted at rest (if required by regulation)
|
|
|
|
|
- [ ] HTTPS for all external communication
|
|
|
|
|
- [ ] Database backups encrypted
|
|
|
|
|
|
|
|
|
|
## Dependency Security
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
# Audit dependencies
|
|
|
|
|
npm audit
|
|
|
|
|
|
|
|
|
|
# Fix automatically where possible
|
|
|
|
|
npm audit fix
|
|
|
|
|
|
|
|
|
|
# Check for critical vulnerabilities
|
|
|
|
|
npm audit --audit-level=critical
|
|
|
|
|
|
|
|
|
|
# Keep dependencies updated
|
|
|
|
|
npx npm-check-updates
|
|
|
|
|
```
|
|
|
|
|
|
2026-06-05 21:57:15 -07:00
|
|
|
**Supply-chain hygiene** (`npm audit` won't catch malicious packages):
|
|
|
|
|
- [ ] Lockfile committed; CI installs with `npm ci` (not `npm install`)
|
|
|
|
|
- [ ] New dependencies reviewed (maintenance, downloads, `postinstall` scripts)
|
|
|
|
|
- [ ] No typosquats (`cross-env` vs `crossenv`, `react-dom` vs `reactdom`)
|
|
|
|
|
|
|
|
|
|
## AI / LLM Security
|
|
|
|
|
|
|
|
|
|
For any feature that calls an LLM (chatbots, summarizers, agents, RAG):
|
|
|
|
|
|
|
|
|
|
- [ ] Model output treated as untrusted — never into `eval`/SQL/shell/`innerHTML`/file paths
|
|
|
|
|
- [ ] Prompt injection assumed; permissions enforced in code, not in the system prompt
|
|
|
|
|
- [ ] Secrets, cross-tenant data, and full system prompts kept out of the context window
|
|
|
|
|
- [ ] Tool/agent permissions scoped; destructive or irreversible actions require confirmation
|
|
|
|
|
- [ ] Token, rate, and recursion/loop limits set (bound consumption)
|
|
|
|
|
|
2026-02-15 14:28:33 -08:00
|
|
|
## Error Handling
|
|
|
|
|
|
|
|
|
|
```typescript
|
|
|
|
|
// Production: generic error, no internals
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
error: { code: 'INTERNAL_ERROR', message: 'Something went wrong' }
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// NEVER in production:
|
|
|
|
|
res.status(500).json({
|
|
|
|
|
error: err.message,
|
|
|
|
|
stack: err.stack, // Exposes internals
|
|
|
|
|
query: err.sql, // Exposes database details
|
|
|
|
|
});
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
## OWASP Top 10 Quick Reference
|
|
|
|
|
|
|
|
|
|
| # | Vulnerability | Prevention |
|
|
|
|
|
|---|---|---|
|
|
|
|
|
| 1 | Broken Access Control | Auth checks on every endpoint, ownership verification |
|
|
|
|
|
| 2 | Cryptographic Failures | HTTPS, strong hashing, no secrets in code |
|
|
|
|
|
| 3 | Injection | Parameterized queries, input validation |
|
|
|
|
|
| 4 | Insecure Design | Threat modeling, spec-driven development |
|
|
|
|
|
| 5 | Security Misconfiguration | Security headers, minimal permissions, audit deps |
|
|
|
|
|
| 6 | Vulnerable Components | `npm audit`, keep deps updated, minimal deps |
|
|
|
|
|
| 7 | Auth Failures | Strong passwords, rate limiting, session management |
|
|
|
|
|
| 8 | Data Integrity Failures | Verify updates/dependencies, signed artifacts |
|
|
|
|
|
| 9 | Logging Failures | Log security events, don't log secrets |
|
|
|
|
|
| 10 | SSRF | Validate/allowlist URLs, restrict outbound requests |
|
2026-06-05 21:57:15 -07:00
|
|
|
|
|
|
|
|
## OWASP Top 10 for LLMs Quick Reference
|
|
|
|
|
|
|
|
|
|
For apps with LLM features. See the [OWASP GenAI Security Project](https://genai.owasp.org/llm-top-10/).
|
|
|
|
|
|
|
|
|
|
| ID | Risk | Prevention |
|
|
|
|
|
|---|---|---|
|
|
|
|
|
| LLM01 | Prompt Injection | Don't trust the system prompt as a boundary; enforce permissions in code |
|
|
|
|
|
| LLM02 | Sensitive Information Disclosure | Keep secrets/PII out of prompts; filter outputs |
|
|
|
|
|
| LLM03 | Supply Chain | Vet models, datasets, and plugins like any dependency |
|
2026-06-07 15:26:33 -07:00
|
|
|
| LLM04 | Data and Model Poisoning | Use trusted model sources, verify integrity; vet fine-tuning and RAG data |
|
2026-06-05 21:57:15 -07:00
|
|
|
| LLM05 | Improper Output Handling | Treat model output as untrusted; validate, parameterize, encode |
|
|
|
|
|
| LLM06 | Excessive Agency | Scope tool permissions; confirm destructive actions |
|
|
|
|
|
| LLM07 | System Prompt Leakage | Assume the system prompt can leak; put no secrets in it |
|
2026-06-07 11:36:31 -07:00
|
|
|
| LLM08 | Vector and Embedding Weaknesses | Partition RAG embeddings per tenant; validate documents before indexing |
|
2026-06-07 15:26:33 -07:00
|
|
|
| LLM09 | Misinformation | Ground answers with citations; validate critical claims; keep a human in the loop |
|
2026-06-05 21:57:15 -07:00
|
|
|
| LLM10 | Unbounded Consumption | Cap tokens, request rate, and loop/recursion depth |
|