[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6EZT656HTMEZHG6DJR6F34R":3,"skill-same:01M6EZT656HTMEZHG6DJR6F34R":83},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":31,"publishedAt":47,"linkOnly":48,"markdownContent":49,"markdownBody":50,"frontMatter":51,"refName":54,"commitSha":55,"skillDirectory":56,"forksCount":57,"repositoryHtmlUrl":58,"repositoryHomepageUrl":59,"ownerHtmlUrl":60,"ownerBlogUrl":6,"ownerDescription":61,"updatedAt":62,"install":63,"resources":76},"01M6EZT656HTMEZHG6DJR6F34R","security-review",null,"Use this skill when adding authentication, handling user input, working with secrets, creating API endpoints, or implementing payment\u002Fsensitive features. Provides comprehensive security checklist and patterns.","ComeOnOliver\u002Fskillshub","ComeOnOliver","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F43215937?v=4","01M6E5JNFECJAAVFE0W7SMWWD2","Haoran Shu","01M6E5JNNDQS7AJZDYFQ8TPZCK",67,"MIT","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fsickn33\u002Fsecurity-review\u002FSKILL.md",[18,23,26],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",{"categoryNo":27,"categoryName":28,"taxonomyType":29,"taxonomyTypeDesc":30},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[32,33,34,35,36,37,38,39,40,41,42,43,44,45,46],"review","security","security review","authentication","api","secrets","user","use","endpoints","checklist","patterns","payment","input","security checklist","with","2026-11-10 10:12:30",false,"---\nname: security-review\ndescription: Use this skill when adding authentication, handling user input, working with secrets, creating API endpoints, or implementing payment\u002Fsensitive features. Provides comprehensive security checklist and patterns.\nauthor: affaan-m\nversion: \"1.0\"\n---\n\n# Security Review Skill\n\nThis skill ensures all code follows security best practices and identifies potential vulnerabilities.\n\n## When to Activate\n\n- Implementing authentication or authorization\n- Handling user input or file uploads\n- Creating new API endpoints\n- Working with secrets or credentials\n- Implementing payment features\n- Storing or transmitting sensitive data\n- Integrating third-party APIs\n\n## Security Checklist\n\n### 1. Secrets Management\n\n#### ❌ NEVER Do This\n```typescript\nconst apiKey = \"sk-proj-xxxxx\"  \u002F\u002F Hardcoded secret\nconst dbPassword = \"password123\" \u002F\u002F In source code\n```\n\n#### ✅ ALWAYS Do This\n```typescript\nconst apiKey = process.env.OPENAI_API_KEY\nconst dbUrl = process.env.DATABASE_URL\n\n\u002F\u002F Verify secrets exist\nif (!apiKey) {\n  throw new Error('OPENAI_API_KEY not configured')\n}\n```\n\n#### Verification Steps\n- [ ] No hardcoded API keys, tokens, or passwords\n- [ ] All secrets in environment variables\n- [ ] `.env.local` in .gitignore\n- [ ] No secrets in git history\n- [ ] Production secrets in hosting platform (Vercel, Railway)\n\n### 2. Input Validation\n\n#### Always Validate User Input\n```typescript\nimport { z } from 'zod'\n\n\u002F\u002F Define validation schema\nconst CreateUserSchema = z.object({\n  email: z.string().email(),\n  name: z.string().min(1).max(100),\n  age: z.number().int().min(0).max(150)\n})\n\n\u002F\u002F Validate before processing\nexport async function createUser(input: unknown) {\n  try {\n    const validated = CreateUserSchema.parse(input)\n    return await db.users.create(validated)\n  } catch (error) {\n    if (error instanceof z.ZodError) {\n      return { success: false, errors: error.errors }\n    }\n    throw error\n  }\n}\n```\n\n#### File Upload Validation\n```typescript\nfunction validateFileUpload(file: File) {\n  \u002F\u002F Size check (5MB max)\n  const maxSize = 5 * 1024 * 1024\n  if (file.size > maxSize) {\n    throw new Error('File too large (max 5MB)')\n  }\n\n  \u002F\u002F Type check\n  const allowedTypes = ['image\u002Fjpeg', 'image\u002Fpng', 'image\u002Fgif']\n  if (!allowedTypes.includes(file.type)) {\n    throw new Error('Invalid file type')\n  }\n\n  \u002F\u002F Extension check\n  const allowedExtensions = ['.jpg', '.jpeg', '.png', '.gif']\n  const extension = file.name.toLowerCase().match(\u002F\\.[^.]+$\u002F)?.[0]\n  if (!extension || !allowedExtensions.includes(extension)) {\n    throw new Error('Invalid file extension')\n  }\n\n  return true\n}\n```\n\n#### Verification Steps\n- [ ] All user inputs validated with schemas\n- [ ] File uploads restricted (size, type, extension)\n- [ ] No direct use of user input in queries\n- [ ] Whitelist validation (not blacklist)\n- [ ] Error messages don't leak sensitive info\n\n### 3. SQL Injection Prevention\n\n#### ❌ NEVER Concatenate SQL\n```typescript\n\u002F\u002F DANGEROUS - SQL Injection vulnerability\nconst query = `SELECT * FROM users WHERE email = '${userEmail}'`\nawait db.query(query)\n```\n\n#### ✅ ALWAYS Use Parameterized Queries\n```typescript\n\u002F\u002F Safe - parameterized query\nconst { data } = await supabase\n  .from('users')\n  .select('*')\n  .eq('email', userEmail)\n\n\u002F\u002F Or with raw SQL\nawait db.query(\n  'SELECT * FROM users WHERE email = $1',\n  [userEmail]\n)\n```\n\n#### Verification Steps\n- [ ] All database queries use parameterized queries\n- [ ] No string concatenation in SQL\n- [ ] ORM\u002Fquery builder used correctly\n- [ ] Supabase queries properly sanitized\n\n### 4. Authentication & Authorization\n\n#### JWT Token Handling\n```typescript\n\u002F\u002F ❌ WRONG: localStorage (vulnerable to XSS)\nlocalStorage.setItem('token', token)\n\n\u002F\u002F ✅ CORRECT: httpOnly cookies\nres.setHeader('Set-Cookie',\n  `token=${token}; HttpOnly; Secure; SameSite=Strict; Max-Age=3600`)\n```\n\n#### Authorization Checks\n```typescript\nexport async function deleteUser(userId: string, requesterId: string) {\n  \u002F\u002F ALWAYS verify authorization first\n  const requester = await db.users.findUnique({\n    where: { id: requesterId }\n  })\n\n  if (requester.role !== 'admin') {\n    return NextResponse.json(\n      { error: 'Unauthorized' },\n      { status: 403 }\n    )\n  }\n\n  \u002F\u002F Proceed with deletion\n  await db.users.delete({ where: { id: userId } })\n}\n```\n\n#### Row Level Security (Supabase)\n```sql\n-- Enable RLS on all tables\nALTER TABLE users ENABLE ROW LEVEL SECURITY;\n\n-- Users can only view their own data\nCREATE POLICY \"Users view own data\"\n  ON users FOR SELECT\n  USING (auth.uid() = id);\n\n-- Users can only update their own data\nCREATE POLICY \"Users update own data\"\n  ON users FOR UPDATE\n  USING (auth.uid() = id);\n```\n\n#### Verification Steps\n- [ ] Tokens stored in httpOnly cookies (not localStorage)\n- [ ] Authorization checks before sensitive operations\n- [ ] Row Level Security enabled in Supabase\n- [ ] Role-based access control implemented\n- [ ] Session management secure\n\n### 5. XSS Prevention\n\n#### Sanitize HTML\n```typescript\nimport DOMPurify from 'isomorphic-dompurify'\n\n\u002F\u002F ALWAYS sanitize user-provided HTML\nfunction renderUserContent(html: string) {\n  const clean = DOMPurify.sanitize(html, {\n    ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'p'],\n    ALLOWED_ATTR: []\n  })\n  return \u003Cdiv dangerouslySetInnerHTML={{ __html: clean }} \u002F>\n}\n```\n\n#### Content Security Policy\n```typescript\n\u002F\u002F next.config.js\nconst securityHeaders = [\n  {\n    key: 'Content-Security-Policy',\n    value: `\n      default-src 'self';\n      script-src 'self' 'unsafe-eval' 'unsafe-inline';\n      style-src 'self' 'unsafe-inline';\n      img-src 'self' data: https:;\n      font-src 'self';\n      connect-src 'self' https:\u002F\u002Fapi.example.com;\n    `.replace(\u002F\\s{2,}\u002Fg, ' ').trim()\n  }\n]\n```\n\n#### Verification Steps\n- [ ] User-provided HTML sanitized\n- [ ] CSP headers configured\n- [ ] No unvalidated dynamic content rendering\n- [ ] React's built-in XSS protection used\n\n### 6. CSRF Protection\n\n#### CSRF Tokens\n```typescript\nimport { csrf } from '@\u002Flib\u002Fcsrf'\n\nexport async function POST(request: Request) {\n  const token = request.headers.get('X-CSRF-Token')\n\n  if (!csrf.verify(token)) {\n    return NextResponse.json(\n      { error: 'Invalid CSRF token' },\n      { status: 403 }\n    )\n  }\n\n  \u002F\u002F Process request\n}\n```\n\n#### SameSite Cookies\n```typescript\nres.setHeader('Set-Cookie',\n  `session=${sessionId}; HttpOnly; Secure; SameSite=Strict`)\n```\n\n#### Verification Steps\n- [ ] CSRF tokens on state-changing operations\n- [ ] SameSite=Strict on all cookies\n- [ ] Double-submit cookie pattern implemented\n\n### 7. Rate Limiting\n\n#### API Rate Limiting\n```typescript\nimport rateLimit from 'express-rate-limit'\n\nconst limiter = rateLimit({\n  windowMs: 15 * 60 * 1000, \u002F\u002F 15 minutes\n  max: 100, \u002F\u002F 100 requests per window\n  message: 'Too many requests'\n})\n\n\u002F\u002F Apply to routes\napp.use('\u002Fapi\u002F', limiter)\n```\n\n#### Expensive Operations\n```typescript\n\u002F\u002F Aggressive rate limiting for searches\nconst searchLimiter = rateLimit({\n  windowMs: 60 * 1000, \u002F\u002F 1 minute\n  max: 10, \u002F\u002F 10 requests per minute\n  message: 'Too many search requests'\n})\n\napp.use('\u002Fapi\u002Fsearch', searchLimiter)\n```\n\n#### Verification Steps\n- [ ] Rate limiting on all API endpoints\n- [ ] Stricter limits on expensive operations\n- [ ] IP-based rate limiting\n- [ ] User-based rate limiting (authenticated)\n\n### 8. Sensitive Data Exposure\n\n#### Logging\n```typescript\n\u002F\u002F ❌ WRONG: Logging sensitive data\nconsole.log('User login:', { email, password })\nconsole.log('Payment:', { cardNumber, cvv })\n\n\u002F\u002F ✅ CORRECT: Redact sensitive data\nconsole.log('User login:', { email, userId })\nconsole.log('Payment:', { last4: card.last4, userId })\n```\n\n#### Error Messages\n```typescript\n\u002F\u002F ❌ WRONG: Exposing internal details\ncatch (error) {\n  return NextResponse.json(\n    { error: error.message, stack: error.stack },\n    { status: 500 }\n  )\n}\n\n\u002F\u002F ✅ CORRECT: Generic error messages\ncatch (error) {\n  console.error('Internal error:', error)\n  return NextResponse.json(\n    { error: 'An error occurred. Please try again.' },\n    { status: 500 }\n  )\n}\n```\n\n#### Verification Steps\n- [ ] No passwords, tokens, or secrets in logs\n- [ ] Error messages generic for users\n- [ ] Detailed errors only in server logs\n- [ ] No stack traces exposed to users\n\n### 9. Blockchain Security (Solana)\n\n#### Wallet Verification\n```typescript\nimport { verify } from '@solana\u002Fweb3.js'\n\nasync function verifyWalletOwnership(\n  publicKey: string,\n  signature: string,\n  message: string\n) {\n  try {\n    const isValid = verify(\n      Buffer.from(message),\n      Buffer.from(signature, 'base64'),\n      Buffer.from(publicKey, 'base64')\n    )\n    return isValid\n  } catch (error) {\n    return false\n  }\n}\n```\n\n#### Transaction Verification\n```typescript\nasync function verifyTransaction(transaction: Transaction) {\n  \u002F\u002F Verify recipient\n  if (transaction.to !== expectedRecipient) {\n    throw new Error('Invalid recipient')\n  }\n\n  \u002F\u002F Verify amount\n  if (transaction.amount > maxAmount) {\n    throw new Error('Amount exceeds limit')\n  }\n\n  \u002F\u002F Verify user has sufficient balance\n  const balance = await getBalance(transaction.from)\n  if (balance \u003C transaction.amount) {\n    throw new Error('Insufficient balance')\n  }\n\n  return true\n}\n```\n\n#### Verification Steps\n- [ ] Wallet signatures verified\n- [ ] Transaction details validated\n- [ ] Balance checks before transactions\n- [ ] No blind transaction signing\n\n### 10. Dependency Security\n\n#### Regular Updates\n```bash\n# Check for vulnerabilities\nnpm audit\n\n# Fix automatically fixable issues\nnpm audit fix\n\n# Update dependencies\nnpm update\n\n# Check for outdated packages\nnpm outdated\n```\n\n#### Lock Files\n```bash\n# ALWAYS commit lock files\ngit add package-lock.json\n\n# Use in CI\u002FCD for reproducible builds\nnpm ci  # Instead of npm install\n```\n\n#### Verification Steps\n- [ ] Dependencies up to date\n- [ ] No known vulnerabilities (npm audit clean)\n- [ ] Lock files committed\n- [ ] Dependabot enabled on GitHub\n- [ ] Regular security updates\n\n## Security Testing\n\n### Automated Security Tests\n```typescript\n\u002F\u002F Test authentication\ntest('requires authentication', async () => {\n  const response = await fetch('\u002Fapi\u002Fprotected')\n  expect(response.status).toBe(401)\n})\n\n\u002F\u002F Test authorization\ntest('requires admin role', async () => {\n  const response = await fetch('\u002Fapi\u002Fadmin', {\n    headers: { Authorization: `Bearer ${userToken}` }\n  })\n  expect(response.status).toBe(403)\n})\n\n\u002F\u002F Test input validation\ntest('rejects invalid input', async () => {\n  const response = await fetch('\u002Fapi\u002Fusers', {\n    method: 'POST',\n    body: JSON.stringify({ email: 'not-an-email' })\n  })\n  expect(response.status).toBe(400)\n})\n\n\u002F\u002F Test rate limiting\ntest('enforces rate limits', async () => {\n  const requests = Array(101).fill(null).map(() =>\n    fetch('\u002Fapi\u002Fendpoint')\n  )\n\n  const responses = await Promise.all(requests)\n  const tooManyRequests = responses.filter(r => r.status === 429)\n\n  expect(tooManyRequests.length).toBeGreaterThan(0)\n})\n```\n\n## Pre-Deployment Security Checklist\n\nBefore ANY production deployment:\n\n- [ ] **Secrets**: No hardcoded secrets, all in env vars\n- [ ] **Input Validation**: All user inputs validated\n- [ ] **SQL Injection**: All queries parameterized\n- [ ] **XSS**: User content sanitized\n- [ ] **CSRF**: Protection enabled\n- [ ] **Authentication**: Proper token handling\n- [ ] **Authorization**: Role checks in place\n- [ ] **Rate Limiting**: Enabled on all endpoints\n- [ ] **HTTPS**: Enforced in production\n- [ ] **Security Headers**: CSP, X-Frame-Options configured\n- [ ] **Error Handling**: No sensitive data in errors\n- [ ] **Logging**: No sensitive data logged\n- [ ] **Dependencies**: Up to date, no vulnerabilities\n- [ ] **Row Level Security**: Enabled in Supabase\n- [ ] **CORS**: Properly configured\n- [ ] **File Uploads**: Validated (size, type)\n- [ ] **Wallet Signatures**: Verified (if blockchain)\n\n## Resources\n\n- [OWASP Top 10](https:\u002F\u002Fowasp.org\u002Fwww-project-top-ten\u002F)\n- [Next.js Security](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fsecurity)\n- [Supabase Security](https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fauth)\n- [Web Security Academy](https:\u002F\u002Fportswigger.net\u002Fweb-security)\n\n---\n\n**Remember**: Security is not optional. One vulnerability can compromise the entire platform. When in doubt, err on the side of caution.","# Security Review Skill\n\nThis skill ensures all code follows security best practices and identifies potential vulnerabilities.\n\n## When to Activate\n\n- Implementing authentication or authorization\n- Handling user input or file uploads\n- Creating new API endpoints\n- Working with secrets or credentials\n- Implementing payment features\n- Storing or transmitting sensitive data\n- Integrating third-party APIs\n\n## Security Checklist\n\n### 1. Secrets Management\n\n#### ❌ NEVER Do This\n```typescript\nconst apiKey = \"sk-proj-xxxxx\"  \u002F\u002F Hardcoded secret\nconst dbPassword = \"password123\" \u002F\u002F In source code\n```\n\n#### ✅ ALWAYS Do This\n```typescript\nconst apiKey = process.env.OPENAI_API_KEY\nconst dbUrl = process.env.DATABASE_URL\n\n\u002F\u002F Verify secrets exist\nif (!apiKey) {\n  throw new Error('OPENAI_API_KEY not configured')\n}\n```\n\n#### Verification Steps\n- [ ] No hardcoded API keys, tokens, or passwords\n- [ ] All secrets in environment variables\n- [ ] `.env.local` in .gitignore\n- [ ] No secrets in git history\n- [ ] Production secrets in hosting platform (Vercel, Railway)\n\n### 2. Input Validation\n\n#### Always Validate User Input\n```typescript\nimport { z } from 'zod'\n\n\u002F\u002F Define validation schema\nconst CreateUserSchema = z.object({\n  email: z.string().email(),\n  name: z.string().min(1).max(100),\n  age: z.number().int().min(0).max(150)\n})\n\n\u002F\u002F Validate before processing\nexport async function createUser(input: unknown) {\n  try {\n    const validated = CreateUserSchema.parse(input)\n    return await db.users.create(validated)\n  } catch (error) {\n    if (error instanceof z.ZodError) {\n      return { success: false, errors: error.errors }\n    }\n    throw error\n  }\n}\n```\n\n#### File Upload Validation\n```typescript\nfunction validateFileUpload(file: File) {\n  \u002F\u002F Size check (5MB max)\n  const maxSize = 5 * 1024 * 1024\n  if (file.size > maxSize) {\n    throw new Error('File too large (max 5MB)')\n  }\n\n  \u002F\u002F Type check\n  const allowedTypes = ['image\u002Fjpeg', 'image\u002Fpng', 'image\u002Fgif']\n  if (!allowedTypes.includes(file.type)) {\n    throw new Error('Invalid file type')\n  }\n\n  \u002F\u002F Extension check\n  const allowedExtensions = ['.jpg', '.jpeg', '.png', '.gif']\n  const extension = file.name.toLowerCase().match(\u002F\\.[^.]+$\u002F)?.[0]\n  if (!extension || !allowedExtensions.includes(extension)) {\n    throw new Error('Invalid file extension')\n  }\n\n  return true\n}\n```\n\n#### Verification Steps\n- [ ] All user inputs validated with schemas\n- [ ] File uploads restricted (size, type, extension)\n- [ ] No direct use of user input in queries\n- [ ] Whitelist validation (not blacklist)\n- [ ] Error messages don't leak sensitive info\n\n### 3. SQL Injection Prevention\n\n#### ❌ NEVER Concatenate SQL\n```typescript\n\u002F\u002F DANGEROUS - SQL Injection vulnerability\nconst query = `SELECT * FROM users WHERE email = '${userEmail}'`\nawait db.query(query)\n```\n\n#### ✅ ALWAYS Use Parameterized Queries\n```typescript\n\u002F\u002F Safe - parameterized query\nconst { data } = await supabase\n  .from('users')\n  .select('*')\n  .eq('email', userEmail)\n\n\u002F\u002F Or with raw SQL\nawait db.query(\n  'SELECT * FROM users WHERE email = $1',\n  [userEmail]\n)\n```\n\n#### Verification Steps\n- [ ] All database queries use parameterized queries\n- [ ] No string concatenation in SQL\n- [ ] ORM\u002Fquery builder used correctly\n- [ ] Supabase queries properly sanitized\n\n### 4. Authentication & Authorization\n\n#### JWT Token Handling\n```typescript\n\u002F\u002F ❌ WRONG: localStorage (vulnerable to XSS)\nlocalStorage.setItem('token', token)\n\n\u002F\u002F ✅ CORRECT: httpOnly cookies\nres.setHeader('Set-Cookie',\n  `token=${token}; HttpOnly; Secure; SameSite=Strict; Max-Age=3600`)\n```\n\n#### Authorization Checks\n```typescript\nexport async function deleteUser(userId: string, requesterId: string) {\n  \u002F\u002F ALWAYS verify authorization first\n  const requester = await db.users.findUnique({\n    where: { id: requesterId }\n  })\n\n  if (requester.role !== 'admin') {\n    return NextResponse.json(\n      { error: 'Unauthorized' },\n      { status: 403 }\n    )\n  }\n\n  \u002F\u002F Proceed with deletion\n  await db.users.delete({ where: { id: userId } })\n}\n```\n\n#### Row Level Security (Supabase)\n```sql\n-- Enable RLS on all tables\nALTER TABLE users ENABLE ROW LEVEL SECURITY;\n\n-- Users can only view their own data\nCREATE POLICY \"Users view own data\"\n  ON users FOR SELECT\n  USING (auth.uid() = id);\n\n-- Users can only update their own data\nCREATE POLICY \"Users update own data\"\n  ON users FOR UPDATE\n  USING (auth.uid() = id);\n```\n\n#### Verification Steps\n- [ ] Tokens stored in httpOnly cookies (not localStorage)\n- [ ] Authorization checks before sensitive operations\n- [ ] Row Level Security enabled in Supabase\n- [ ] Role-based access control implemented\n- [ ] Session management secure\n\n### 5. XSS Prevention\n\n#### Sanitize HTML\n```typescript\nimport DOMPurify from 'isomorphic-dompurify'\n\n\u002F\u002F ALWAYS sanitize user-provided HTML\nfunction renderUserContent(html: string) {\n  const clean = DOMPurify.sanitize(html, {\n    ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'p'],\n    ALLOWED_ATTR: []\n  })\n  return \u003Cdiv dangerouslySetInnerHTML={{ __html: clean }} \u002F>\n}\n```\n\n#### Content Security Policy\n```typescript\n\u002F\u002F next.config.js\nconst securityHeaders = [\n  {\n    key: 'Content-Security-Policy',\n    value: `\n      default-src 'self';\n      script-src 'self' 'unsafe-eval' 'unsafe-inline';\n      style-src 'self' 'unsafe-inline';\n      img-src 'self' data: https:;\n      font-src 'self';\n      connect-src 'self' https:\u002F\u002Fapi.example.com;\n    `.replace(\u002F\\s{2,}\u002Fg, ' ').trim()\n  }\n]\n```\n\n#### Verification Steps\n- [ ] User-provided HTML sanitized\n- [ ] CSP headers configured\n- [ ] No unvalidated dynamic content rendering\n- [ ] React's built-in XSS protection used\n\n### 6. CSRF Protection\n\n#### CSRF Tokens\n```typescript\nimport { csrf } from '@\u002Flib\u002Fcsrf'\n\nexport async function POST(request: Request) {\n  const token = request.headers.get('X-CSRF-Token')\n\n  if (!csrf.verify(token)) {\n    return NextResponse.json(\n      { error: 'Invalid CSRF token' },\n      { status: 403 }\n    )\n  }\n\n  \u002F\u002F Process request\n}\n```\n\n#### SameSite Cookies\n```typescript\nres.setHeader('Set-Cookie',\n  `session=${sessionId}; HttpOnly; Secure; SameSite=Strict`)\n```\n\n#### Verification Steps\n- [ ] CSRF tokens on state-changing operations\n- [ ] SameSite=Strict on all cookies\n- [ ] Double-submit cookie pattern implemented\n\n### 7. Rate Limiting\n\n#### API Rate Limiting\n```typescript\nimport rateLimit from 'express-rate-limit'\n\nconst limiter = rateLimit({\n  windowMs: 15 * 60 * 1000, \u002F\u002F 15 minutes\n  max: 100, \u002F\u002F 100 requests per window\n  message: 'Too many requests'\n})\n\n\u002F\u002F Apply to routes\napp.use('\u002Fapi\u002F', limiter)\n```\n\n#### Expensive Operations\n```typescript\n\u002F\u002F Aggressive rate limiting for searches\nconst searchLimiter = rateLimit({\n  windowMs: 60 * 1000, \u002F\u002F 1 minute\n  max: 10, \u002F\u002F 10 requests per minute\n  message: 'Too many search requests'\n})\n\napp.use('\u002Fapi\u002Fsearch', searchLimiter)\n```\n\n#### Verification Steps\n- [ ] Rate limiting on all API endpoints\n- [ ] Stricter limits on expensive operations\n- [ ] IP-based rate limiting\n- [ ] User-based rate limiting (authenticated)\n\n### 8. Sensitive Data Exposure\n\n#### Logging\n```typescript\n\u002F\u002F ❌ WRONG: Logging sensitive data\nconsole.log('User login:', { email, password })\nconsole.log('Payment:', { cardNumber, cvv })\n\n\u002F\u002F ✅ CORRECT: Redact sensitive data\nconsole.log('User login:', { email, userId })\nconsole.log('Payment:', { last4: card.last4, userId })\n```\n\n#### Error Messages\n```typescript\n\u002F\u002F ❌ WRONG: Exposing internal details\ncatch (error) {\n  return NextResponse.json(\n    { error: error.message, stack: error.stack },\n    { status: 500 }\n  )\n}\n\n\u002F\u002F ✅ CORRECT: Generic error messages\ncatch (error) {\n  console.error('Internal error:', error)\n  return NextResponse.json(\n    { error: 'An error occurred. Please try again.' },\n    { status: 500 }\n  )\n}\n```\n\n#### Verification Steps\n- [ ] No passwords, tokens, or secrets in logs\n- [ ] Error messages generic for users\n- [ ] Detailed errors only in server logs\n- [ ] No stack traces exposed to users\n\n### 9. Blockchain Security (Solana)\n\n#### Wallet Verification\n```typescript\nimport { verify } from '@solana\u002Fweb3.js'\n\nasync function verifyWalletOwnership(\n  publicKey: string,\n  signature: string,\n  message: string\n) {\n  try {\n    const isValid = verify(\n      Buffer.from(message),\n      Buffer.from(signature, 'base64'),\n      Buffer.from(publicKey, 'base64')\n    )\n    return isValid\n  } catch (error) {\n    return false\n  }\n}\n```\n\n#### Transaction Verification\n```typescript\nasync function verifyTransaction(transaction: Transaction) {\n  \u002F\u002F Verify recipient\n  if (transaction.to !== expectedRecipient) {\n    throw new Error('Invalid recipient')\n  }\n\n  \u002F\u002F Verify amount\n  if (transaction.amount > maxAmount) {\n    throw new Error('Amount exceeds limit')\n  }\n\n  \u002F\u002F Verify user has sufficient balance\n  const balance = await getBalance(transaction.from)\n  if (balance \u003C transaction.amount) {\n    throw new Error('Insufficient balance')\n  }\n\n  return true\n}\n```\n\n#### Verification Steps\n- [ ] Wallet signatures verified\n- [ ] Transaction details validated\n- [ ] Balance checks before transactions\n- [ ] No blind transaction signing\n\n### 10. Dependency Security\n\n#### Regular Updates\n```bash\n# Check for vulnerabilities\nnpm audit\n\n# Fix automatically fixable issues\nnpm audit fix\n\n# Update dependencies\nnpm update\n\n# Check for outdated packages\nnpm outdated\n```\n\n#### Lock Files\n```bash\n# ALWAYS commit lock files\ngit add package-lock.json\n\n# Use in CI\u002FCD for reproducible builds\nnpm ci  # Instead of npm install\n```\n\n#### Verification Steps\n- [ ] Dependencies up to date\n- [ ] No known vulnerabilities (npm audit clean)\n- [ ] Lock files committed\n- [ ] Dependabot enabled on GitHub\n- [ ] Regular security updates\n\n## Security Testing\n\n### Automated Security Tests\n```typescript\n\u002F\u002F Test authentication\ntest('requires authentication', async () => {\n  const response = await fetch('\u002Fapi\u002Fprotected')\n  expect(response.status).toBe(401)\n})\n\n\u002F\u002F Test authorization\ntest('requires admin role', async () => {\n  const response = await fetch('\u002Fapi\u002Fadmin', {\n    headers: { Authorization: `Bearer ${userToken}` }\n  })\n  expect(response.status).toBe(403)\n})\n\n\u002F\u002F Test input validation\ntest('rejects invalid input', async () => {\n  const response = await fetch('\u002Fapi\u002Fusers', {\n    method: 'POST',\n    body: JSON.stringify({ email: 'not-an-email' })\n  })\n  expect(response.status).toBe(400)\n})\n\n\u002F\u002F Test rate limiting\ntest('enforces rate limits', async () => {\n  const requests = Array(101).fill(null).map(() =>\n    fetch('\u002Fapi\u002Fendpoint')\n  )\n\n  const responses = await Promise.all(requests)\n  const tooManyRequests = responses.filter(r => r.status === 429)\n\n  expect(tooManyRequests.length).toBeGreaterThan(0)\n})\n```\n\n## Pre-Deployment Security Checklist\n\nBefore ANY production deployment:\n\n- [ ] **Secrets**: No hardcoded secrets, all in env vars\n- [ ] **Input Validation**: All user inputs validated\n- [ ] **SQL Injection**: All queries parameterized\n- [ ] **XSS**: User content sanitized\n- [ ] **CSRF**: Protection enabled\n- [ ] **Authentication**: Proper token handling\n- [ ] **Authorization**: Role checks in place\n- [ ] **Rate Limiting**: Enabled on all endpoints\n- [ ] **HTTPS**: Enforced in production\n- [ ] **Security Headers**: CSP, X-Frame-Options configured\n- [ ] **Error Handling**: No sensitive data in errors\n- [ ] **Logging**: No sensitive data logged\n- [ ] **Dependencies**: Up to date, no vulnerabilities\n- [ ] **Row Level Security**: Enabled in Supabase\n- [ ] **CORS**: Properly configured\n- [ ] **File Uploads**: Validated (size, type)\n- [ ] **Wallet Signatures**: Verified (if blockchain)\n\n## Resources\n\n- [OWASP Top 10](https:\u002F\u002Fowasp.org\u002Fwww-project-top-ten\u002F)\n- [Next.js Security](https:\u002F\u002Fnextjs.org\u002Fdocs\u002Fsecurity)\n- [Supabase Security](https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fauth)\n- [Web Security Academy](https:\u002F\u002Fportswigger.net\u002Fweb-security)\n\n---\n\n**Remember**: Security is not optional. One vulnerability can compromise the entire platform. When in doubt, err on the side of caution.",{"name":5,"author":52,"version":53,"description":7},"affaan-m","1.0","main","def8531e65114c0fca8fb8551c1871ee0eed705c","skills\u002Faiskillstore\u002Fmarketplace\u002Fsickn33\u002Fsecurity-review",24,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub","https:\u002F\u002Fskillshub.wtf","https:\u002F\u002Fgithub.com\u002FComeOnOliver","AI & Blockchain Engineer\r\n","2026-06-24 22:07:19",{"source":8,"skillName":5,"commands":64,"prompt":74,"zipAvailable":75},[65,68,71],{"tool":66,"command":67},"npx","npx skills add ComeOnOliver\u002Fskillshub --skill security-review",{"tool":69,"command":70},"bunx","bunx skills add ComeOnOliver\u002Fskillshub --skill security-review",{"tool":72,"command":73},"pnpm","pnpm dlx skills add ComeOnOliver\u002Fskillshub --skill security-review","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fsickn33\u002Fsecurity-review\u002FSKILL.md",true,[77],{"path":78,"resourceType":79,"resourceTypeDesc":80,"sizeBytes":81,"sourceHtmlUrl":82},"skill-report.json","REFERENCE","参考文档",9724,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faiskillstore\u002Fmarketplace\u002Fsickn33\u002Fsecurity-review\u002Fskill-report.json",[84,94,104,113,119,126],{"skillNo":85,"name":86,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":87,"categories":88,"keywords":90,"publishedAt":47},"01M6FKJN13GMG4KY57J3QD8GY5","model-hierarchy-skill","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzscole\u002Fmodel-hierarchy-skill\u002Fmodel-hierarchy-skill\u002FSKILL.md",[89],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[91,92,93],"model","model hierarchy","model hierarchy skill",{"skillNo":95,"name":96,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":97,"categories":98,"keywords":100,"publishedAt":47},"01M6FKJJJ6GCAMR4PPPRD12M5X","zoom-mcp","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-mcp\u002FSKILL.md",[99],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[101,102,103],"MCP","zoom","zoom mcp",{"skillNo":105,"name":106,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":107,"categories":108,"keywords":109,"publishedAt":47},"01M6FKJE3KYT3KPEZMEEHYKA6K","zoom-apps-sdk","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-apps-sdk\u002FSKILL.md",[],[110,111,112,102],"sdk","zoom apps sdk","apps",{"skillNo":114,"name":115,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":116,"categories":117,"keywords":118,"publishedAt":47},"01M6FKJ9EDH9Q5VWDF8HAJRSP0","windows","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwindows\u002FSKILL.md",[],[115],{"skillNo":120,"name":121,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":122,"categories":123,"keywords":125,"publishedAt":47},"01M6FKJ666BEEFC3AE9GJ72Q93","whiteboard","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwhiteboard\u002FSKILL.md",[124],{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},[121],{"skillNo":127,"name":128,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":129,"categories":130,"keywords":131,"publishedAt":47},"01M6FKJ21WFCDGTJQ2Q91T9DVW","websockets","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwebsockets\u002FSKILL.md",[],[128]]