Cloudflare Workers Security Guide

Share

To secure Cloudflare Workers, you need to: (1) store secrets using wrangler secret put (never in wrangler.toml), (2) implement rate limiting using Workers KV or Durable Objects, (3) validate all incoming requests including JWT verification at the edge, (4) configure CORS properly to prevent unauthorized origins, and (5) ensure error messages do not leak sensitive information. This blueprint covers edge security patterns for serverless functions.

Setup Time1-2 hours

TL;DR

Workers run at the edge with access to secrets via environment variables. Use wrangler secrets for sensitive data, validate all incoming requests, implement rate limiting with Workers KV or Durable Objects, and be careful with CORS configuration.

JWT Validation at the Edge Cloudflare

src/index.ts
export interface Env {
  JWT_SECRET: string
  ALLOWED_ORIGINS: string
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    // CORS handling
    if (request.method === 'OPTIONS') {
      return handleCors(request, env)
    }

    // Authenticate
    const authHeader = request.headers.get('Authorization')
    if (!authHeader?.startsWith('Bearer ')) {
      return new Response('Unauthorized', { status: 401 })
    }

    const token = authHeader.slice(7)

    try {
      const payload = await verifyJwt(token, env.JWT_SECRET)
      // Token is valid, process request
      return handleRequest(request, payload, env)
    } catch {
      return new Response('Invalid token', { status: 401 })
    }
  },
}

async function verifyJwt(token: string, secret: string) {
  const encoder = new TextEncoder()
  const key = await crypto.subtle.importKey(
    'raw',
    encoder.encode(secret),
    { name: 'HMAC', hash: 'SHA-256' },
    false,
    ['verify']
  )

  const [headerB64, payloadB64, signatureB64] = token.split('.')
  const data = encoder.encode(`${headerB64}.${payloadB64}`)
  const signature = base64UrlDecode(signatureB64)

  const valid = await crypto.subtle.verify('HMAC', key, signature, data)
  if (!valid) throw new Error('Invalid signature')

  return JSON.parse(atob(payloadB64))
}

Rate Limiting with KV Cloudflare

src/rate-limit.ts
export interface Env {
  RATE_LIMIT_KV: KVNamespace
}

export async function rateLimit(
  ip: string,
  env: Env,
  limit = 100,
  window = 60
): Promise<boolean> {
  const key = `rate:${ip}`
  const current = await env.RATE_LIMIT_KV.get(key)

  if (!current) {
    await env.RATE_LIMIT_KV.put(key, '1', { expirationTtl: window })
    return true
  }

  const count = parseInt(current, 10)
  if (count >= limit) {
    return false
  }

  await env.RATE_LIMIT_KV.put(key, String(count + 1), { expirationTtl: window })
  return true
}

// Usage in worker
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const ip = request.headers.get('CF-Connecting-IP') || 'unknown'

    if (!await rateLimit(ip, env)) {
      return new Response('Too many requests', { status: 429 })
    }

    // Process request...
  },
}

Secrets Management

wrangler.toml + CLI
# wrangler.toml - Don't put secrets here!
name = "my-worker"
main = "src/index.ts"

[vars]
ALLOWED_ORIGINS = "https://myapp.com"

# Add secrets via CLI (encrypted, not in source)
# wrangler secret put JWT_SECRET
# wrangler secret put DATABASE_URL

Never put secrets in wrangler.toml. Use wrangler secret put for sensitive values. They're encrypted and only accessible at runtime.

Security Checklist

Pre-Launch Checklist

Secrets stored via wrangler secret

Rate limiting implemented

CORS configured correctly

Request validation in place

Error messages don't leak info

S3 Secure Uploads Redis Session Management OAuth at the Edge

Check Your Workers Security

Scan for edge function vulnerabilities.

Start Free Scan
Security Blueprints

Cloudflare Workers Security Guide