Back to skills
SkillHub ClubAnalyze Data & AIFull StackData / AISecurity

security-checklist

Comprehensive security checklist covering OWASP Top 10, SQL injection, XSS, CSRF, authentication, authorization, secrets management, input validation, and security headers. Use when scanning for vulnerabilities, reviewing security, implementing authentication/authorization, or handling sensitive data.

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
6
Hot score
82
Updated
March 20, 2026
Overall rating
C3.3
Composite score
3.3
Best-practice grade
B73.6

Install command

npx @skill-hub/cli install webdevtodayjason-titanium-plugins-security-checklist

Repository

webdevtodayjason/titanium-plugins

Skill path: plugins/titanium-toolkit/skills/security-checklist

Comprehensive security checklist covering OWASP Top 10, SQL injection, XSS, CSRF, authentication, authorization, secrets management, input validation, and security headers. Use when scanning for vulnerabilities, reviewing security, implementing authentication/authorization, or handling sensitive data.

Open repository

Best for

Primary workflow: Analyze Data & AI.

Technical facets: Full Stack, Data / AI, Security.

Target audience: everyone.

License: Unknown.

Original source

Catalog source: SkillHub Club.

Repository owner: webdevtodayjason.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install security-checklist into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/webdevtodayjason/titanium-plugins before adding security-checklist to shared team environments
  • Use security-checklist for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: security-checklist
description: Comprehensive security checklist covering OWASP Top 10, SQL injection, XSS, CSRF, authentication, authorization, secrets management, input validation, and security headers. Use when scanning for vulnerabilities, reviewing security, implementing authentication/authorization, or handling sensitive data.
---

# Security Checklist

This skill provides comprehensive security guidance to protect your applications from common vulnerabilities and attacks.

## OWASP Top 10 Vulnerabilities

### 1. Broken Access Control

**What it is**: Users can access resources or perform actions they shouldn't be authorized for.

**Examples**:
- Accessing another user's data by changing URL parameter
- Elevating privileges (user → admin)
- Bypassing authentication checks

**Prevention**:
```typescript
// ❌ BAD - No authorization check
app.get('/api/users/:id', async (req, res) => {
  const user = await db.user.findUnique({ where: { id: req.params.id } });
  res.json(user);
});

// ✅ GOOD - Verify ownership or admin
app.get('/api/users/:id', authenticate, async (req, res) => {
  const requestedId = req.params.id;
  const currentUserId = req.user.id;
  const isAdmin = req.user.role === 'admin';

  if (requestedId !== currentUserId && !isAdmin) {
    return res.status(403).json({ error: 'Forbidden' });
  }

  const user = await db.user.findUnique({ where: { id: requestedId } });
  res.json(user);
});
```

**Checklist**:
- [ ] Enforce least privilege (deny by default)
- [ ] Verify user permissions on every request
- [ ] Never trust user IDs from client
- [ ] Log access control failures
- [ ] Use centralized access control logic

### 2. Cryptographic Failures

**What it is**: Exposing sensitive data due to weak or missing encryption.

**Examples**:
- Storing passwords in plain text
- Using weak hashing algorithms (MD5, SHA1)
- Transmitting sensitive data over HTTP

**Prevention**:
```typescript
import bcrypt from 'bcrypt';
import crypto from 'crypto';

// ✅ Password hashing
async function hashPassword(password: string): Promise<string> {
  const saltRounds = 12; // Increase for more security
  return await bcrypt.hash(password, saltRounds);
}

async function verifyPassword(password: string, hash: string): Promise<boolean> {
  return await bcrypt.compare(password, hash);
}

// ✅ Encrypt sensitive data at rest
function encrypt(text: string, key: string): string {
  const iv = crypto.randomBytes(16);
  const cipher = crypto.createCipheriv('aes-256-gcm', Buffer.from(key), iv);

  let encrypted = cipher.update(text, 'utf8', 'hex');
  encrypted += cipher.final('hex');

  const authTag = cipher.getAuthTag().toString('hex');
  return `${iv.toString('hex')}:${authTag}:${encrypted}`;
}
```

**Checklist**:
- [ ] Use HTTPS everywhere
- [ ] Hash passwords with bcrypt (12+ rounds)
- [ ] Encrypt sensitive data at rest
- [ ] Use strong encryption algorithms (AES-256)
- [ ] Properly manage encryption keys
- [ ] Never commit secrets to version control

### 3. Injection Attacks

**See SQL Injection Prevention section below**

