Use 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 headers, validating input with Zod, and setting up JWT tokens. Invoke for authentication, authorization, input validation, encryption, OWASP Top 10 prevention, secure session management, and security hardening. For pre-built OAuth/SSO integrations or standalone security audits, consider a more specialized skill.
SKILL.md
Secure Code Guardian
Core Workflow
Threat model — Identify attack surface and threats
Design — Plan security controls
Implement — Write secure code with defense in depth; see code examples below
Validate — Test security controls with explicit checkpoints (see below)
Document — Record security decisions
Validation Checkpoints
After each implementation step, verify:
Authentication: Test brute-force protection (lockout/rate limit triggers), session fixation resistance, token expiration, and invalid-credential error messages (must not leak user existence).
Authorization: Verify horizontal and vertical privilege escalation paths are blocked; test with tokens belonging to different roles/users.
Input handling: Confirm SQL injection payloads (' OR 1=1--) are rejected; confirm XSS payloads (<script>alert(1)</script>) are escaped or rejected.
Headers/CORS: Validate with a security scanner (e.g., curl -I, Mozilla Observatory) that security headers are present and CORS origin allowlist is correct.
Reference Guide
Load detailed guidance based on context:
Topic
Reference
Load When
Installs
0
OWASP
references/owasp-prevention.md
OWASP Top 10 patterns
Authentication
references/authentication.md
Password hashing, JWT
Input Validation
references/input-validation.md
Zod, SQL injection
XSS/CSRF
references/xss-csrf.md
XSS prevention, CSRF
Headers
references/security-headers.md
Helmet, rate limiting
Constraints
MUST DO
Hash passwords with bcrypt/argon2 (never MD5/SHA-1/unsalted hashes)
Use parameterized queries (never string-interpolated SQL)
Store secrets in environment variables or secret managers (never in source code)
MUST NOT DO
Store passwords in plaintext or reversibly encrypted form
Trust user input without validation
Expose sensitive data in logs or error responses
Use weak or deprecated algorithms (MD5, SHA-1, DES, ECB mode)
Hardcode secrets or credentials in code
Code Examples
Password Hashing (bcrypt)
import bcrypt from 'bcrypt';
const SALT_ROUNDS = 12; // minimum 10; 12 balances security and performance
export async function hashPassword(plaintext: string): Promise<string> {
return bcrypt.hash(plaintext, SALT_ROUNDS);
}
export async function verifyPassword(plaintext: string, hash: string): Promise<boolean> {
return bcrypt.compare(plaintext, hash);
}
Parameterized SQL Query (Node.js / pg)
// NEVER: `SELECT * FROM users WHERE email = '${email}'`
// ALWAYS: use positional parameters
import { Pool } from 'pg';
const pool = new Pool();
export async function getUserByEmail(email: string) {
const { rows } = await pool.query(
'SELECT id, email, role FROM users WHERE email = $1',
[email] // value passed separately — never interpolated
);
return rows[0] ?? null;
}
Input Validation with Zod
import { z } from 'zod';
const LoginSchema = z.object({
email: z.string().email().max(254),
password: z.string().min(8).max(128),
});
export function validateLoginInput(raw: unknown) {
const result = LoginSchema.safeParse(raw);
if (!result.success) {
// Return generic error — never echo raw input back
throw new Error('Invalid credentials format');
}
return result.data;
}
JWT Validation
import jwt from 'jsonwebtoken';
const JWT_SECRET = process.env.JWT_SECRET!; // never hardcode
export function verifyToken(token: string): jwt.JwtPayload {
// Throws if expired, tampered, or wrong algorithm
const payload = jwt.verify(token, JWT_SECRET, {
algorithms: ['HS256'], // explicitly allowlist algorithm
issuer: 'your-app',
audience: 'your-app',
});
if (typeof payload === 'string') throw new Error('Invalid token payload');
return payload;
}