$npx -y skills add Jeffallan/claude-skills --skill secure-code-guardianUse when implementing authentication/authorization, securing user input, or preventing OWASP Top 10 vulnerabilities — including custom security implementations such as hashing passwords with bcrypt/argon2, sanitizing SQL queries with parameterized statements, configuring CORS/CSP
| 1 | # Secure Code Guardian |
| 2 | |
| 3 | ## Core Workflow |
| 4 | |
| 5 | 1. **Threat model** — Identify attack surface and threats |
| 6 | 2. **Design** — Plan security controls |
| 7 | 3. **Implement** — Write secure code with defense in depth; see code examples below |
| 8 | 4. **Validate** — Test security controls with explicit checkpoints (see below) |
| 9 | 5. **Document** — Record security decisions |
| 10 | |
| 11 | ### Validation Checkpoints |
| 12 | |
| 13 | After each implementation step, verify: |
| 14 | |
| 15 | - **Authentication**: Test brute-force protection (lockout/rate limit triggers), session fixation resistance, token expiration, and invalid-credential error messages (must not leak user existence). |
| 16 | - **Authorization**: Verify horizontal and vertical privilege escalation paths are blocked; test with tokens belonging to different roles/users. |
| 17 | - **Input handling**: Confirm SQL injection payloads (`' OR 1=1--`) are rejected; confirm XSS payloads (`<script>alert(1)</script>`) are escaped or rejected. |
| 18 | - **Headers/CORS**: Validate with a security scanner (e.g., `curl -I`, Mozilla Observatory) that security headers are present and CORS origin allowlist is correct. |
| 19 | |
| 20 | ## Reference Guide |
| 21 | |
| 22 | Load detailed guidance based on context: |
| 23 | |
| 24 | | Topic | Reference | Load When | |
| 25 | |-------|-----------|-----------| |
| 26 | | OWASP | `references/owasp-prevention.md` | OWASP Top 10 patterns | |
| 27 | | Authentication | `references/authentication.md` | Password hashing, JWT | |
| 28 | | Input Validation | `references/input-validation.md` | Zod, SQL injection | |
| 29 | | XSS/CSRF | `references/xss-csrf.md` | XSS prevention, CSRF | |
| 30 | | Headers | `references/security-headers.md` | Helmet, rate limiting | |
| 31 | |
| 32 | ## Constraints |
| 33 | |
| 34 | ### MUST DO |
| 35 | - Hash passwords with bcrypt/argon2 (never MD5/SHA-1/unsalted hashes) |
| 36 | - Use parameterized queries (never string-interpolated SQL) |
| 37 | - Validate and sanitize all user input before use |
| 38 | - Implement rate limiting on auth endpoints |
| 39 | - Set security headers (CSP, HSTS, X-Frame-Options) |
| 40 | - Log security events (failed auth, privilege escalation attempts) |
| 41 | - Store secrets in environment variables or secret managers (never in source code) |
| 42 | |
| 43 | ### MUST NOT DO |
| 44 | - Store passwords in plaintext or reversibly encrypted form |
| 45 | - Trust user input without validation |
| 46 | - Expose sensitive data in logs or error responses |
| 47 | - Use weak or deprecated algorithms (MD5, SHA-1, DES, ECB mode) |
| 48 | - Hardcode secrets or credentials in code |
| 49 | |
| 50 | ## Code Examples |
| 51 | |
| 52 | ### Password Hashing (bcrypt) |
| 53 | |
| 54 | ```typescript |
| 55 | import bcrypt from 'bcrypt'; |
| 56 | |
| 57 | const SALT_ROUNDS = 12; // minimum 10; 12 balances security and performance |
| 58 | |
| 59 | export async function hashPassword(plaintext: string): Promise<string> { |
| 60 | return bcrypt.hash(plaintext, SALT_ROUNDS); |
| 61 | } |
| 62 | |
| 63 | export async function verifyPassword(plaintext: string, hash: string): Promise<boolean> { |
| 64 | return bcrypt.compare(plaintext, hash); |
| 65 | } |
| 66 | ``` |
| 67 | |
| 68 | ### Parameterized SQL Query (Node.js / pg) |
| 69 | |
| 70 | ```typescript |
| 71 | // NEVER: `SELECT * FROM users WHERE email = '${email}'` |
| 72 | // ALWAYS: use positional parameters |
| 73 | import { Pool } from 'pg'; |
| 74 | const pool = new Pool(); |
| 75 | |
| 76 | export async function getUserByEmail(email: string) { |
| 77 | const { rows } = await pool.query( |
| 78 | 'SELECT id, email, role FROM users WHERE email = $1', |
| 79 | [email] // value passed separately — never interpolated |
| 80 | ); |
| 81 | return rows[0] ?? null; |
| 82 | } |
| 83 | ``` |
| 84 | |
| 85 | ### Input Validation with Zod |
| 86 | |
| 87 | ```typescript |
| 88 | import { z } from 'zod'; |
| 89 | |
| 90 | const LoginSchema = z.object({ |
| 91 | email: z.string().email().max(254), |
| 92 | password: z.string().min(8).max(128), |
| 93 | }); |
| 94 | |
| 95 | export function validateLoginInput(raw: unknown) { |
| 96 | const result = LoginSchema.safeParse(raw); |
| 97 | if (!result.success) { |
| 98 | // Return generic error — never echo raw input back |
| 99 | throw new Error('Invalid credentials format'); |
| 100 | } |
| 101 | return result.data; |
| 102 | } |
| 103 | ``` |
| 104 | |
| 105 | ### JWT Validation |
| 106 | |
| 107 | ```typescript |
| 108 | import jwt from 'jsonwebtoken'; |
| 109 | |
| 110 | const JWT_SECRET = process.env.JWT_SECRET!; // never hardcode |
| 111 | |
| 112 | export function verifyToken(token: string): jwt.JwtPayload { |
| 113 | // Throws if expired, tampered, or wrong algorithm |
| 114 | const payload = jwt.verify(token, JWT_SECRET, { |
| 115 | algorithms: ['HS256'], // explicitly allowlist algorithm |
| 116 | is |