🎯

security-review

🎯Skill

from mhylle/claude-skills-collection

VibeIndex|
What it does

Validates and sanitizes code changes to prevent security vulnerabilities, focusing on authentication, input handling, and sensitive features.

πŸ“¦

Part of

mhylle/claude-skills-collection(18 items)

security-review

Installation

Shell ScriptRun shell script
./install.sh
Shell ScriptRun shell script
./init-workflow.sh ~/projects/myapp # Standard level (recommended)
Shell ScriptRun shell script
./init-workflow.sh ~/projects/myapp minimal # Lightweight reminder
Shell ScriptRun shell script
./init-workflow.sh ~/projects/myapp strict # Full enforcement
npm runRun npm script
npm run dev
πŸ“– Extracted from docs: mhylle/claude-skills-collection
1Installs
-
AddedFeb 4, 2026

Skill Details

SKILL.md

Comprehensive security audit for code changes. Use this skill when implementing authentication, authorization, user input handling, API endpoints, secrets/credentials, payment features, or file uploads. Provides security checklists, vulnerability patterns, and remediation guidance. Integrates with implement-phase as a security quality gate.

Overview

# Security Review Skill

This skill ensures all code follows security best practices and identifies potential vulnerabilities before they reach production.

Design Philosophy

Security is not optional. This skill acts as a security quality gate that validates code against common vulnerability patterns (OWASP Top 10) and project-specific security requirements. One vulnerability can compromise the entire platform.

When to Activate

Trigger this skill when code involves:

  • Authentication or authorization - Login flows, session management, role checks
  • User input handling - Forms, query parameters, file uploads
  • API endpoints - New routes, especially public-facing
  • Secrets or credentials - API keys, database connections, tokens
  • Payment features - Financial transactions, billing, subscriptions
  • Sensitive data - PII, health data, financial records
  • Third-party API integration - External service connections
  • Database queries - Especially raw SQL or dynamic queries

Security Checklist

1. Secrets Management

#### BAD - Never Do This

```typescript

const apiKey = "sk-proj-xxxxx" // Hardcoded secret

const dbPassword = "password123" // In source code

const config = {

stripe_key: "sk_live_xxxxx" // Committed to repo

}

```

#### GOOD - Always Do This

```typescript

const apiKey = process.env.OPENAI_API_KEY

const dbUrl = process.env.DATABASE_URL

// Verify secrets exist at startup

if (!apiKey) {

throw new Error('OPENAI_API_KEY not configured')

}

// Use secret management services for production

// AWS Secrets Manager, HashiCorp Vault, etc.

```

#### Verification Checklist

  • [ ] No hardcoded API keys, tokens, or passwords in source
  • [ ] All secrets loaded from environment variables
  • [ ] .env, .env.local, .env.production in .gitignore
  • [ ] No secrets in git history (run git log -p | grep -i "api_key\|secret\|password")
  • [ ] Production secrets in secure secret management (Vercel, Railway, AWS SM)
  • [ ] Different secrets for dev/staging/production environments

---

2. Input Validation

#### BAD - Never Trust User Input

```typescript

// DANGEROUS: No validation

async function createUser(req: Request) {

const { email, name, role } = req.body

return db.users.create({ email, name, role }) // role injection!

}

// DANGEROUS: Client-side only validation

if (formData.email.includes('@')) { / good enough? NO / }

```

#### GOOD - Validate Everything Server-Side

```typescript

import { z } from 'zod'

const CreateUserSchema = z.object({

email: z.string().email().max(255),

name: z.string().min(1).max(100).regex(/^[a-zA-Z\s]+$/),

age: z.number().int().min(0).max(150).optional()

// Note: role is NOT accepted from user input

})

export async function createUser(input: unknown) {

const validated = CreateUserSchema.parse(input)

return await db.users.create({

...validated,

role: 'user' // Role set server-side, never from input

})

}

```

#### 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)')

}

// MIME type check (verify actual content, not just header)