### 4. Insecure Design

**What it is**: Security flaws in the application architecture.

**Examples**:
- Missing rate limiting
- Unrestricted file uploads
- Insecure password reset flows

**Prevention**:
```typescript
// ✅ Rate limiting
import rateLimit from 'express-rate-limit';

const loginLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 5, // 5 attempts
  message: 'Too many login attempts, please try again later',
});

app.post('/api/auth/login', loginLimiter, async (req, res) => {
  // Login logic
});

// ✅ Secure file upload
import multer from 'multer';

const upload = multer({
  limits: {
    fileSize: 5 * 1024 * 1024, // 5MB max
  },
  fileFilter: (req, file, cb) => {
    const allowedTypes = ['image/jpeg', 'image/png', 'image/gif'];
    if (!allowedTypes.includes(file.mimetype)) {
      return cb(new Error('Invalid file type'));
    }
    cb(null, true);
  },
});
```

**Checklist**:
- [ ] Implement rate limiting on all endpoints
- [ ] Validate file uploads (type, size, content)
- [ ] Use secure password reset flows (token-based)
- [ ] Implement account lockout after failed attempts
- [ ] Log and monitor security events

### 5. Security Misconfiguration

**What it is**: Insecure default configurations, unnecessary features enabled.

**Prevention**:
```typescript
// ✅ Secure Express configuration
import express from 'express';
import helmet from 'helmet';

const app = express();

// Security headers
app.use(helmet());

// Disable X-Powered-By
app.disable('x-powered-by');

// Environment-specific settings
if (process.env.NODE_ENV === 'production') {
  app.set('trust proxy', 1); // Trust first proxy
}

// CORS configuration
import cors from 'cors';

const corsOptions = {
  origin: process.env.ALLOWED_ORIGINS?.split(',') || [],
  credentials: true,
  optionsSuccessStatus: 200,
};

app.use(cors(corsOptions));
```

**Checklist**:
- [ ] Remove default accounts and passwords
- [ ] Disable directory listing
- [ ] Remove unnecessary features/endpoints
- [ ] Keep all software updated
- [ ] Use security headers (see section below)

### 6. Vulnerable and Outdated Components

**Prevention**:
```bash
# Check for vulnerabilities
npm audit

# Fix vulnerabilities
npm audit fix

# Update dependencies
npm update

# Use automated tools
npm install -g snyk
snyk test
snyk monitor
```

**Checklist**:
- [ ] Regularly update dependencies
- [ ] Monitor security advisories
- [ ] Remove unused dependencies
- [ ] Use dependabot or renovate
- [ ] Pin dependency versions in production

### 7. Identification and Authentication Failures

**See Authentication Best Practices section below**

### 8. Software and Data Integrity Failures

**Prevention**:
```typescript
// ✅ Verify package integrity
// package-lock.json ensures same versions

// ✅ Use Subresource Integrity (SRI) for CDN
<script
  src="https://cdn.example.com/library.js"
  integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxy9rx7HNQlGYl1kPzQho1wx4JwY8wC"
  crossorigin="anonymous"
></script>

// ✅ Validate data from external sources
import { z } from 'zod';

const ExternalDataSchema = z.object({
  id: z.string().uuid(),
  amount: z.number().positive(),
  status: z.enum(['pending', 'completed', 'failed']),
});

function processExternalData(data: unknown) {
  const validated = ExternalDataSchema.parse(data);
  // Now safe to use
}
```

### 9. Security Logging and Monitoring Failures

**Prevention**:
```typescript
import winston from 'winston';

const logger = winston.createLogger({
  level: 'info',
  format: winston.format.json(),
  transports: [
    new winston.transports.File({ filename: 'error.log', level: 'error' }),
    new winston.transports.File({ filename: 'combined.log' }),
  ],
});

// ✅ Log security events
logger.warn('Failed login attempt', {
  email: req.body.email,
  ip: req.ip,
  userAgent: req.get('user-agent'),
  timestamp: new Date().toISOString(),
});

logger.error('SQL injection attempt detected', {
  query: sanitizedQuery,
  ip: req.ip,
  endpoint: req.path,
});
```

**Checklist**:
- [ ] Log authentication events (login, logout, failures)
- [ ] Log authorization failures
- [ ] Log input validation failures
- [ ] Monitor for suspicious patterns
- [ ] Set up alerts for security events

### 10. Server-Side Request Forgery (SSRF)

