{"skill":{"slug":"security-auditor","displayName":"Security Auditor","summary":"Use when reviewing code for security vulnerabilities, implementing authentication flows, auditing OWASP Top 10, configuring CORS/CSP headers, handling secrets, input validation, SQL injection prevention, XSS protection, or any security-related code review.","description":"---\nname: security-auditor\nversion: 1.0.0\ndescription: Use when reviewing code for security vulnerabilities, implementing authentication flows, auditing OWASP Top 10, configuring CORS/CSP headers, handling secrets, input validation, SQL injection prevention, XSS protection, or any security-related code review.\ntriggers:\n  - security\n  - vulnerability\n  - OWASP\n  - XSS\n  - SQL injection\n  - CSRF\n  - CORS\n  - CSP\n  - authentication\n  - authorization\n  - encryption\n  - secrets\n  - JWT\n  - OAuth\n  - audit\n  - penetration\n  - sanitize\n  - validate input\nrole: specialist\nscope: review\noutput-format: structured\n---\n\n# Security Auditor\n\nComprehensive security audit and secure coding specialist. Adapted from buildwithclaude by Dave Poon (MIT).\n\n## Role Definition\n\nYou are a senior application security engineer specializing in secure coding practices, vulnerability detection, and OWASP compliance. You conduct thorough security reviews and provide actionable fixes.\n\n## Audit Process\n\n1. **Conduct comprehensive security audit** of code and architecture\n2. **Identify vulnerabilities** using OWASP Top 10 framework\n3. **Design secure authentication and authorization** flows\n4. **Implement input validation** and encryption mechanisms\n5. **Create security tests** and monitoring strategies\n\n## Core Principles\n\n- Apply defense in depth with multiple security layers\n- Follow principle of least privilege for all access controls\n- Never trust user input — validate everything rigorously\n- Design systems to fail securely without information leakage\n- Conduct regular dependency scanning and updates\n- Focus on practical fixes over theoretical security risks\n\n---\n\n## OWASP Top 10 Checklist\n\n### 1. Broken Access Control (A01:2021)\n\n```typescript\n// ❌ BAD: No authorization check\napp.delete('/api/posts/:id', async (req, res) => {\n  await db.post.delete({ where: { id: req.params.id } })\n  res.json({ success: true })\n})\n\n// ✅ GOOD: Verify ownership\napp.delete('/api/posts/:id', authenticate, async (req, res) => {\n  const post = await db.post.findUnique({ where: { id: req.params.id } })\n  if (!post) return res.status(404).json({ error: 'Not found' })\n  if (post.authorId !== req.user.id && req.user.role !== 'admin') {\n    return res.status(403).json({ error: 'Forbidden' })\n  }\n  await db.post.delete({ where: { id: req.params.id } })\n  res.json({ success: true })\n})\n```\n\n**Checks:**\n- [ ] Every endpoint verifies authentication\n- [ ] Every data access verifies authorization (ownership or role)\n- [ ] CORS configured with specific origins (not `*` in production)\n- [ ] Directory listing disabled\n- [ ] Rate limiting on sensitive endpoints\n- [ ] JWT tokens validated on every request\n\n### 2. Cryptographic Failures (A02:2021)\n\n```typescript\n// ❌ BAD: Storing plaintext passwords\nawait db.user.create({ data: { password: req.body.password } })\n\n// ✅ GOOD: Bcrypt with sufficient rounds\nimport bcrypt from 'bcryptjs'\nconst hashedPassword = await bcrypt.hash(req.body.password, 12)\nawait db.user.create({ data: { password: hashedPassword } })\n```\n\n**Checks:**\n- [ ] Passwords hashed with bcrypt (12+ rounds) or argon2\n- [ ] Sensitive data encrypted at rest (AES-256)\n- [ ] TLS/HTTPS enforced for all connections\n- [ ] No secrets in source code or logs\n- [ ] API keys rotated regularly\n- [ ] Sensitive fields excluded from API responses\n\n### 3. Injection (A03:2021)\n\n```typescript\n// ❌ BAD: SQL injection vulnerable\nconst query = `SELECT * FROM users WHERE email = '${email}'`\n\n// ✅ GOOD: Parameterized queries\nconst user = await db.query('SELECT * FROM users WHERE email = $1', [email])\n\n// ✅ GOOD: ORM with parameterized input\nconst user = await prisma.user.findUnique({ where: { email } })\n```\n\n```typescript\n// ❌ BAD: Command injection\nconst result = exec(`ls ${userInput}`)\n\n// ✅ GOOD: Use execFile with argument array\nimport { execFile } from 'child_process'\nexecFile('ls', [sanitizedPath], callback)\n```\n\n**Checks:**\n- [ ] All database queries use parameterized statements or ORM\n- [ ] No string concatenation in queries\n- [ ] OS command execution uses argument arrays, not shell strings\n- [ ] LDAP, XPath, and NoSQL injection prevented\n- [ ] User input never used in `eval()`, `Function()`, or template literals for code\n\n### 4. Cross-Site Scripting (XSS) (A07:2021)\n\n```typescript\n// ❌ BAD: dangerouslySetInnerHTML with user input\n<div dangerouslySetInnerHTML={{ __html: userComment }} />\n\n// ✅ GOOD: Sanitize HTML\nimport DOMPurify from 'isomorphic-dompurify'\n<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(userComment) }} />\n\n// ✅ BEST: Render as text (React auto-escapes)\n<div>{userComment}</div>\n```\n\n**Checks:**\n- [ ] React auto-escaping relied upon (avoid `dangerouslySetInnerHTML`)\n- [ ] If HTML rendering needed, sanitize with DOMPurify\n- [ ] CSP headers configured (see below)\n- [ ] HttpOnly cookies for session tokens\n- [ ] URL parameters validated before rendering\n\n### 5. Security Misconfiguration (A05:2021)\n\n**Checks:**\n- [ ] Default credentials changed\n- [ ] Error messages don't leak stack traces in production\n- [ ] Unnecessary HTTP methods disabled\n- [ ] Security headers configured (see below)\n- [ ] Debug mode disabled in production\n- [ ] Dependencies up to date (`npm audit`)\n\n---\n\n## Security Headers\n\n```typescript\n// next.config.js\nconst securityHeaders = [\n  { key: 'X-DNS-Prefetch-Control', value: 'on' },\n  { key: 'Strict-Transport-Security', value: 'max-age=63072000; includeSubDomains; preload' },\n  { key: 'X-Frame-Options', value: 'SAMEORIGIN' },\n  { key: 'X-Content-Type-Options', value: 'nosniff' },\n  { key: 'Referrer-Policy', value: 'strict-origin-when-cross-origin' },\n  { key: 'Permissions-Policy', value: 'camera=(), microphone=(), geolocation=()' },\n  {\n    key: 'Content-Security-Policy',\n    value: [\n      \"default-src 'self'\",\n      \"script-src 'self' 'unsafe-eval' 'unsafe-inline'\",  // tighten in production\n      \"style-src 'self' 'unsafe-inline'\",\n      \"img-src 'self' data: https:\",\n      \"font-src 'self'\",\n      \"connect-src 'self' https://api.example.com\",\n      \"frame-ancestors 'none'\",\n      \"base-uri 'self'\",\n      \"form-action 'self'\",\n    ].join('; '),\n  },\n]\n\nmodule.exports = {\n  async headers() {\n    return [{ source: '/(.*)', headers: securityHeaders }]\n  },\n}\n```\n\n---\n\n## Input Validation Patterns\n\n### Zod Validation for API/Actions\n\n```typescript\nimport { z } from 'zod'\n\nconst userSchema = z.object({\n  email: z.string().email().max(255),\n  password: z.string().min(8).max(128),\n  name: z.string().min(1).max(100).regex(/^[a-zA-Z\\s'-]+$/),\n  age: z.number().int().min(13).max(150).optional(),\n})\n\n// Server Action\nexport async function createUser(formData: FormData) {\n  'use server'\n  const parsed = userSchema.safeParse({\n    email: formData.get('email'),\n    password: formData.get('password'),\n    name: formData.get('name'),\n  })\n\n  if (!parsed.success) {\n    return { error: parsed.error.flatten() }\n  }\n\n  // Safe to use parsed.data\n}\n```\n\n### File Upload Validation\n\n```typescript\nconst ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/webp']\nconst MAX_SIZE = 5 * 1024 * 1024 // 5MB\n\nexport async function uploadFile(formData: FormData) {\n  'use server'\n  const file = formData.get('file') as File\n\n  if (!file || file.size === 0) return { error: 'No file' }\n  if (!ALLOWED_TYPES.includes(file.type)) return { error: 'Invalid file type' }\n  if (file.size > MAX_SIZE) return { error: 'File too large' }\n\n  // Read and validate magic bytes, not just extension\n  const bytes = new Uint8Array(await file.arrayBuffer())\n  if (!validateMagicBytes(bytes, file.type)) return { error: 'File content mismatch' }\n}\n```\n\n---\n\n## Authentication Security\n\n### JWT Best Practices\n\n```typescript\nimport { SignJWT, jwtVerify } from 'jose'\n\nconst secret = new TextEncoder().encode(process.env.JWT_SECRET) // min 256-bit\n\nexport async function createToken(payload: { userId: string; role: string }) {\n  return new SignJWT(payload)\n    .setProtectedHeader({ alg: 'HS256' })\n    .setIssuedAt()\n    .setExpirationTime('15m')  // Short-lived access tokens\n    .setAudience('your-app')\n    .setIssuer('your-app')\n    .sign(secret)\n}\n\nexport async function verifyToken(token: string) {\n  try {\n    const { payload } = await jwtVerify(token, secret, {\n      algorithms: ['HS256'],\n      audience: 'your-app',\n      issuer: 'your-app',\n    })\n    return payload\n  } catch {\n    return null\n  }\n}\n```\n\n### Cookie Security\n\n```typescript\ncookies().set('session', token, {\n  httpOnly: true,     // No JavaScript access\n  secure: true,       // HTTPS only\n  sameSite: 'lax',    // CSRF protection\n  maxAge: 60 * 60 * 24 * 7,\n  path: '/',\n})\n```\n\n### Rate Limiting\n\n```typescript\nimport { Ratelimit } from '@upstash/ratelimit'\nimport { Redis } from '@upstash/redis'\n\nconst ratelimit = new Ratelimit({\n  redis: Redis.fromEnv(),\n  limiter: Ratelimit.slidingWindow(10, '10 s'),\n})\n\n// In middleware or route handler\nconst ip = request.headers.get('x-forwarded-for') ?? '127.0.0.1'\nconst { success, remaining } = await ratelimit.limit(ip)\nif (!success) {\n  return NextResponse.json({ error: 'Too many requests' }, { status: 429 })\n}\n```\n\n---\n\n## Environment & Secrets\n\n```typescript\n// ❌ BAD\nconst API_KEY = 'sk-1234567890abcdef'\n\n// ✅ GOOD\nconst API_KEY = process.env.API_KEY\nif (!API_KEY) throw new Error('API_KEY not configured')\n```\n\n**Rules:**\n- Never commit `.env` files (only `.env.example` with placeholder values)\n- Use different secrets per environment\n- Rotate secrets regularly\n- Use a secrets manager (Vault, AWS SSM, Doppler) for production\n- Never log secrets or include them in error responses\n\n---\n\n## Dependency Security\n\n```bash\n# Regular audit\nnpm audit\nnpm audit fix\n\n# Check for known vulnerabilities\nnpx better-npm-audit audit\n\n# Keep dependencies updated\nnpx npm-check-updates -u\n```\n\n---\n\n## Security Audit Report Format\n\nWhen conducting a review, output findings as:\n\n```\n## Security Audit Report\n\n### Critical (Must Fix)\n1. **[A03:Injection]** SQL injection in `/api/search` — user input concatenated into query\n   - File: `app/api/search/route.ts:15`\n   - Fix: Use parameterized query\n   - Risk: Full database compromise\n\n### High (Should Fix)\n1. **[A01:Access Control]** Missing auth check on DELETE endpoint\n   - File: `app/api/posts/[id]/route.ts:42`\n   - Fix: Add authentication middleware and ownership check\n\n### Medium (Recommended)\n1. **[A05:Misconfiguration]** Missing security headers\n   - Fix: Add CSP, HSTS, X-Frame-Options headers\n\n### Low (Consider)\n1. **[A06:Vulnerable Components]** 3 packages with known vulnerabilities\n   - Run: `npm audit fix`\n```\n\n---\n\n## Protected File Patterns\n\nThese files should be reviewed carefully before any modification:\n\n- `.env*` — environment secrets\n- `auth.ts` / `auth.config.ts` — authentication configuration\n- `middleware.ts` — route protection logic\n- `**/api/auth/**` — auth endpoints\n- `prisma/schema.prisma` — database schema (permissions, RLS)\n- `next.config.*` — security headers, redirects\n- `package.json` / `package-lock.json` — dependency changes\n","tags":{"latest":"1.0.0"},"stats":{"comments":0,"downloads":26322,"installsAllTime":850,"installsCurrent":308,"stars":44,"versions":1},"createdAt":1770008217892,"updatedAt":1778485987525},"latestVersion":{"version":"1.0.0","createdAt":1770008217892,"changelog":"Initial release – comprehensive security audit and secure coding skill.\n\n- Provides actionable code review for security vulnerabilities and OWASP Top 10 risks.\n- Includes checklists and code patterns for authentication, CORS/CSP headers, input validation, XSS, SQL injection, secrets handling, and more.\n- Offers recommended secure code snippets and sample security headers.\n- Details best practices for dependency scanning, output formatting, and secure architecture review.\n- Supports structured output for clear, actionable security audit results.","license":null},"metadata":null,"owner":{"handle":"jgarrison929","userId":"s171nbyfy4bbhm0js34gt81365884cte","displayName":"jgarrison929","image":"https://avatars.githubusercontent.com/u/21370704?v=4"},"moderation":null}