AgentSkillsCN

security-review

面向Web应用的全方位安全评审技能。涵盖身份认证、权限控制、密钥管理、防范注入攻击、输入验证,以及OWASP十大常见漏洞。

SKILL.md
--- frontmatter
name: security-review
description: Comprehensive security review skill for web applications. Covers authentication, authorization, secret management, injection prevention, input validation, and OWASP Top 10 vulnerabilities.

Security Review Skill

A comprehensive security review checklist for web applications, covering common vulnerabilities and best practices.

Activation Conditions

  • When implementing authentication/authorization features
  • When handling user input
  • When creating new API endpoints
  • When working with secrets/credentials
  • When implementing payment or sensitive features
  • When handling file uploads
  • Before deploying to production

Security Checklist

1. Secret Management

Never Do This

javascript
// Hardcoded secrets
const apiKey = "sk-proj-xxxxx"
const dbPassword = "password123"
const jwtSecret = "super-secret-key"

Correct Approach

javascript
// Use environment variables
const apiKey = process.env.API_KEY;
const dbUrl = process.env.DATABASE_URL;

// Validate secret existence at startup
if (!apiKey) {
  throw new Error('API_KEY not configured');
}

Production Secret Management

Use a dedicated secret management service:

  • AWS Secrets Manager / SSM Parameter Store
  • Google Cloud Secret Manager
  • Azure Key Vault
  • HashiCorp Vault
  • Doppler, 1Password Secrets, etc.

Verification Items

  • No hardcoded API keys, tokens, or passwords
  • All secrets use environment variables or secret manager
  • .env* files are in .gitignore
  • No secrets in git history
  • Production secrets stored in secure vault

2. Input Validation

Server-Side Validation (Required)

javascript
// Always validate on the server side
function validateUserInput(input) {
  // Type validation
  if (typeof input.email !== 'string') {
    throw new ValidationError('Email must be a string');
  }

  // Format validation
  if (!isValidEmail(input.email)) {
    throw new ValidationError('Invalid email format');
  }

  // Length limits
  if (input.name.length > 100) {
    throw new ValidationError('Name too long');
  }

  // Range validation
  if (input.age < 0 || input.age > 150) {
    throw new ValidationError('Invalid age');
  }

  // Array size limits
  if (input.items.length > 100) {
    throw new ValidationError('Too many items');
  }
}

Common Validation Rules

Input TypeValidation
StringType check, min/max length, format (regex)
NumberType check, min/max value, integer check
EmailFormat validation, length limit
URLFormat validation, allowed protocols
ArrayType of elements, max size
FileSize limit, allowed types, extension check

Verification Items

  • All user inputs validated on server side
  • String length limits applied
  • Number range limits applied
  • Array size limits applied
  • Error messages don't expose sensitive info

3. SQL Injection Prevention

Safe: Parameterized Queries

javascript
// Using parameterized queries (prepared statements)
const user = await db.query(
  'SELECT * FROM users WHERE id = $1',
  [userId]
);

// Using ORM query builders
const users = await db.users.findMany({
  where: { status: userStatus }
});

Dangerous: String Concatenation

javascript
// NEVER do this - SQL injection vulnerability
const query = `SELECT * FROM users WHERE id = ${userId}`;
const query = "SELECT * FROM users WHERE name = '" + userName + "'";

Dynamic Queries (Safe Approach)

javascript
// Building dynamic conditions safely
const conditions = [];
const params = [];

if (filter.status) {
  conditions.push('status = $' + (params.length + 1));
  params.push(filter.status);
}

if (filter.category) {
  conditions.push('category = $' + (params.length + 1));
  params.push(filter.category);
}

const whereClause = conditions.length > 0
  ? 'WHERE ' + conditions.join(' AND ')
  : '';

await db.query(`SELECT * FROM products ${whereClause}`, params);

Verification Items

  • All queries use parameterized statements
  • ORM query builders used where available
  • No string concatenation for SQL queries
  • Dynamic queries still use parameters

4. Authentication & Authorization

Token Validation

javascript
// JWT validation essentials
function validateToken(token) {
  // 1. Verify signature
  const payload = jwt.verify(token, SECRET_KEY);

  // 2. Check expiration
  if (payload.exp < Date.now() / 1000) {
    throw new Error('Token expired');
  }

  // 3. Validate issuer/audience if applicable
  if (payload.iss !== EXPECTED_ISSUER) {
    throw new Error('Invalid issuer');
  }

  return payload;
}

Authorization Checks

javascript
// Resource-level authorization
async function getResource(resourceId, currentUser) {
  const resource = await db.resources.findById(resourceId);

  if (!resource) {
    throw new NotFoundError();
  }

  // Check ownership or permission
  if (resource.ownerId !== currentUser.id && !currentUser.isAdmin) {
    throw new ForbiddenError();
  }

  return resource;
}

// Role-based access control
function requireRole(allowedRoles) {
  return (req, res, next) => {
    if (!allowedRoles.includes(req.user.role)) {
      return res.status(403).json({ error: 'Forbidden' });
    }
    next();
  };
}

Multi-Tenancy Data Isolation

javascript
// Always filter by tenant/organization
async function getProducts(filters, currentUser) {
  return db.products.findMany({
    where: {
      ...filters,
      // Force tenant isolation
      organizationId: currentUser.organizationId
    }
  });
}

Verification Items

  • Authentication applied to all protected endpoints
  • Token signature and expiration verified
  • Authorization checked for each resource access
  • Multi-tenant data properly isolated
  • Session timeout implemented
  • Password requirements enforced

5. Rate Limiting

Implementation Guidelines