**Prevention**:
```typescript
import validator from 'validator';

// ❌ BAD - Allows SSRF
app.post('/api/fetch-url', async (req, res) => {
  const url = req.body.url;
  const response = await fetch(url);
  res.json(await response.json());
});

// ✅ GOOD - Validate and whitelist
app.post('/api/fetch-url', async (req, res) => {
  const url = req.body.url;

  // Validate URL format
  if (!validator.isURL(url, { protocols: ['https'] })) {
    return res.status(400).json({ error: 'Invalid URL' });
  }

  // Whitelist allowed domains
  const allowedDomains = ['api.trusted-service.com'];
  const urlObj = new URL(url);

  if (!allowedDomains.includes(urlObj.hostname)) {
    return res.status(403).json({ error: 'Domain not allowed' });
  }

  // Block internal IPs
  const hostname = urlObj.hostname;
  if (
    hostname === 'localhost' ||
    hostname.startsWith('192.168.') ||
    hostname.startsWith('10.') ||
    hostname.startsWith('172.')
  ) {
    return res.status(403).json({ error: 'Internal IPs not allowed' });
  }

  const response = await fetch(url);
  res.json(await response.json());
});
```

## SQL Injection Prevention

### Parameterized Queries

```typescript
// ❌ VULNERABLE - String concatenation
const email = req.body.email;
const query = `SELECT * FROM users WHERE email = '${email}'`;
// Attacker can input: ' OR '1'='1
// Resulting query: SELECT * FROM users WHERE email = '' OR '1'='1'

// ✅ SAFE - Parameterized query
const email = req.body.email;
const query = 'SELECT * FROM users WHERE email = ?';
const user = await db.execute(query, [email]);

// ✅ SAFE - ORM (Prisma)
const user = await prisma.user.findUnique({
  where: { email: req.body.email },
});
```

### Input Validation

```typescript
import { z } from 'zod';

const UserQuerySchema = z.object({
  email: z.string().email(),
  id: z.string().uuid().optional(),
  name: z.string().max(100).optional(),
});

app.get('/api/users', async (req, res) => {
  try {
    const params = UserQuerySchema.parse(req.query);
    const users = await db.user.findMany({ where: params });
    res.json(users);
  } catch (error) {
    res.status(400).json({ error: 'Invalid query parameters' });
  }
});
```

## XSS (Cross-Site Scripting) Prevention

### Types of XSS

**1. Stored XSS**: Malicious script stored in database
**2. Reflected XSS**: Malicious script in URL/input reflected back
**3. DOM-based XSS**: Script manipulates DOM directly

### Prevention

```typescript
// ✅ React automatically escapes by default
function Comment({ text }: { text: string }) {
  return <p>{text}</p>; // Safe - React escapes HTML
}

// ❌ DANGEROUS - dangerouslySetInnerHTML
function Comment({ html }: { html: string }) {
  return <p dangerouslySetInnerHTML={{ __html: html }} />; // UNSAFE
}

// ✅ Sanitize HTML before rendering
import DOMPurify from 'dompurify';

function Comment({ html }: { html: string }) {
  const clean = DOMPurify.sanitize(html, {
    ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'a'],
    ALLOWED_ATTR: ['href'],
  });
  return <p dangerouslySetInnerHTML={{ __html: clean }} />;
}

// ✅ Server-side sanitization
import sanitizeHtml from 'sanitize-html';

app.post('/api/comments', async (req, res) => {
  const clean = sanitizeHtml(req.body.content, {
    allowedTags: ['b', 'i', 'em', 'strong', 'a'],
    allowedAttributes: {
      'a': ['href'],
    },
  });

  const comment = await db.comment.create({
    data: { content: clean },
  });

  res.json(comment);
});
```

### Content Security Policy (CSP)

```typescript
app.use(
  helmet.contentSecurityPolicy({
    directives: {
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'", 'https://trusted-cdn.com'],
      styleSrc: ["'self'", "'unsafe-inline'"],
      imgSrc: ["'self'", 'data:', 'https:'],
      connectSrc: ["'self'", 'https://api.example.com'],
      fontSrc: ["'self'", 'https://fonts.gstatic.com'],
      objectSrc: ["'none'"],
      upgradeInsecureRequests: [],
    },
  })
);
```

## CSRF (Cross-Site Request Forgery) Protection

### CSRF Token Pattern

