Claude Code Plugins

Community-maintained marketplace

Feedback

Universal security checklist based on OWASP Top 10 for ANY project type or language. Use before deploying to production, handling sensitive data, or processing user input.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name security-first
description Universal security checklist based on OWASP Top 10 for ANY project type or language. Use before deploying to production, handling sensitive data, or processing user input.

Security First - Shield Your Code

🎯 When to Use This Skill

Use BEFORE:

  • Deploying to production
  • Handling sensitive data
  • Opening API endpoints
  • Processing user input
  • Storing passwords
  • Accepting file uploads
  • Going live with payments

⚡ 5-Minute Security Audit

WITH MCP (Security Scanner):

"Run complete security audit on my codebase"
"Find and fix all OWASP Top 10 vulnerabilities"

WITHOUT MCP - Quick Scan:

# 1. Find hardcoded secrets (CRITICAL!)
grep -r "password\|secret\|token\|api[_-]key" --include="*.js" --include="*.env" | grep -v ".example"

# 2. Check for SQL injection
grep -r "query.*\+\|query.*\$\{" --include="*.js"

# 3. Find eval/exec usage
grep -r "eval(\|exec(\|Function(" --include="*.js"

# 4. Check dependencies
npm audit  # or pip check, bundle audit

# 5. Find unvalidated input
grep -r "req.body\|req.query\|req.params" --include="*.js" | grep -v "validate\|sanitize"

🛡️ OWASP Top 10 Checklist (2024)

1. Injection (SQL, NoSQL, Command) 💉

Vulnerable Code:

// ❌ NEVER DO THIS
const query = `SELECT * FROM users WHERE id = ${req.params.id}`;
db.query(query); // SQL Injection!

// ❌ Command injection
exec(`ping ${userInput}`); // Dangerous!

Secure Code:

// ✅ Parameterized queries
const query = 'SELECT * FROM users WHERE id = ?';
db.query(query, [req.params.id]);

// ✅ For MongoDB
User.findOne({ _id: sanitize(req.params.id) });

// ✅ Command execution
const { spawn } = require('child_process');
spawn('ping', [userInput], { shell: false });

2. Broken Authentication 🔐

Security Checklist:

// ✅ Strong password requirements
function validatePassword(password) {
  const requirements = {
    minLength: 12,
    hasUpperCase: /[A-Z]/.test(password),
    hasLowerCase: /[a-z]/.test(password),
    hasNumbers: /\d/.test(password),
    hasSpecialChar: /[!@#$%^&*]/.test(password),
    notCommon: !commonPasswords.includes(password),
  };

  return Object.values(requirements).every(req => req);
}

// ✅ Secure session management
app.use(
  session({
    secret: process.env.SESSION_SECRET, // From environment
    resave: false,
    saveUninitialized: false,
    cookie: {
      secure: true, // HTTPS only
      httpOnly: true, // No JS access
      maxAge: 3600000, // 1 hour
      sameSite: 'strict', // CSRF protection
    },
  })
);

// ✅ Rate limiting
const rateLimit = require('express-rate-limit');
const loginLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 5, // 5 attempts
  message: 'Too many login attempts',
});
app.post('/login', loginLimiter, loginHandler);

3. Sensitive Data Exposure 🔒

Never Store in Code:

// ❌ WRONG
const API_KEY = 'sk_live_abcd1234';
const DB_PASSWORD = 'admin123';

// ✅ CORRECT - Use environment variables
const API_KEY = process.env.API_KEY;
const DB_PASSWORD = process.env.DB_PASSWORD;

// ✅ Use .env file (never commit!)
require('dotenv').config();

// ✅ Encrypt sensitive data at rest
const crypto = require('crypto');
const algorithm = 'aes-256-gcm';

function encrypt(text) {
  const key = Buffer.from(process.env.ENCRYPTION_KEY, 'hex');
  const iv = crypto.randomBytes(16);
  const cipher = crypto.createCipheriv(algorithm, key, iv);

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

  const authTag = cipher.getAuthTag();

  return {
    encrypted,
    iv: iv.toString('hex'),
    authTag: authTag.toString('hex'),
  };
}

4. XML External Entities (XXE) 📄

