Back to Blog
Cloud NativeJuly 1, 20264 min read

Vercel Security: Implementing Custom WAF Rules with Cloudflare Workers

Enhance Vercel security by using Cloudflare Workers for custom request filtering. Learn to build a granular edge WAF to protect your Vercel origins.

VercelCloudflare WorkersWeb SecurityEdge ComputingWAFNext.jsDevOpsCloudflareDeployment

We recently hit a wall during a high-traffic launch when standard rate-limiting wasn't enough to stop a series of sophisticated, low-volume scraping attempts. While Vercel handles standard DDoS protection beautifully, we needed more granular control over specific request payloads that were hitting our API routes.

Instead of refactoring our entire backend, we shifted the security layer to the edge. By using Cloudflare Workers as a custom WAF, we gained the ability to inspect, block, or modify requests before they ever touched our Vercel origin.

Why Layer Security at the Edge?

Vercel is great for developer experience, but sometimes you need to intercept traffic based on application-specific logic. Standard WAF rules often operate on broad IP ranges or generic signatures. If you’re dealing with parameter pollution, you need logic that understands your specific API schema.

By placing a Worker in front of your deployment, you effectively create a programmable firewall. This is similar to how we manage complex traffic patterns for Vercel blue-green deployment or edge-side A/B testing, but with a focus on request validation rather than routing.

Implementing Custom Request Filtering

To get started, you’ll need your domain proxied through Cloudflare. The Worker will intercept the incoming Request object, validate your criteria, and only then fetch the request to the Vercel origin.

Here is a basic implementation of a request filter that blocks requests containing suspicious headers:

JAVASCRIPT
addEventListener(CE9178">'fetch', event => {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  const userAgent = request.headers.get(CE9178">'user-agent') || CE9178">''
  
  // Custom logic: block specific bots or suspicious patterns
  if (userAgent.includes(CE9178">'BadBot/1.0')) {
    return new Response(CE9178">'Forbidden: Access Denied', { status: 403 })
  }

  // Forward the request to Vercel
  const url = new URL(request.url)
  url.hostname = CE9178">'your-vercel-project.vercel.app'
  
  const modifiedRequest = new Request(url, request)
  return fetch(modifiedRequest)
}

The Trade-offs of Edge Filtering

We first tried implementing this logic directly within our Next.js API routes. It was cleaner, but it meant every blocked request still consumed our Vercel execution time and billing credits. Moving this to Cloudflare Workers saved us roughly 30% on our edge function execution costs during that surge.

However, there is a catch: you have to manage two separate deployment environments. If you update your API path, you have to ensure your Worker's filtering logic stays in sync.

FeatureStandard Vercel SecurityCloudflare Workers WAF
GranularityLimited (IP/Geo)Unlimited (Custom Code)
CostIncludedUsage-based
ComplexityLowModerate
Logic LocationOrigin-basedEdge-based

Advanced Protection for Vercel Origins

If you're already optimizing your Vercel Edge Functions cold start with KV stores, you can take this further. You can use Cloudflare KV to maintain a dynamic "deny list" of IPs or user IDs that you update in real-time without redeploying your Worker code.

When protecting your Vercel origins, always ensure you’re validating the CF-Connecting-IP header or checking for a secret header that only Cloudflare sends. This prevents attackers from bypassing your Worker by hitting your Vercel URL directly.

What I’d Do Differently Next Time

If I were to rebuild this today, I would lean harder into Cloudflare's WAF Managed Rules first. We spent about two days writing custom filtering logic that we could have partially offloaded to their pre-built rulesets. Only write custom code when your security requirement is truly unique—like blocking traffic based on specific JWT claims or complex header combinations that standard tools don't recognize.

I'm still tinkering with the balance between edge-side latency and the number of checks we perform. Adding too much logic to the Worker adds roughly 20-50ms of latency. For most apps, this is negligible, but it's something to watch if you're chasing sub-100ms LCP scores.

Frequently Asked Questions

Does using a Worker add significant latency to Vercel requests? Usually, no. Cloudflare Workers execute in under 1ms, though complex regex or external API calls inside the Worker will increase that.

Can I block requests based on body content? Yes, but be careful. Reading the request body in a Worker can be tricky if you don't use request.clone(). Ensure you aren't consuming the stream before it reaches Vercel.

Is this a replacement for Vercel's built-in protection? No. Think of it as a defense-in-depth strategy. Keep Vercel's native features enabled to handle volumetric DDoS attacks while using your Worker for application-layer, granular filtering.

Similar Posts