```typescript
import csrf from 'csurf';
import cookieParser from 'cookie-parser';

const csrfProtection = csrf({ cookie: true });

app.use(cookieParser());

// Get CSRF token
app.get('/api/csrf-token', csrfProtection, (req, res) => {
  res.json({ csrfToken: req.csrfToken() });
});

// Protect state-changing endpoints
app.post('/api/users', csrfProtection, async (req, res) => {
  // Token automatically verified by middleware
  const user = await createUser(req.body);
  res.json(user);
});
```

### SameSite Cookies

```typescript
// ✅ Set SameSite attribute
res.cookie('sessionId', token, {
  httpOnly: true,
  secure: true, // HTTPS only
  sameSite: 'strict', // or 'lax'
  maxAge: 24 * 60 * 60 * 1000, // 24 hours
});
```

## Authentication Best Practices

### Password Requirements

```typescript
import { z } from 'zod';

const PasswordSchema = z
  .string()
  .min(12, 'Password must be at least 12 characters')
  .regex(/[A-Z]/, 'Password must contain uppercase letter')
  .regex(/[a-z]/, 'Password must contain lowercase letter')
  .regex(/[0-9]/, 'Password must contain number')
  .regex(/[^A-Za-z0-9]/, 'Password must contain special character');

// Check against common passwords
import { isCommonPassword } from 'common-passwords';

function validatePassword(password: string): boolean {
  if (isCommonPassword(password)) {
    throw new Error('Password is too common');
  }
  return true;
}
```

### JWT Best Practices

```typescript
import jwt from 'jsonwebtoken';

// ✅ Short-lived access tokens
function generateAccessToken(userId: string): string {
  return jwt.sign(
    { userId, type: 'access' },
    process.env.JWT_SECRET!,
    { expiresIn: '15m' } // Short expiry
  );
}

// ✅ Long-lived refresh tokens
function generateRefreshToken(userId: string): string {
  return jwt.sign(
    { userId, type: 'refresh' },
    process.env.JWT_REFRESH_SECRET!,
    { expiresIn: '7d' }
  );
}

// ✅ Verify token
function verifyAccessToken(token: string) {
  try {
    const payload = jwt.verify(token, process.env.JWT_SECRET!);
    if (payload.type !== 'access') {
      throw new Error('Invalid token type');
    }
    return payload;
  } catch (error) {
    throw new Error('Invalid token');
  }
}

// ✅ Blacklist tokens on logout
const tokenBlacklist = new Set<string>();

app.post('/api/auth/logout', authenticate, (req, res) => {
  const token = req.headers.authorization?.split(' ')[1];
  if (token) {
    tokenBlacklist.add(token);
  }
  res.json({ message: 'Logged out' });
});
```

### Multi-Factor Authentication (MFA)

```typescript
import speakeasy from 'speakeasy';
import QRCode from 'qrcode';

// Generate MFA secret
async function enableMFA(userId: string) {
  const secret = speakeasy.generateSecret({
    name: `MyApp (${user.email})`,
  });

  // Generate QR code
  const qrCode = await QRCode.toDataURL(secret.otpauth_url!);

  // Save secret to database (encrypted)
  await db.user.update({
    where: { id: userId },
    data: { mfaSecret: encrypt(secret.base32) },
  });

  return { secret: secret.base32, qrCode };
}

// Verify MFA token
function verifyMFAToken(secret: string, token: string): boolean {
  return speakeasy.totp.verify({
    secret,
    encoding: 'base32',
    token,
    window: 2, // Allow 2 time steps before/after
  });
}
```

## Authorization Patterns

### Role-Based Access Control (RBAC)

```typescript
enum Role {
  USER = 'user',
  MODERATOR = 'moderator',
  ADMIN = 'admin',
}

const permissions = {
  [Role.USER]: ['read:own', 'write:own'],
  [Role.MODERATOR]: ['read:own', 'write:own', 'read:all', 'delete:others'],
  [Role.ADMIN]: ['*'], // All permissions
};

function authorize(requiredPermission: string) {
  return (req: Request, res: Response, next: NextFunction) => {
    const userRole = req.user.role;
    const userPermissions = permissions[userRole];

    if (!userPermissions.includes('*') && !userPermissions.includes(requiredPermission)) {
      return res.status(403).json({ error: 'Forbidden' });
    }

    next();
  };
}

// Usage
app.delete('/api/posts/:id', authenticate, authorize('delete:others'), async (req, res) => {
  await deletePost(req.params.id);
  res.json({ success: true });
});
```

### Attribute-Based Access Control (ABAC)