// ❌ Vulnerable XML parsing
const libxmljs = require('libxmljs');
const doc = libxmljs.parseXml(userInput); // XXE vulnerable!

// ✅ Safe XML parsing
const parser = new DOMParser();
const doc = parser.parseFromString(userInput, 'text/xml');

// ✅ Or disable external entities
const options = {
  xmlMode: true,
  recognizeSelfClosing: true,
  decodeEntities: false, // Disable entity expansion
};

5. Broken Access Control 🚪

// ❌ No authorization check
app.get('/api/user/:id', (req, res) => {
  const user = User.findById(req.params.id);
  res.json(user); // Anyone can see any user!
});

// ✅ Proper authorization
app.get('/api/user/:id', authenticate, (req, res) => {
  // Check if user can access this resource
  if (req.user.id !== req.params.id && !req.user.isAdmin) {
    return res.status(403).json({ error: 'Forbidden' });
  }

  const user = User.findById(req.params.id);
  res.json(user);
});

// ✅ Role-based access control (RBAC)
const authorize = roles => {
  return (req, res, next) => {
    if (!roles.includes(req.user.role)) {
      return res.status(403).json({ error: 'Insufficient permissions' });
    }
    next();
  };
};

app.delete('/api/users/:id', authenticate, authorize(['admin']), deleteUser);

6. Security Misconfiguration ⚙️

# ✅ Security headers
app.use(helmet({
  contentSecurityPolicy: {
    directives: {
      defaultSrc: ["'self'"],
      styleSrc: ["'self'", "'unsafe-inline'"],
      scriptSrc: ["'self'"],
      imgSrc: ["'self'", "data:", "https:"],
    },
  },
  hsts: {
    maxAge: 31536000,
    includeSubDomains: true,
    preload: true
  }
}));

# ✅ Disable unnecessary features
app.disable('x-powered-by');  # Hide Express

# ✅ Error handling (don't leak info)
app.use((err, req, res, next) => {
  console.error(err.stack);  // Log full error

  // Send generic message to client
  res.status(500).json({
    error: 'Internal server error',
    // Don't send: err.stack or err.message
  });
});

7. Cross-Site Scripting (XSS) 🎭

// ❌ Vulnerable to XSS
app.get('/search', (req, res) => {
  res.send(`Results for: ${req.query.q}`);  // XSS!
});

// ✅ Sanitize output
const DOMPurify = require('isomorphic-dompurify');

app.get('/search', (req, res) => {
  const clean = DOMPurify.sanitize(req.query.q);
  res.send(`Results for: ${clean}`);
});

// ✅ React automatically escapes
<div>{userInput}</div>  // Safe

// ❌ But dangerouslySetInnerHTML is dangerous
<div dangerouslySetInnerHTML={{__html: userInput}} />  // XSS!

// ✅ Content-Type headers
res.set('Content-Type', 'text/plain');  // Not HTML
res.set('X-Content-Type-Options', 'nosniff');

8. Insecure Deserialization 📦

// ❌ Dangerous deserialization
const userData = JSON.parse(req.body.data);
eval(userData.code); // Code execution!

// ✅ Validate before deserializing
const schema = Joi.object({
  name: Joi.string().required(),
  age: Joi.number().min(0).max(120),
});

const { error, value } = schema.validate(JSON.parse(req.body.data));
if (error) return res.status(400).json({ error });

// ✅ Never deserialize untrusted data into code
// Use JSON.parse() only, never eval() or Function()

9. Components with Known Vulnerabilities 📚

# ✅ Regular dependency checks
# Add to package.json
{
  "scripts": {
    "security": "npm audit && npm outdated",
    "security:fix": "npm audit fix",
    "preinstall": "npm audit"
  }
}

# ✅ Automated updates (GitHub)
# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "daily"
    open-pull-requests-limit: 10

10. Insufficient Logging & Monitoring 📊