javascript
// Global rate limiting
// Example: 100 requests per minute per IP

// Stricter limits for sensitive endpoints
// - Login: 5 attempts per minute
// - Password reset: 3 requests per hour
// - SMS/Email verification: 3 requests per minute
// - File upload: 10 per hour
// - Search/expensive operations: 30 per minute

Verification Items

  • Global rate limiting configured
  • Stricter limits on auth endpoints
  • Limits on expensive operations
  • IP-based and user-based limiting
  • Proper 429 response with Retry-After header

6. Sensitive Data Exposure Prevention

Logging Best Practices

javascript
// WRONG - Logging sensitive data
console.log('User login:', { email, password });
console.log('Payment:', { cardNumber, cvv });
console.log('Request:', req.headers.authorization);

// CORRECT - Redact sensitive fields
console.log('User login:', { email, userId });
console.log('Payment:', { last4: card.slice(-4), userId });
console.log('Request:', { method: req.method, path: req.path });

Error Response Handling

javascript
// WRONG - Exposing internal details
res.status(500).json({
  error: err.message,
  stack: err.stack,
  query: failedQuery
});

// CORRECT - Generic error to client, detailed log server-side
logger.error('Database error', { error: err, query: failedQuery });
res.status(500).json({
  error: 'An internal error occurred',
  requestId: req.id  // For support reference
});

Response Data Filtering

javascript
// Define what to expose explicitly
function toUserResponse(user) {
  return {
    id: user.id,
    name: user.name,
    email: user.email,
    // Exclude: password, passwordHash, internalId, etc.
  };
}

Verification Items

  • No passwords/tokens/secrets in logs
  • No stack traces in error responses
  • Response DTOs exclude sensitive fields
  • Debug endpoints disabled in production

7. XSS (Cross-Site Scripting) Prevention

Output Encoding

javascript
// Always encode user content before rendering
const safeHtml = escapeHtml(userInput);

// Use framework's built-in protection
// React: automatically escapes by default
// Vue: use {{ }} not v-html
// Angular: automatically sanitizes

// Be careful with dangerouslySetInnerHTML / v-html
// Only use with sanitized content

Content Security Policy

javascript
// Set CSP headers
res.setHeader('Content-Security-Policy',
  "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'"
);

Verification Items

  • User content properly escaped
  • CSP headers configured
  • No inline event handlers with user data
  • HttpOnly flag on sensitive cookies

8. File Upload Security

javascript
function validateFileUpload(file) {
  const allowedMimeTypes = ['image/jpeg', 'image/png', 'image/gif'];
  const maxFileSize = 5 * 1024 * 1024; // 5MB
  const allowedExtensions = ['.jpg', '.jpeg', '.png', '.gif'];

  // Size validation
  if (file.size > maxFileSize) {
    throw new Error('File too large');
  }

  // MIME type validation
  if (!allowedMimeTypes.includes(file.mimetype)) {
    throw new Error('Invalid file type');
  }

  // Extension validation (prevent MIME spoofing)
  const ext = path.extname(file.originalname).toLowerCase();
  if (!allowedExtensions.includes(ext)) {
    throw new Error('Invalid file extension');
  }

  // Generate safe filename
  const safeFilename = `${uuid()}_${Date.now()}${ext}`;

  return safeFilename;
}

Verification Items

  • File size limits enforced
  • MIME type validated
  • File extension validated
  • Filename sanitized
  • Files stored outside web root
  • Antivirus scanning for uploads (if applicable)

9. HTTPS and Transport Security

javascript
// Force HTTPS in production
if (process.env.NODE_ENV === 'production') {
  app.use((req, res, next) => {
    if (req.header('x-forwarded-proto') !== 'https') {
      return res.redirect(`https://${req.header('host')}${req.url}`);
    }
    next();
  });
}

// Security headers
app.use(helmet());  // or set manually:
res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('X-XSS-Protection', '1; mode=block');

Verification Items

  • HTTPS enforced in production
  • HSTS header configured
  • Secure flag on cookies
  • Security headers applied

10. Dependency Security

bash
# Check for known vulnerabilities
npm audit
yarn audit
pip-audit
bundle audit

# Keep dependencies updated
npm update
yarn upgrade

Verification Items

  • No known vulnerabilities in dependencies
  • Dependencies regularly updated
  • Lock files committed
  • Automated vulnerability scanning in CI

Pre-Deployment Security Checklist

Before every production deployment:

  • Secrets: No hardcoded secrets, using secret manager
  • Input Validation: All user inputs validated server-side
  • SQL Injection: Parameterized queries only
  • Authentication: Token validation on protected endpoints
  • Authorization: Resource-level access control
  • Rate Limiting: Applied to all endpoints
  • HTTPS: Enforced in production
  • Error Handling: No sensitive info exposed
  • Logging: No secrets/passwords in logs
  • Dependencies: No known vulnerabilities
  • Debug Code: console.log/debugger removed

Security Scan Commands

bash
# Search for hardcoded secrets
grep -rn "api_key\|apikey\|secret\|password\s*=" --include="*.js" --include="*.ts" src/
grep -rn "sk-\|pk_\|Bearer " --include="*.js" --include="*.ts" src/

# Search for console.log (excluding tests)
grep -rn "console.log" --include="*.js" --include="*.ts" src/ | grep -v ".test.\|.spec."

# Check for .env files in git
git ls-files | grep -E "\.env"

# Dependency audit
npm audit

Related Resources

Related Agents

  • security-reviewer: Deep security analysis agent
  • code-reviewer: General code quality review

Security is not optional. When in doubt, always choose the safer approach.