```typescript
interface AccessPolicy {
  subject: { role: string; department?: string };
  resource: { type: string; owner?: string };
  action: string;
  conditions?: Record<string, any>;
}

function checkAccess(
  user: User,
  resource: Resource,
  action: string
): boolean {
  // User can access own resources
  if (resource.ownerId === user.id) {
    return true;
  }

  // Admins can access everything
  if (user.role === 'admin') {
    return true;
  }

  // Department managers can access department resources
  if (
    user.role === 'manager' &&
    user.department === resource.department
  ) {
    return true;
  }

  return false;
}
```

## Secrets Management

### Environment Variables

```typescript
// ✅ .env file (NOT committed to git)
DATABASE_URL=postgresql://user:password@localhost:5432/db
JWT_SECRET=super-secret-key-change-in-production
API_KEY=sk_live_abc123xyz

// ✅ .env.example (committed to git)
DATABASE_URL=
JWT_SECRET=
API_KEY=

// ✅ Load environment variables
import dotenv from 'dotenv';
dotenv.config();

// ✅ Validate required env vars
const requiredEnvVars = ['DATABASE_URL', 'JWT_SECRET', 'API_KEY'];

for (const envVar of requiredEnvVars) {
  if (!process.env[envVar]) {
    throw new Error(`Missing required environment variable: ${envVar}`);
  }
}
```

### Key Vault Integration

```typescript
// ✅ AWS Secrets Manager
import { SecretsManager } from '@aws-sdk/client-secrets-manager';

async function getSecret(secretName: string): Promise<string> {
  const client = new SecretsManager({ region: 'us-east-1' });
  const response = await client.getSecretValue({ SecretId: secretName });
  return response.SecretString!;
}

// ✅ Azure Key Vault
import { SecretClient } from '@azure/keyvault-secrets';

async function getAzureSecret(secretName: string): Promise<string> {
  const client = new SecretClient(vaultUrl, credential);
  const secret = await client.getSecret(secretName);
  return secret.value!;
}
```

## Input Validation

### Validation Schema

```typescript
import { z } from 'zod';

const CreateUserSchema = z.object({
  email: z.string().email().max(255),
  password: z.string().min(12).max(100),
  name: z.string().min(1).max(100),
  age: z.number().int().min(18).max(120),
  phone: z.string().regex(/^\+?[1-9]\d{1,14}$/).optional(),
  website: z.string().url().optional(),
});

app.post('/api/users', async (req, res) => {
  try {
    const data = CreateUserSchema.parse(req.body);
    const user = await createUser(data);
    res.json(user);
  } catch (error) {
    if (error instanceof z.ZodError) {
      return res.status(400).json({
        error: 'Validation failed',
        details: error.errors,
      });
    }
    throw error;
  }
});
```

### Sanitization

```typescript
import validator from 'validator';

function sanitizeInput(input: string): string {
  // Trim whitespace
  let clean = input.trim();

  // Escape HTML entities
  clean = validator.escape(clean);

  // Remove null bytes
  clean = clean.replace(/\0/g, '');

  return clean;
}
```

## Security Headers

### Comprehensive Header Configuration

```typescript
import helmet from 'helmet';

app.use(
  helmet({
    // Content Security Policy
    contentSecurityPolicy: {
      directives: {
        defaultSrc: ["'self'"],
        scriptSrc: ["'self'", "'unsafe-inline'"],
        styleSrc: ["'self'", "'unsafe-inline'"],
        imgSrc: ["'self'", 'data:', 'https:'],
      },
    },

    // HTTP Strict Transport Security
    hsts: {
      maxAge: 31536000, // 1 year
      includeSubDomains: true,
      preload: true,
    },

    // X-Frame-Options
    frameguard: {
      action: 'deny', // or 'sameorigin'
    },

    // X-Content-Type-Options
    noSniff: true,

    // X-XSS-Protection
    xssFilter: true,

    // Referrer-Policy
    referrerPolicy: {
      policy: 'strict-origin-when-cross-origin',
    },
  })
);

// Additional custom headers
app.use((req, res, next) => {
  res.setHeader('X-Content-Type-Options', 'nosniff');
  res.setHeader('X-Frame-Options', 'DENY');
  res.setHeader('X-XSS-Protection', '1; mode=block');
  res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload');
  next();
});
```

## Rate Limiting

### Endpoint-Specific Rate Limits

