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