Overview Install Files SecuritySummary Cloudflare Workers security with authentication, CORS, rate limiting, input validation. Use for securing APIs, JWT/API keys, or encountering auth failures, CORS errors, XSS/injection vulnerabilities.
Cloudflare Workers Security
Comprehensive security patterns for protecting Workers and APIs.
Quick Security Checklist
// 1. Validate all input
const validated = schema.parse(await request.json());
// 2. Authenticate requests
const user = await verifyToken(request.headers.get('Authorization'));
if (!user) return new Response('Unauthorized', { status: 401 });
// 3. Rate limit
const limited = await rateLimiter.check(clientIP);
if (!limited.allowed) return new Response('Too Many Requests', { status: 429 });
// 4. Add security headers
response.headers.set('X-Content-Type-Options', 'nosniff');
response.headers.set('X-Frame-Options', 'DENY');
// 5. Use HTTPS-only cookies
headers.set('Set-Cookie', 'session=xxx; Secure; HttpOnly; SameSite=Strict');
Critical Rules
Never trust client input - Validate and sanitize everything
Use secure secrets - Store in Wrangler secrets, never in code
Implement rate limiting - Protect against abuse
Set security headers - Prevent common attacks
Use CORS properly - Don't use * in production
Top 10 Security Errors
Vulnerability Symptom Prevention Missing auth Unauthorized access Verify tokens on every request SQL injection Data breach Use parameterized queries with D1 XSS Script injection Sanitize output, set CSP CORS misconfiguration Blocked requests or open access Configure specific origins Secrets in code
Missing rate limits DoS vulnerability Implement per-IP limits
Weak tokens Session hijacking Use crypto.subtle for signing
Missing HTTPS Data interception Enforce HTTPS redirects
Insecure headers Clickjacking, MIME attacks Set security headers
Excessive permissions Blast radius Principle of least privilege
Authentication Patterns
JWT Verification async function verifyJWT(token: string, secret: string): Promise<{ valid: boolean; payload?: unknown }> {
try {
const [headerB64, payloadB64, signatureB64] = token.split('.');
// Verify signature
const key = await crypto.subtle.importKey(
'raw',
new TextEncoder().encode(secret),
{ name: 'HMAC', hash: 'SHA-256' },
false,
['verify']
);
const signature = Uint8Array.from(atob(signatureB64.replace(/-/g, '+').replace(/_/g, '/')), c => c.charCodeAt(0));
const data = new TextEncoder().encode(`${headerB64}.${payloadB64}`);
const valid = await crypto.subtle.verify('HMAC', key, signature, data);
if (!valid) return { valid: false };
// Decode payload
const payload = JSON.parse(atob(payloadB64.replace(/-/g, '+').replace(/_/g, '/')));
// Check expiration
if (payload.exp && Date.now() / 1000 > payload.exp) {
return { valid: false };
}
return { valid: true, payload };
} catch {
return { valid: false };
}
}
API Key Validation async function validateApiKey(
request: Request,
env: Env
): Promise<{ valid: boolean; clientId?: string }> {
const apiKey = request.headers.get('X-API-Key');
if (!apiKey) return { valid: false };
// Hash the key for lookup (never store plain keys)
const keyHash = await sha256(apiKey);
// Lookup in KV or D1
const client = await env.KV.get(`apikey:${keyHash}`, 'json');
if (!client) return { valid: false };
return { valid: true, clientId: client.id };
}
async function sha256(str: string): Promise<string> {
const buffer = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(str));
return [...new Uint8Array(buffer)].map(b => b.toString(16).padStart(2, '0')).join('');
}
Input Validation
With Zod import { z } from 'zod';
const UserSchema = z.object({
name: z.string().min(1).max(100),
email: z.email(),
age: z.number().int().min(0).max(150).optional(),
});
async function handleCreate(request: Request): Promise<Response> {
try {
const body = await request.json();
const user = UserSchema.parse(body);
// Safe to use validated data
return Response.json({ success: true, user });
} catch (error) {
if (error instanceof z.ZodError) {
return Response.json({ error: 'Validation failed', details: error.errors }, { status: 400 });
}
throw error;
}
}
Security Headers function addSecurityHeaders(response: Response): Response {
const headers = new Headers(response.headers);
// Prevent MIME type sniffing
headers.set('X-Content-Type-Options', 'nosniff');
// Prevent clickjacking
headers.set('X-Frame-Options', 'DENY');
// XSS protection
headers.set('X-XSS-Protection', '1; mode=block');
// Content Security Policy
headers.set('Content-Security-Policy', "default-src 'self'; script-src 'self'");
// HSTS
headers.set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
// Referrer policy
headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
return new Response(response.body, { status: response.status, headers });
}
CORS Configuration const ALLOWED_ORIGINS = ['https://app.example.com', 'https://admin.example.com'];
function handleCORS(request: Request, response: Response): Response {
const origin = request.headers.get('Origin');
if (!origin || !ALLOWED_ORIGINS.includes(origin)) {
return response; // No CORS headers
}
const headers = new Headers(response.headers);
headers.set('Access-Control-Allow-Origin', origin);
headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization');
headers.set('Access-Control-Allow-Credentials', 'true');
headers.set('Access-Control-Max-Age', '86400');
return new Response(response.body, { status: response.status, headers });
}
When to Load References Load specific references based on the task:
Implementing authentication? → Load references/authentication.md
CORS issues? → Load references/cors-security.md
Validating input? → Load references/input-validation.md
Managing secrets? → Load references/secrets-management.md
Rate limiting? → Load references/rate-limiting.md
Security headers? → Load references/security-headers.md
Templates Template Purpose Use When templates/auth-middleware.tsJWT/API key auth Adding authentication templates/cors-handler.tsCORS middleware Handling cross-origin templates/rate-limiter.tsRate limiting Preventing abuse templates/secure-worker.tsFull secure setup Starting secure project
Scripts Script Purpose Command scripts/security-audit.shAudit security ./security-audit.sh <url>
Resources