```typescript
import rateLimit from 'express-rate-limit';

// Strict limit for authentication
const authLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 5,
  message: 'Too many authentication attempts',
  standardHeaders: true,
  legacyHeaders: false,
});

// Moderate limit for API endpoints
const apiLimiter = rateLimit({
  windowMs: 1 * 60 * 1000, // 1 minute
  max: 60,
  message: 'Too many requests',
});

// Apply rate limiters
app.post('/api/auth/login', authLimiter, loginHandler);
app.post('/api/auth/register', authLimiter, registerHandler);
app.use('/api', apiLimiter);
```

## Logging Security Events

### What NOT to Log

**❌ Never log**:
- Passwords (plain or hashed)
- Credit card numbers
- Social Security numbers
- API keys/secrets
- Session tokens
- Personally identifiable information (PII) in clear text

```typescript
// ❌ BAD - Logs sensitive data
logger.info('User login', { email, password });

// ✅ GOOD - Logs non-sensitive data
logger.info('User login attempt', {
  email,
  ip: req.ip,
  userAgent: req.get('user-agent'),
  success: true,
});
```

### Security Event Logging

```typescript
enum SecurityEvent {
  LOGIN_SUCCESS = 'login_success',
  LOGIN_FAILURE = 'login_failure',
  PASSWORD_RESET = 'password_reset',
  ACCOUNT_LOCKED = 'account_locked',
  PERMISSION_DENIED = 'permission_denied',
  SUSPICIOUS_ACTIVITY = 'suspicious_activity',
}

function logSecurityEvent(
  event: SecurityEvent,
  userId: string | null,
  metadata: Record<string, any>
) {
  logger.warn({
    type: 'security',
    event,
    userId,
    timestamp: new Date().toISOString(),
    ip: metadata.ip,
    userAgent: metadata.userAgent,
    ...metadata,
  });
}
```

## Dependency Scanning

### Automated Security Scanning

```yaml
# .github/workflows/security.yml
name: Security Scan

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]
  schedule:
    - cron: '0 0 * * 0' # Weekly

jobs:
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Run npm audit
        run: npm audit --audit-level=high

      - name: Run Snyk security scan
        uses: snyk/actions/node@master
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

      - name: Run Trivy vulnerability scanner
        uses: aquasecurity/trivy-action@master
        with:
          scan-type: 'fs'
          scan-ref: '.'
```

## Security Checklist Summary

### Pre-Deployment Checklist

**Authentication & Authorization**:
- [ ] Passwords hashed with bcrypt (12+ rounds)
- [ ] JWT tokens have short expiry (15 minutes)
- [ ] Refresh tokens properly implemented
- [ ] MFA available for sensitive accounts
- [ ] Authorization checks on all endpoints
- [ ] Rate limiting on auth endpoints

**Input Validation**:
- [ ] All inputs validated with schemas
- [ ] SQL queries use parameterized statements
- [ ] File uploads restricted (type, size)
- [ ] HTML content sanitized
- [ ] No eval() or Function() with user input

**Security Headers**:
- [ ] HTTPS enforced
- [ ] CSP configured
- [ ] HSTS enabled
- [ ] X-Frame-Options set
- [ ] X-Content-Type-Options set

**Data Protection**:
- [ ] Sensitive data encrypted at rest
- [ ] Secrets stored in environment variables/vault
- [ ] No secrets in version control
- [ ] PII handled according to regulations
- [ ] Database backups encrypted

**Logging & Monitoring**:
- [ ] Security events logged
- [ ] No sensitive data in logs
- [ ] Failed auth attempts monitored
- [ ] Unusual activity alerts configured
- [ ] Log retention policy defined

**Dependencies**:
- [ ] All dependencies up to date
- [ ] No known vulnerabilities (npm audit)
- [ ] Dependabot/Renovate configured
- [ ] Unused dependencies removed

**API Security**:
- [ ] CORS properly configured
- [ ] CSRF protection enabled
- [ ] Rate limiting implemented
- [ ] API keys rotated regularly
- [ ] Endpoints documented

## When to Use This Skill

Use this skill when:
- Conducting security audits
- Implementing authentication/authorization
- Reviewing code for vulnerabilities
- Setting up new projects
- Handling sensitive data
- Responding to security incidents
- Training team on security
- Preparing for compliance audits
- Deploying to production
- Integrating third-party services

---

**Remember**: Security is not a one-time task but an ongoing process. Stay informed about new vulnerabilities, keep dependencies updated, and always assume malicious actors are trying to exploit your application.
security-checklist | SkillHub