const allowedTypes = ['image/jpeg', 'image/png', 'image/gif']

if (!allowedTypes.includes(file.type)) {

throw new Error('Invalid file type')

}

// Extension check (defense in depth)

const allowedExtensions = ['.jpg', '.jpeg', '.png', '.gif']

const extension = file.name.toLowerCase().match(/\.[^.]+$/)?.[0]

if (!extension || !allowedExtensions.includes(extension)) {

throw new Error('Invalid file extension')

}

// Sanitize filename

const sanitizedName = file.name.replace(/[^a-zA-Z0-9.-]/g, '_')

return { ...file, name: sanitizedName }

}

```

#### Verification Checklist

  • [ ] All user inputs validated with schemas (zod, yup, joi)
  • [ ] Validation happens server-side (client validation is UX only)
  • [ ] File uploads restricted by size, type, and extension
  • [ ] File contents verified (not just extensions)
  • [ ] Whitelist validation preferred over blacklist
  • [ ] Error messages don't leak sensitive information
  • [ ] No direct use of user input in file paths or system commands

---

3. SQL Injection Prevention

#### BAD - Never Concatenate SQL

```typescript

// CRITICAL VULNERABILITY - SQL Injection

const query = SELECT * FROM users WHERE email = '${userEmail}'

await db.query(query)

// Also dangerous with template literals

const search = SELECT * FROM products WHERE name LIKE '%${term}%'

```

#### GOOD - Always Use Parameterized Queries

```typescript

// Safe - parameterized query with Supabase

const { data } = await supabase

.from('users')

.select('*')

.eq('email', userEmail)

// Safe - parameterized raw SQL

await db.query(

'SELECT * FROM users WHERE email = $1',

[userEmail]

)

// Safe - ORM with proper escaping

const user = await prisma.user.findUnique({

where: { email: userEmail }

})

// Safe - LIKE queries with parameterization

await db.query(

'SELECT * FROM products WHERE name LIKE $1',

[%${term}%]

)

```

#### Verification Checklist

  • [ ] All database queries use parameterized queries or ORM
  • [ ] No string concatenation or interpolation in SQL
  • [ ] Query builders used correctly (not bypassed)
  • [ ] Stored procedures use parameterized inputs
  • [ ] Database user has minimal required permissions

---

4. Authentication & Authorization

#### BAD - Insecure Token Storage

```typescript

// WRONG: localStorage vulnerable to XSS

localStorage.setItem('token', token)

localStorage.setItem('user', JSON.stringify(user))

// WRONG: No authorization check

async function deleteUser(userId: string) {

await db.users.delete({ where: { id: userId } }) // Anyone can delete!

}

```

#### GOOD - Secure Token Handling

```typescript

// CORRECT: httpOnly cookies (server-side)

res.setHeader('Set-Cookie', [

token=${token}; HttpOnly; Secure; SameSite=Strict; Max-Age=3600; Path=/

])

// CORRECT: Authorization check before action

export async function deleteUser(userId: string, requesterId: string) {

const requester = await db.users.findUnique({

where: { id: requesterId },

select: { id: true, role: true }

})

// Check ownership OR admin role

if (requester.id !== userId && requester.role !== 'admin') {

throw new ForbiddenError('Not authorized to delete this user')

}

await db.users.delete({ where: { id: userId } })

}

```

#### Row Level Security (Supabase/PostgreSQL)

```sql

-- Enable RLS on all tables with user data

ALTER TABLE users ENABLE ROW LEVEL SECURITY;

ALTER TABLE posts 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);

-- Admin policy (if needed)

CREATE POLICY "Admins can view all"

ON users FOR SELECT

USING (

EXISTS (

SELECT 1 FROM users WHERE id = auth.uid() AND role = 'admin'

)

);