// ✅ Comprehensive logging
const winston = require('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
function logSecurityEvent(event, user, details) {
  logger.warn({
    type: 'SECURITY',
    event,
    user: user?.id,
    ip: user?.ip,
    timestamp: new Date().toISOString(),
    details,
  });
}

// Usage
logSecurityEvent('FAILED_LOGIN', req.user, {
  attempts: failedAttempts,
  ip: req.ip,
});

logSecurityEvent('UNAUTHORIZED_ACCESS', req.user, {
  resource: req.path,
  method: req.method,
});

🔐 Password Security

// ✅ NEVER store plain text passwords!
const bcrypt = require('bcrypt');

// Hashing
async function hashPassword(password) {
  const saltRounds = 12; // Higher = more secure but slower
  return await bcrypt.hash(password, saltRounds);
}

// Verifying
async function verifyPassword(password, hash) {
  return await bcrypt.compare(password, hash);
}

// ✅ Password reset flow
async function resetPassword(email) {
  // 1. Generate secure token
  const token = crypto.randomBytes(32).toString('hex');

  // 2. Store hashed token with expiry
  await storeResetToken(email, hashToken(token), Date.now() + 3600000);

  // 3. Send unhashed token via email
  await sendEmail(email, `Reset link: ${BASE_URL}/reset?token=${token}`);
}

🚪 API Security

// ✅ API Security Checklist
const apiSecurity = {
  // 1. Authentication
  authentication: 'Bearer token (JWT)',

  // 2. Rate limiting
  rateLimit: {
    windowMs: 15 * 60 * 1000, // 15 minutes
    max: 100, // requests per window
  },

  // 3. Input validation
  validateInput: (data, schema) => {
    return Joi.validate(data, schema);
  },

  // 4. CORS configuration
  cors: {
    origin: process.env.ALLOWED_ORIGINS?.split(',') || false,
    credentials: true,
  },

  // 5. API versioning
  versioning: '/api/v1/',

  // 6. Request size limit
  bodyLimit: '10mb',

  // 7. Timeout
  timeout: 30000, // 30 seconds

  // 8. HTTPS only
  httpsOnly: true,
};

📋 Security Deployment Checklist

## Pre-Deployment Security Checklist

### Code Security

- [ ] No hardcoded secrets
- [ ] All inputs validated
- [ ] SQL queries parameterized
- [ ] XSS protection enabled
- [ ] CSRF tokens implemented
- [ ] Authentication required
- [ ] Authorization checks present
- [ ] Rate limiting configured

### Dependencies

- [ ] `npm audit` shows 0 vulnerabilities
- [ ] All packages from trusted sources
- [ ] Lock file committed
- [ ] Licenses reviewed

### Configuration

- [ ] Environment variables used
- [ ] HTTPS enforced
- [ ] Security headers set
- [ ] CORS configured
- [ ] Error messages sanitized
- [ ] Debug mode disabled
- [ ] Source maps disabled in production

### Data Protection

- [ ] Passwords hashed (bcrypt)
- [ ] Sensitive data encrypted
- [ ] PII fields marked
- [ ] Data retention policy set
- [ ] Backups encrypted

### Infrastructure

- [ ] Firewall rules configured
- [ ] Ports minimized
- [ ] SSH keys only (no passwords)
- [ ] Monitoring enabled
- [ ] Logging configured
- [ ] Incident response plan ready

🚨 Incident Response Plan

// security-incident.js
class SecurityIncident {
  async respond(incident) {
    // 1. Detect
    this.log('INCIDENT_DETECTED', incident);

    // 2. Contain
    await this.blockIP(incident.sourceIP);
    await this.disableAccount(incident.userId);

    // 3. Investigate
    const logs = await this.gatherLogs(incident);

    // 4. Remediate
    await this.patchVulnerability(incident.vulnerability);

    // 5. Recover
    await this.restoreService();

    // 6. Lessons Learned
    await this.documentIncident(incident);

    // 7. Notify
    await this.notifyStakeholders(incident);
  }
}

💡 Security Quick Wins

# 1. Add security.txt
echo "Contact: security@example.com" > public/.well-known/security.txt

# 2. Enable Dependabot
gh api repos/:owner/:repo --method PUT --field security_and_analysis[secret_scanning][status]=enabled

# 3. Add pre-commit hooks
npm install --save-dev husky
npx husky add .husky/pre-commit "npm audit"

# 4. Security headers test
curl -I https://yoursite.com | grep -i "strict-transport\|content-security\|x-frame"

Remember: Security is not a feature, it's a requirement! 🛡️