
Security Review
FreeEnsure your code adheres to security best practices.
Free · Opens the source repo
What Security Review does
The Security Review skill is designed to help developers and designers implement security best practices in their code. It provides a comprehensive checklist and guidelines for various scenarios where security is critical, such as authentication, authorization, and handling user inputs. By following the recommendations laid out in this skill, users can identify potential vulnerabilities early in the development process, making their applications more secure.
This skill includes detailed instructions on secrets management, input validation, SQL injection prevention, authentication and authorization practices, XSS prevention, and CSRF protection. Each section offers clear examples of what to avoid and what to implement, ensuring that users can easily understand and apply these best practices in their projects. The skill emphasizes the importance of using environment variables for sensitive information, validating user inputs against schemas, and employing parameterized queries to prevent SQL injection attacks.
The Security Review skill is particularly useful for developers who are building applications that handle sensitive data, such as user credentials, payment information, or personal details. It is also beneficial for teams integrating third-party APIs or working with file uploads, as it provides a framework to ensure that security considerations are not overlooked. By integrating this skill into their workflow, developers can enhance the security posture of their applications and reduce the risk of vulnerabilities.
Overall, the Security Review skill serves as a valuable resource for anyone involved in the development process, helping to foster a culture of security awareness and best practices within teams.
When to use it
Use this skill when implementing authentication, handling user input, or creating new API endpoints to ensure security best practices are followed.
When not to use it
This skill may not be suitable for projects that do not involve user data or sensitive information, as its focus is on security best practices for such scenarios.
What you can build with it
Implementing User Authentication
Use the security review skill to ensure that authentication mechanisms are secure, including proper token storage and validation.
Handling File Uploads Safely
Refer to the skill for guidelines on validating file uploads to prevent vulnerabilities related to file handling.
Creating Secure API Endpoints
Utilize the skill to verify that API endpoints are protected against common security threats like SQL injection and XSS.
How to install Security Review
View source1. Install with the skills CLI
npx skills add sickn33/agentic-awesome-skills/cc-skill-security-review --agent claude-code2. Or install it manually
Download the skill folder and drop it into ~/.claude/skills/ for all projects, or .claude/skills/ to scope it to one repo. Restart Claude Code so it picks up the new skill.
Anthropic's agentic coding CLI, and the reference implementation of Agent Skills. Drop a skill folder into ~/.claude/skills and Claude Code loads it automatically whenever a task matches the skill's description. Claude Code docs
Inside SKILL.md
Written by sickn33Security Review Skill
This skill ensures all code follows security best practices and identifies potential vulnerabilities.
When to Use
- Implementing authentication or authorization
- Handling user input or file uploads
- Creating new API endpoints
- Working with secrets or credentials
- Implementing payment features
- Storing or transmitting sensitive data
- Integrating third-party APIs
Security Checklist
1. Secrets Management
❌ NEVER Do This
const leakedToken = "[redacted API key]" // Hardcoded secret
const dbCredential = "[redacted password]" // In source code
✅ ALWAYS Do This
const apiKey = process.env.OPENAI_API_KEY
const dbUrl = process.env.DATABASE_URL
// Verify secrets exist
if (!apiKey) {
throw new Error('OPENAI_API_KEY not configured')
}
Verification Steps
- No hardcoded API keys, tokens, or passwords
- All secrets in environment variables
-
.env.localin .gitignore - No secrets in git history
- Production secrets in hosting platform (Vercel, Railway)
2. Input Validation
Always Validate User Input
import { z } from 'zod'
// Define validation schema
const CreateUserSchema = z.object({
email: z.string().email(),
name: z.string().min(1).max(100),
age: z.number().int().min(0).max(150)
})
// Validate before processing
export async function createUser(input: unknown) {
try {
const validated = CreateUserSchema.parse(input)
return await db.users.create(validated)
} catch (error) {
if (error instanceof z.ZodError) {
return { success: false, errors: error.errors }
}
throw error
}
}
File Upload Validation
function validateFileUpload(file: File) {
// Size check (5MB max)
const maxSize = 5 * 1024 * 1024
if (file.size > maxSize) {
throw new Error('File too large (max 5MB)')
}
// Type check
const allowedTypes = ['image/jpeg', 'image/png', 'image/gif']
if (!allowedTypes.includes(file.type)) {
throw new Error('Invalid file type')
}
// Extension check
const allowedExtensions = ['.jpg', '.jpeg', '.png', '.gif']
const extension = file.name.toLowerCase().match(/\.[^.]+$/)?.[0]
if (!extension || !allowedExtensions.includes(extension)) {
throw new Error('Invalid file extension')
}
return true
}
Verification Steps
- All user inputs validated with schemas
- File uploads restricted (size, type, extension)
- No direct use of user input in queries
- Whitelist validation (not blacklist)
- Error messages don't leak sensitive info
3. SQL Injection Prevention
❌ NEVER Concatenate SQL
// DANGEROUS - SQL Injection vulnerability
const query = `SELECT * FROM users WHERE email = '${userEmail}'`
await db.query(query)
✅ ALWAYS Use Parameterized Queries
// Safe - parameterized query
const { data } = await supabase
.from('users')
.select('*')
.eq('email', userEmail)
// Or with raw SQL
await db.query(
'SELECT * FROM users WHERE email = $1',
[userEmail]
)
Verification Steps
- All database queries use parameterized queries
- No string concatenation in SQL
- ORM/query builder used correctly
- Supabase queries properly sanitized
4. Authentication & Authorization
JWT Token Handling
// ❌ WRONG: localStorage (vulnerable to XSS)
localStorage.setItem('token', token)
// ✅ CORRECT: httpOnly cookies
res.setHeader('Set-Cookie',
`token=${token}; HttpOnly; Secure; SameSite=Strict; Max-Age=3600`)
Authorization Checks
export async function deleteUser(userId: string, requesterId: string) {
// ALWAYS verify authorization first
const requester = await db.users.findUnique({
where: { id: requesterId }
})
if (requester.role !== 'admin') {
return NextResponse.json(
{ error: 'Unauthorized' },
{ status: 403 }
)
}
// Proceed with deletion
await db.users.delete({ where: { id: userId } })
}
Row Level Security (Supabase)
-- Enable RLS on all tables
ALTER TABLE users ENABLE ROW LEVEL SECURITY;
-- Users can only view their own data
CREATE POLICY "Users view own data"
ON users FOR SELECT
USING (auth.uid() = id);
-- Users can only update their own data
CREATE POLICY "Users update own data"
ON users FOR UPDATE
USING (auth.uid() = id);
Verification Steps
- Tokens stored in httpOnly cookies (not localStorage)
- Authorization checks before sensitive operations
- Row Level Security enabled in Supabase
- Role-based access control implemented
- Session management secure
5. XSS Prevention
Sanitize HTML
import DOMPurify from 'isomorphic-dompurify'
// ALWAYS sanitize user-provided HTML
function renderUserContent(html: string) {
const clean = DOMPurify.sanitize(html, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'p'],
ALLOWED_ATTR: []
})
return <div dangerouslySetInnerHTML={{ __html: clean }} />
}
Content Security Policy
// next.config.js
const securityHeaders = [
{
key: 'Content-Security-Policy',
value: `
default-src 'self';
script-src 'self' 'unsafe-eval' 'unsafe-inline';
style-src 'self' 'unsafe-inline';
img-src 'self' data: https:;
font-src 'self';
connect-src 'self' https://api.example.com;
`.replace(/\s{2,}/g, ' ').trim()
}
]
Verification Steps
- User-provided HTML sanitized
- CSP headers configured
- No unvalidated dynamic content rendering
- React's built-in XSS protection used
6. CSRF Protection
CSRF Tokens
import { csrf } from '@/lib/csrf'
export async function POST(request: Request) {
const token = request.headers.get('X-CSRF-Token')
if (!csrf.verify(token)) {
return NextResponse.json(
{ error: 'Invalid CSRF token' },
{ status: 403 }
)
}
// Process request
}
SameSite Cookies
res.setHeader('Set-Cookie',
`session=${sessionId}; HttpOnly; Secure; SameSite=Strict`)
Verification Steps
- CSRF tokens on state-changing operations
- SameSite=Strict on all cookies
- Double-submit cookie pattern implemented
7. Rate Limiting
API Rate Limiting
import rateLimit from 'express-rate-limit'
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // 100 requests per window
message: 'Too many requests'
})
// Apply to routes
app.use('/api/', limiter)
Expensive Operations
// Aggressive rate limiting for searches
const searchLimiter = rateLimit({
windowMs: 60 * 1000, // 1 minute
max: 10, // 10 requests per minute
message: 'Too many search requests'
})
app.use('/api/search', searchLimiter)
Verification Steps
- Rate limiting on all API endpoints
- Stricter limits on expensive operations
- IP-based rate limiting
- User-based rate limiting (authenticated)
8. Sensitive Data Exposure
Logging
// ❌ WRONG: Logging sensitive data
console.log('User login:', { email, password })
console.log('Payment:', { cardNumber, cvv })
// ✅ CORRECT: Redact sensitive data
console.log('User login:', { email, userId })
console.log('Payment:', { last4: card.last4, userId })
Error Messages
// ❌ WRONG: Exposing internal details
catch (error) {
return NextResponse.json(
{ error: error.message, stack: error.stack },
{ status: 500 }
)
}
// ✅ CORRECT: Generic error messages
catch (error) {
console.error('Internal error:', error)
return NextResponse.json(
{ error: 'An error occurred. Please try again.' },
{ status: 500 }
)
}
Verification Steps
- No passwords, tokens, or secrets in logs
- Error messages generic for users
- Detailed errors only in server logs
- No stack traces exposed to users
9. Blockchain Security (Solana)
Wallet Verification
import { verify } from '@solana/web3.js'
async function verifyWalletOwnership(
publicKey: string,
signature: string,
message: string
) {
try {
const isValid = verify(
Buffer.from(message),
Buffer.from(signature, 'base64'),
Buffer.from(publicKey, 'base64')
)
return isValid
} catch (error) {
return false
}
}
Transaction Verification
async function verifyTransaction(transaction: Transaction) {
// Verify recipient
if (transaction.to !== expectedRecipient) {
throw new Error('Invalid recipient')
}
// Verify amount
if (transaction.amount > maxAmount) {
throw new Error('Amount exceeds limit')
}
// Verify user has sufficient balance
const balance = await getBalance(transaction.from)
if (balance < transaction.amount) {
throw new Error('Insufficient balance')
}
return true
}
Verification Steps
- Wallet signatures verified
- Transaction details validated
- Balance checks before transactions
- No blind transaction signing
10. Dependency Security
Regular Updates
# Check for vulnerabilities
npm audit
# Fix automatically fixable issues
npm audit fix
# Update dependencies
npm update
# Check for outdated packages
npm outdated
Lock Files
# ALWAYS commit lock files
git add package-lock.json
# Use in CI/CD for reproducible builds
npm ci # Instead of npm install
Verification Steps
- Dependencies up to date
- No known vulnerabilities (npm audit clean)
- Lock files committed
- Dependabot enabled on GitHub
- Regular security updates
Security Testing
Automated Security Tests
// Test authentication
test('requires authentication', async () => {
const response = await fetch('/api/protected')
expect(response.status).toBe(401)
})
// Test authorization
test('requires admin role', async () => {
const response = await fetch('/api/admin', {
headers: { Authorization: `Bearer ${userToken}` }
})
expect(response.status).toBe(403)
})
// Test input validation
test('rejects invalid input', async () => {
const response = await fetch('/api/users', {
method: 'POST',
body: JSON.stringify({ email: 'not-an-email' })
})
expect(response.status).toBe(400)
})
// Test rate limiting
test('enforces rate limits', async () => {
const requests = Array(101).fill(null).map(() =>
fetch('/api/endpoint')
)
const responses = await Promise.all(requests)
const tooManyRequests = responses.filter(r => r.status === 429)
expect(tooManyRequests.length).toBeGreaterThan(0)
})
Pre-Deployment Security Checklist
Before ANY production deployment:
- Secrets: No hardcoded secrets, all in env vars
- Input Validation: All user inputs validated
- SQL Injection: All queries parameterized
- XSS: User content sanitized
- CSRF: Protection enabled
- Authentication: Proper token handling
- Authorization: Role checks in place
- Rate Limiting: Enabled on all endpoints
- HTTPS: Enforced in production
- Security Headers: CSP, X-Frame-Options configured
- Error Handling: No sensitive data in errors
- Logging: No sensitive data logged
- Dependencies: Up to date, no vulnerabilities
- Row Level Security: Enabled in Supabase
- CORS: Properly configured
- File Uploads: Validated (size, type)
- Wallet Signatures: Verified (if blockchain)
Resources
Remember: Security is not optional. One vulnerability can compromise the entire platform. When in doubt, err on the side of caution.
When to Use
This skill is applicable to execute the workflow or actions described in the overview.
Limitations
- Use this skill only when the task clearly matches the scope described above.
- Do not treat the output as a substitute for environment-specific validation, testing, or expert review.
- Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.
Frequently asked questions about Security Review
Similar skills
GitHub Actions Hardening
Enhance the security of your GitHub Actions workflows.
Sensitive Logging Audit
Audit and fix sensitive data exposure in Python logging.
Android App Static Analysis
Automate security assessments of Android apps with MobSF.
Integrating DAST with OWASP ZAP
Seamlessly integrate dynamic security testing into CI/CD pipelines.
Implementing Runtime Security with Tetragon
Enhance Kubernetes security with eBPF-based observability.
Implementing Mobile Application Management
Secure enterprise data on mobile devices with app-level controls.