```

#### Verification Checklist

  • [ ] Tokens stored in httpOnly cookies (not localStorage/sessionStorage)
  • [ ] Secure and SameSite flags set on cookies
  • [ ] Authorization check before every sensitive operation
  • [ ] Row Level Security enabled in database (Supabase)
  • [ ] Role-based access control implemented correctly
  • [ ] Session timeout configured appropriately
  • [ ] Password reset tokens single-use and time-limited
  • [ ] Failed login attempts tracked and limited

---

5. XSS Prevention

#### BAD - Rendering Unsanitized Content

```typescript

// DANGEROUS: Direct HTML injection

function Comment({ html }) {

return

}

// DANGEROUS: Eval-like functions

const userCode = getUserInput()

eval(userCode)

new Function(userCode)()

```

#### GOOD - Sanitize All User HTML

```typescript

import DOMPurify from 'isomorphic-dompurify'

function SafeComment({ html }: { html: string }) {

const clean = DOMPurify.sanitize(html, {

ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'p', 'br'],

ALLOWED_ATTR: [] // No attributes allowed

})

return

}

// Better: Use markdown instead of HTML

import { marked } from 'marked'

import DOMPurify from 'isomorphic-dompurify'

function MarkdownContent({ markdown }: { markdown: string }) {

const html = marked(markdown)

const clean = DOMPurify.sanitize(html)

return

}

```

#### Content Security Policy

```typescript

// next.config.js

const securityHeaders = [

{

key: 'Content-Security-Policy',

value: [

"default-src 'self'",

"script-src 'self'", // Remove 'unsafe-inline' 'unsafe-eval' if possible

"style-src 'self' 'unsafe-inline'", // Needed for most CSS-in-JS

"img-src 'self' data: https:",

"font-src 'self'",

"connect-src 'self' https://api.example.com",

"frame-ancestors 'none'",

"base-uri 'self'",

"form-action 'self'"

].join('; ')

},

{

key: 'X-Content-Type-Options',

value: 'nosniff'

},

{

key: 'X-Frame-Options',

value: 'DENY'

}

]

```

#### Verification Checklist

  • [ ] All user-provided HTML sanitized with DOMPurify or similar
  • [ ] dangerouslySetInnerHTML only used with sanitized content
  • [ ] CSP headers configured and tested
  • [ ] No eval(), new Function(), or innerHTML with user data
  • [ ] React's built-in XSS protection not bypassed unnecessarily
  • [ ] URL parameters validated before use in links (javascript: protocol blocked)

---

6. CSRF Protection

#### BAD - No CSRF Protection

```typescript

// VULNERABLE: State-changing GET request

app.get('/api/delete-account', async (req, res) => {

await deleteAccount(req.user.id)

})

// VULNERABLE: No CSRF token verification

app.post('/api/transfer', async (req, res) => {

await transferMoney(req.body.amount, req.body.to)

})

```

#### GOOD - Implement CSRF Protection

```typescript

import { csrf } from '@/lib/csrf'

export async function POST(request: Request) {

// Verify CSRF token from header

const token = request.headers.get('X-CSRF-Token')

if (!csrf.verify(token)) {

return NextResponse.json(

{ error: 'Invalid CSRF token' },

{ status: 403 }

)

}

// Process request

}

// Client-side: Include CSRF token in requests

fetch('/api/action', {

method: 'POST',

headers: {

'X-CSRF-Token': csrfToken, // From meta tag or cookie

'Content-Type': 'application/json'

},

body: JSON.stringify(data)

})

```

#### SameSite Cookies (Primary Defense)

```typescript

// Modern browsers: SameSite provides CSRF protection

res.setHeader('Set-Cookie', [

session=${sessionId}; HttpOnly; Secure; SameSite=Strict; Path=/

])

```

#### Verification Checklist

  • [ ] All state-changing operations use POST/PUT/DELETE (not GET)
  • [ ] CSRF tokens on forms and AJAX requests
  • [ ] SameSite=Strict on all authentication cookies
  • [ ] Origin header verified on sensitive endpoints
  • [ ] Double-submit cookie pattern for APIs (if needed)

---

7. Rate Limiting

#### BAD - No Rate Limiting

```typescript

