security-patterns
Security patterns for input validation, PII protection, and cryptographic operations
When & Why to Use This Skill
This Claude skill provides a comprehensive framework of security patterns and best practices for modern software development. It focuses on robust input validation using Zod, automated PII (Personally Identifiable Information) protection, secure cryptographic operations, and defensive error handling. By integrating these patterns, developers can effectively mitigate common vulnerabilities such as XSS, SQL injection, and data leaks while ensuring compliance with privacy standards.
Use Cases
- Implementing strict input validation for API endpoints using Zod schemas to prevent malicious data entry and ensure type safety.
- Automating PII protection by sanitizing application logs to ensure sensitive user data like emails, tokens, and passwords are never exposed.
- Securing third-party integrations, such as Stripe webhooks, through cryptographic signature verification and replay attack prevention.
- Establishing secure authentication workflows using cryptographically secure random number generation and encrypted client-side storage.
- Designing resilient error handling systems that provide generic feedback to users while logging detailed, sanitized debugging information server-side.
| name | security-patterns |
|---|---|
| description | Security patterns for input validation, PII protection, and cryptographic operations |
Security Patterns
Purpose: Security best practices (validation, PII protection, crypto, defense against vulnerabilities)
- Keywords: security, validation, auth, password, token, sanitize, xss, sql injection, zod, pii, webhook, signature, verify, encrypt, decrypt, hash, jwt, oauth, csrf, authentication, authorization, stripe
Quick Reference
| Category | ✅ DO | ❌ AVOID |
|---|---|---|
| Validation | Zod schemas with constraints | Trust client input |
| PII | sanitizeForLogging() |
Log emails, names, tokens |
| Crypto | crypto.randomInt() |
Math.random() |
| Storage | Encrypt localStorage | Store keys/passwords |
| Errors | Generic to client | Stack traces to client |
Input Validation (Zod)
import { z } from "zod"
const orderSchema = z.object({
name: z.string().min(1).max(100).trim(),
email: z.string().email().max(255).toLowerCase(),
amount: z.number().positive().max(1000000),
phone: z.string().regex(/^\+?[1-9]\d{1,14}$/).optional()
})
type Result<T, E> = { ok: true; value: T } | { ok: false; error: E }
const validate = (input: unknown): Result<Order, z.ZodError> => {
const result = orderSchema.safeParse(input)
return result.success
? { ok: true, value: result.data }
: { ok: false, error: result.error }
}
Key: Use .safeParse(), add constraints (.min(), .max(), .trim()), return Result
PII Protection
import { sanitizeForLogging } from "./utils/sanitize"
// ✅ Auto-removes PII
logger.audit('order_created', sanitizeForLogging({
user_id: "123",
full_name: "John", // Removed
email: "john@example.com", // Removed
amount: 100
}))
// Logged: { user_id: "123", amount: 100 }
Auto-removed: Passwords, tokens, API keys, emails, names, SSN, cards, Bitcoin keys/addresses, phones
See resources/pii-protection.md for implementation.
Secure Random
import { randomInt } from "crypto"
// ✅ Cryptographically secure
const sessionId = randomInt(0, Number.MAX_SAFE_INTEGER).toString(36)
const code = randomInt(100000, 999999).toString()
// ✅ Browser
const array = new Uint32Array(1)
crypto.getRandomValues(array)
// ❌ NEVER for security
const code = Math.random() * 1000000
Secure Client Storage
import { encrypt, decrypt } from "./crypto"
const saveSession = (data: SessionData) => {
const encrypted = encrypt(JSON.stringify(data))
localStorage.setItem("session", encrypted)
}
// ❌ NEVER store Bitcoin keys/passwords (even encrypted)
Error Handling
export const createOrder = async (input: unknown) => {
try {
const order = await processOrder(input)
return { ok: true, value: order }
} catch (error) {
// ✅ Log full details server-side
logger.error('Order failed', {
error,
stack: error.stack,
input: sanitizeForLogging(input)
})
// ✅ Generic to client
return {
ok: false,
error: new Error("Failed to create order")
}
}
}
Webhook Verification
export const handleStripeWebhook = async (req: Request) => {
const signature = req.headers.get("stripe-signature")
const body = await req.text()
// ✅ Verify signature BEFORE processing
if (!verifySignature(body, signature, WEBHOOK_SECRET)) {
logger.warn('Invalid signature', { ip: req.headers.get("x-forwarded-for") })
return new Response("Invalid signature", { status: 401 })
}
// ✅ Check timestamp (replay attack)
const event = JSON.parse(body)
const eventTime = event.created * 1000
if (Date.now() - eventTime > 5 * 60 * 1000) {
return new Response("Timestamp too old", { status: 400 })
}
await processWebhookEvent(event)
return new Response("OK", { status: 200 })
}
Pre-Implementation Checklist
Before implementing, ask:
- ✅ Can users access data they shouldn't? (Authorization)
- ✅ Can this be automated/abused? (Rate limiting)
- ✅ Am I trusting client data? (Validation)
- ✅ Could this leak PII? (Sanitization)
- ✅ Can concurrent requests cause issues? (Race conditions)
- ✅ Can this be spammed? (Rate limiting, CAPTCHA)
If ANY "yes" → redesign before implementing
Rate Limits
| Action | Limit |
|---|---|
| Registration | 3/IP/24h |
| Login | 10/email/5min |
| Password reset | 3/email/hour |
| API calls | 100/user/hour |
See resources/rate-limiting.md
Incident Response
| Severity | Response | Examples |
|---|---|---|
| Critical | 4 hours | Breach, auth bypass |
| High | 24 hours | PII leak, privilege escalation |
| Medium | 3 days | XSS, CSRF |
Steps: Assess → Contain → Investigate → Patch → Notify (<72h if PII)
Resources
resources/input-validation.md- Zod patternsresources/pii-protection.md- Sanitizationresources/crypto-operations.md- Secure random, encryptionresources/rate-limiting.md- Rate limit implementation