Security Review Skill
/SKILLThis skill ensures all code follows security best practices and identifies potential vulnerabilities.
--- name: security-review description: > Use this skill when adding authentication, handling user input, working with secrets, creating API endpoints, or implementing payment/sensitive features. Provides comprehensive security checklist and patterns. metadata: origin: ECC --- # Security Review Skill This skill ensures all code follows security best practices and identifies potential vulnerabilities. ## When to Activate - Implementing authentication or authorization - Handling user input or file uploads - Creating new API endpoints - Working with secrets or credentials - Implementing payment features - Storing or transmitting sensitive data - Integrating third-party APIs ## Security Checklist ### 1. Secrets Management #### FAIL: NEVER Do This ``typescript const apiKey = "sk-proj-xxxxx" // Hardcoded secret const dbPassword = "password123" // In source code ` #### PASS: ALWAYS Do This `typescript const apiKey = process.env.OPENAI_API_KEY const dbUrl = process.env.DATABASE_URL // Verify secrets exist if (!apiKey) { throw new Error('OPENAI_API_KEY not configured') } ` #### Verification Steps - [ ] No hardcoded API keys, tokens, or passwords - [ ] All secrets in environment variables - [ ] .env.local in .gitignore - [ ] No secrets in git history - [ ] Production secrets in hosting platform (Vercel, Railway) ### 2. Input Validation #### Always Validate User Input `typescript import { z } from 'zod' // Define validation schema const CreateUserSchema = z.object({ email: z.string().email(), name: z.string().min(1).max(100), age: z.number().int().min(0).max(150) }) // Validate before processing export async function createUser(input: unknown) { try { const validated = CreateUserSchema.parse(input) return await db.users.create(validated) } catch (error) { if (error instanceof z.ZodError) { return { success: false, errors: error.errors } } throw error } } ` #### File Upload Validation `typescript function validateFileUpload(file: File) { // Size check (5MB max) const maxSize = 5 * 1024 * 1024 if (file.size > maxSize) { throw new Error('File too large (max 5MB)') } // Type check const allowedTypes = ['image/jpeg', 'image/png', 'image/gif'] if (!allowedTypes.includes(file.type)) { throw new Error('Invalid file type') } // Extension check const allowedExtensions = ['.jpg', '.jpeg', '.png', '.gif'] const extension = file.name.toLowerCase().match(/\.[^.]+$/)?.[0] if (!extension || !allowedExtensions.includes(extension)) { throw new Error('Invalid file extension') } return true } ` #### Verification Steps - [ ] All user inputs validated with schemas - [ ] File uploads restricted (size, type, extension) - [ ] No direct use of user input in queries - [ ] Whitelist validation (not blacklist) - [ ] Error messages don't leak sensitive info ### 3. SQL Injection Prevention #### FAIL: NEVER Concatenate SQL `typescript // DANGEROUS - SQL Injection vulnerability const query = SELECT * FROM users WHERE email = '${userEmail}' await db.query(query) ` #### PASS: ALWAYS Use Parameterized Queries `typescript // Safe - parameterized query const { data } = await supabase .from('users') .select('*') .eq('email', userEmail) // Or with raw SQL await db.query( 'SELECT * FROM users WHERE email = $1', [userEmail] ) ` #### Verification Steps - [ ] All database queries use parameterized queries - [ ] No string concatenation in SQL - [ ] ORM/query builder used correctly - [ ] Supabase queries properly sanitized ### 4. Authentication & Authorization #### JWT Token Handling `typescript // FAIL: WRONG: localStorage (vulnerable to XSS) localStorage.setItem('token', token) // PASS: CORRECT: httpOnly cookies res.setHeader('Set-Cookie', token=${token}; HttpOnly; Secure; SameSite=Strict; Max-Age=3600) ` #### Authorization Checks `typescript export async function deleteUser(userId: string, requesterId: string) { // ALWAYS verify authorization first const requester = await db.users.findUnique({ where: { id: requesterId } }) if (requester.role !== 'admin') { return NextResponse.json( { error: 'Unauthorized' }, { status: 403 } ) } // Proceed with deletion await db.users.delete({ where: { id: userId } }) } ` #### Row Level Security (Supabase) `sql -- Enable RLS on all tables ALTER TABLE users ENABLE ROW LEVEL SECURITY; -- Users can only view their own data CREATE POLICY "Users view own data" ON users FOR SELECT USING (auth.uid() = id); -- Users can only update their own data CREATE POLICY "Users update own data" ON users FOR UPDATE USING (auth.uid() = id); `` #### Verification Steps - [ ] Tokens stored in httpOnly cookies (not localStorage) - [ ] Authorization checks before sensitive operations - [ ] Row Level Security enabled in Supabase - [ ] Role-based access control implemented - [ ] Session management secure ### 5. XSS Prevention #### Sanitize H