// VULNERABLE: No limits on expensive operation

app.post('/api/search', async (req, res) => {

const results = await expensiveSearch(req.body.query)

return res.json(results)

})

// VULNERABLE: No limits on auth endpoints

app.post('/api/login', async (req, res) => {

// Brute force attack possible

})

```

#### GOOD - Implement Rate Limiting

```typescript

import rateLimit from 'express-rate-limit'

// General API rate limit

const apiLimiter = rateLimit({

windowMs: 15 60 1000, // 15 minutes

max: 100, // 100 requests per window

message: { error: 'Too many requests, please try again later' },

standardHeaders: true,

legacyHeaders: false

})

// Strict rate limit for auth endpoints

const authLimiter = rateLimit({

windowMs: 15 60 1000,

max: 5, // 5 attempts per 15 minutes

message: { error: 'Too many login attempts' },

skipSuccessfulRequests: true

})

// Very strict for expensive operations

const searchLimiter = rateLimit({

windowMs: 60 * 1000, // 1 minute

max: 10,

message: { error: 'Too many search requests' }

})

app.use('/api/', apiLimiter)

app.use('/api/auth/', authLimiter)

app.use('/api/search', searchLimiter)

```

#### Verification Checklist

  • [ ] Rate limiting on all API endpoints
  • [ ] Stricter limits on authentication endpoints
  • [ ] Stricter limits on expensive operations (search, AI, etc.)
  • [ ] IP-based rate limiting for unauthenticated requests
  • [ ] User-based rate limiting for authenticated requests
  • [ ] Rate limit headers returned to clients
  • [ ] Graceful handling of rate limit exceeded

---

8. Sensitive Data Exposure

#### BAD - Leaking Sensitive Data

```typescript

// WRONG: Logging sensitive data

console.log('User login:', { email, password })

console.log('Payment processed:', { cardNumber, cvv, amount })

console.log('Request body:', req.body) // May contain passwords

// WRONG: Exposing internal errors

catch (error) {

return res.json({

error: error.message,

stack: error.stack, // Stack trace exposed!

query: sqlQuery // Query exposed!

})

}

// WRONG: Returning full user object

return res.json({ user }) // Includes password hash, internal IDs, etc.

```

#### GOOD - Protect Sensitive Data

```typescript

// CORRECT: Redact sensitive data in logs

console.log('User login:', { email, userId: user.id })

console.log('Payment processed:', {

last4: card.number.slice(-4),

amount,

userId

})

// CORRECT: Generic error messages to clients

catch (error) {

// Log full error server-side

logger.error('Payment failed', {

error: error.message,

userId,

// Never log card numbers, even partial

})

// Return generic message to client

return res.status(500).json({

error: 'Payment processing failed. Please try again.'

})

}

// CORRECT: Select specific fields

const user = await db.users.findUnique({

where: { id: userId },

select: {

id: true,

email: true,

name: true,

// Explicitly exclude: passwordHash, internalNotes, etc.

}

})

return res.json({ user })

```

#### Verification Checklist

  • [ ] No passwords, tokens, or full card numbers in logs
  • [ ] Error messages generic for end users
  • [ ] Detailed errors only in server-side logs
  • [ ] No stack traces exposed to clients
  • [ ] API responses select specific fields (not SELECT *)
  • [ ] Sensitive data encrypted at rest
  • [ ] Sensitive data encrypted in transit (HTTPS enforced)
  • [ ] PII handling compliant with regulations (GDPR, CCPA)

---

9. Blockchain Security (Conditional)

Only applicable when project involves blockchain/crypto functionality.

#### BAD - Insecure Blockchain Handling

```typescript

// WRONG: Not verifying wallet ownership

async function claimReward(walletAddress: string) {

await sendReward(walletAddress) // Anyone can claim!

}

// WRONG: Blind transaction signing

async function processTransaction(tx: any) {

await wallet.signAndSend(tx) // No validation!

}

```

#### GOOD - Verify Everything

```typescript

import { verify } from '@solana/web3.js'

import nacl from 'tweetnacl'

// Verify wallet ownership with signed message

async function verifyWalletOwnership(

publicKey: string,

signature: string,

message: string

): Promise {

try {

const messageBytes = new TextEncoder().encode(message)

const signatureBytes = Buffer.from(signature, 'base64')

const publicKeyBytes = Buffer.from(publicKey, 'base64')

return nacl.sign.detached.verify(

messageBytes,

signatureBytes,

publicKeyBytes

)

} catch {

return false

}

}

// Validate transaction before signing

async function processTransaction(transaction: Transaction) {

// Verify recipient is expected

if (transaction.to !== KNOWN_RECIPIENT) {

throw new Error('Invalid recipient address')

}

// Verify amount is within limits

if (transaction.amount > MAX_TRANSACTION_AMOUNT) {

throw new Error('Amount exceeds limit')

}

// Verify user has sufficient balance

const balance = await getBalance(transaction.from)

if (balance < transaction.amount + GAS_BUFFER) {

throw new Error('Insufficient balance')

}

// Log transaction for audit

await auditLog.record({

type: 'transaction',

from: transaction.from,

to: transaction.to,

amount: transaction.amount,

timestamp: new Date()

})

return await signAndSend(transaction)

}

```

#### Verification Checklist

  • [ ] Wallet signatures verified before granting access
  • [ ] Transaction details validated before signing
  • [ ] Balance checks before transactions
  • [ ] No blind transaction signing
  • [ ] Transaction limits enforced
  • [ ] Audit logging for all transactions
  • [ ] Private keys never exposed in logs or errors
  • [ ] Smart contract interactions validated

---

10. Dependency Security

#### Regular Security Audits

```bash

# Check for known vulnerabilities

npm audit

# Automatically fix what's possible

npm audit fix

# Check for outdated packages

npm outdated

# Update dependencies

npm update

# For major updates, use interactive mode carefully

npx npm-check-updates -i

```

#### Lock File Management

```bash

# ALWAYS commit lock files

git add package-lock.json # or yarn.lock, pnpm-lock.yaml

# In CI/CD, use clean install for reproducible builds

npm ci # Not npm install

# Verify integrity

npm ci --ignore-scripts # Then run scripts separately if needed

```

#### Verification Checklist

  • [ ] No known vulnerabilities (npm audit clean or exceptions documented)
  • [ ] Dependencies regularly updated
  • [ ] Lock files committed to repository
  • [ ] Dependabot or similar enabled on GitHub
  • [ ] Unused dependencies removed
  • [ ] Dependencies from trusted sources only
  • [ ] License compliance verified (no GPL in proprietary code, etc.)
  • [ ] Postinstall scripts reviewed for new dependencies

---

Integration with implement-phase

When invoked as part of the implement-phase pipeline (Step 3), this skill provides structured output for orchestration.

Input Context

```

Security Review for Phase [N]

Context:

  • Plan: [path to plan file]
  • Phase: [phase number and name]
  • Changed files: [list of modified/added files]
  • Security-relevant changes: [auth, input, api, secrets, payment, uploads]

```

Output Format

```

STATUS: PASS | PASS_WITH_ISSUES | FAIL

CATEGORIES_CHECKED: [count of applicable categories reviewed]

ISSUES_FOUND:

  • [CRITICAL] [Category]: [Description]
  • [HIGH] [Category]: [Description]
  • [MEDIUM] [Category]: [Description]
  • [LOW] [Category]: [Description]

SEVERITY: CRITICAL | HIGH | MEDIUM | LOW | NONE

RECOMMENDATIONS:

  • [Non-blocking improvement suggestions]

REPORT: [Path to detailed report if written]

```

Severity Levels

| Level | Meaning | Action Required |

|-------|---------|-----------------|

| CRITICAL | Active vulnerability, exploitable now | Block deployment, fix immediately |

| HIGH | Serious vulnerability, likely exploitable | Block deployment, fix before merge |

| MEDIUM | Potential vulnerability, context-dependent | Should fix, may proceed with documented exception |

| LOW | Best practice violation, minimal risk | Note for improvement |

Integration Point in Pipeline

```

implement-phase Pipeline:

Step 1: Implementation

Step 2: Functional verification (tests pass)

Step 3: Code review

Step 4: SECURITY REVIEW (this skill) <--

Step 5: Plan synchronization

Step 6: Completion report

On FAIL:

- Block phase completion

- Report blocking issues

- Require fixes before retry

```

---

Pre-Deployment Security Checklist

Before ANY production deployment, verify:

Secrets & Configuration

  • [ ] No hardcoded secrets in code
  • [ ] All secrets in environment variables
  • [ ] Production secrets in secure management
  • [ ] Different secrets per environment

Input & Data

  • [ ] All user input validated server-side
  • [ ] File uploads validated and sanitized
  • [ ] All database queries parameterized
  • [ ] Sensitive data encrypted at rest

Authentication & Authorization

  • [ ] Tokens in httpOnly cookies
  • [ ] Authorization checks on all operations
  • [ ] Row Level Security enabled
  • [ ] Session management secure

Web Security

  • [ ] XSS protection (CSP, sanitization)
  • [ ] CSRF protection enabled
  • [ ] HTTPS enforced
  • [ ] Security headers configured

Infrastructure

  • [ ] Rate limiting on all endpoints
  • [ ] Error messages don't leak info
  • [ ] Logging doesn't include secrets
  • [ ] Dependencies up to date

Compliance

  • [ ] CORS properly configured
  • [ ] Privacy policy accurate
  • [ ] Data handling compliant (GDPR/CCPA)

---

References

For detailed checklists and examples:

  • [security-checklist.md](references/security-checklist.md) - Quick reference checklist
  • [OWASP Top 10](https://owasp.org/www-project-top-ten/) - Common vulnerabilities
  • [OWASP Cheat Sheets](https://cheatsheetseries.owasp.org/) - Detailed guidance

---

Security is everyone's responsibility. When in doubt, ask for a security review.

More from this repository10

🎯
brainstorm🎯Skill

Helps users systematically explore and refine ideas through Socratic questioning, multi-perspective analysis, and proactive research to transform raw concepts into structured proposals.

🎯
prompt-generator🎯Skill

Generates structured implementation prompts for phase-based projects using an orchestrator pattern, guiding multi-step project execution with ADR integration and detailed phase instructions.

🎯
create-plan🎯Skill

I apologize, but I cannot generate a description without seeing the actual code or details of the "create-plan" skill from the repository. Could you provide more context about what the skill does, ...

🎯
iterate-plan🎯Skill

Iteratively updates and refines implementation plans through user feedback, research, and migration to Task tools system.

🎯
implement-plan🎯Skill

Orchestrates complete implementation plans by delegating phases to implement-phase skill, managing lifecycle, sequencing, and tracking progress.

🎯
agent-creator🎯Skill

I apologize, but I cannot generate a description without seeing the actual repository or skill details. Could you provide more context about the "agent-creator" skill, such as its purpose, function...

🎯
codebase-research🎯Skill

Researches codebase comprehensively by decomposing queries into parallel sub-agent tasks and synthesizing detailed findings about code structure and functionality.

🎯
implement-phase🎯Skill

Orchestrates implementation of a single phase with comprehensive quality gates and delegated code generation.

🎯
strategic-compact🎯Skill

Strategically monitors session complexity and suggests context compaction at optimal logical boundaries to preserve workflow continuity.

🎯
skill-visualizer🎯Skill

Visualizes skills, codebase, and dependencies using interactive D3.js-powered HTML diagrams with color-coded, collapsible nodes.