Skip to content
saltwaterbrc
Go back

Securing APIs with Cloudflare: API Shield, Schema Validation, and Layered Defense

Why This Matters

Most application-layer traffic now comes through APIs, not web pages. Every time someone uses my AI agent, signs the guestbook, or loads the visitor counter — that’s an API call. And every one of those calls is an entry point that needs protection.

I’ve been building Cloudflare products into this site since day one — Workers, D1, Durable Objects, Vectorize, WAF, AI Gateway, Agents SDK. The whole point is to understand how each product works hands-on, so I can speak to how they’d fit into specific industries — healthcare, financial services, retail, government, corrections. That’s why the AI agent on this site surfaces industry-specific use cases. But I hadn’t set up API Shield yet, and with API traffic becoming the dominant attack surface, it was time to close that gap.

What’s an API, Really?

An API is a door into your application that software talks to instead of humans. When you visit saltwaterbrc.com in a browser, you see a webpage. But when the AI chat sends a message, it hits /agents/salt-water-agent/{sessionId} — no webpage, just data going back and forth as JSON.

My site has three APIs I built with Cloudflare Workers:

Each of these is an endpoint — a specific URL path and HTTP method combination that does something. Think of endpoints as numbered doors in a building. Each one leads somewhere different, and each one needs its own security.

What I Set Up

Step 1: API Discovery

Cloudflare’s ML-based API Discovery watches your traffic and automatically identifies API endpoints. I didn’t tell it anything — it analyzed request patterns and found four endpoints on its own:

GET  /                    saltwaterbrc.com
GET  /                    www.saltwaterbrc.com
GET  /tags/vectorize/     saltwaterbrc.com
HEAD /                    www.saltwaterbrc.com

These are the page routes it detected from organic traffic. I saved all four to Endpoint Management. But my actual API endpoints — the Workers that handle JSON requests — needed to be added manually. That’s where the OpenAPI schema comes in.

Step 2: Writing the OpenAPI Schema

An OpenAPI spec is a YAML file that describes every endpoint your API exposes: what methods it accepts, what the request body should look like, and what it returns. It’s the blueprint Cloudflare uses to validate incoming traffic.

Here’s what my guestbook endpoint definition looks like:

/api/guestbook:
  post:
    operationId: signGuestbook
    summary: Sign the guestbook
    requestBody:
      required: true
      content:
        application/json:
          schema:
            type: object
            required:
              - name
              - message
            properties:
              name:
                type: string
                maxLength: 100
              company:
                type: string
                maxLength: 100
              message:
                type: string
                maxLength: 1000
            additionalProperties: false

The key line is additionalProperties: false. That tells Cloudflare: only name, company, and message are allowed. Anything else gets flagged. If someone sends {"admin": true, "deleteAll": true} — that’s a non-compliant request.

I wrote specs for all three API endpoints and uploaded the full openapi.yaml to API Shield via the dashboard. Cloudflare parsed it and created 18 endpoint entries across my three server origins (the Astro site, the agent worker, and the counter worker).

Step 3: Schema Validation

After uploading, you choose what happens when a request doesn’t match your schema:

ActionWhat Happens
NoneRequest goes through, nothing logged
LogRequest goes through but gets recorded in Security Events
BlockRequest gets rejected before it reaches your Worker

I set mine to Log first. This lets me see what would get blocked without accidentally breaking legitimate traffic. Once I verify everything looks clean, one click switches it to Block.

You’re telling Cloudflare: “Here are my doors, here’s what’s allowed through each one — block anything weird.”

Testing It: Good Request vs. Bad Request

With the schema live, I fired two requests at my guestbook API from the browser console.

Good request — matches the schema exactly:

fetch('/api/guestbook', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    name: 'API Shield Demo',
    message: 'Valid schema-compliant request'
  })
});
// → 201 Created ✓

Bad request — sends fields that don’t exist in the schema:

fetch('/api/guestbook', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    admin: true,
    deleteAll: true,
    escalatePrivileges: 'root'
  })
});
// → 400 Error ✗

The good request went through and created guestbook entry #5. The bad request got rejected — my Worker returned a 400 because name and message were missing, and Cloudflare’s schema validation flagged it as non-compliant because it contained additionalProperties that don’t belong.

That’s two layers of defense: the Worker’s own validation AND Cloudflare’s schema enforcement. Even if my Worker code had a bug that let bad data through, Cloudflare would catch it at the edge first.

What’s Already Being Blocked

Before I even set up API Shield, Cloudflare’s WAF Managed Rules were already catching real attacks on my site. In just 24 hours, Security Events showed:

/.env              — 6 attempts (stealing environment variables)
/wp-config.php.bak — 2 attempts (scanning for WordPress backups)
/.env.bak          — 1 attempt  (backup env files)
/web.config        — 1 attempt  (IIS server config)

Ten blocks from automated scanners originating in the Netherlands and Lithuania. These are bots probing every site they can find, looking for exposed secrets and misconfigurations. My site doesn’t even use WordPress or IIS — they’re spraying and praying.

The Managed Rules that caught them:

This is the layered security story. WAF Managed Rules handle the broad attack patterns. API Shield adds application-specific protection on top — schema validation ensures only properly formatted requests reach your code, and BOLA detection watches for authorization abuse.

The Layered Defense Model

Here’s how the layers stack:

Incoming Request


┌─────────────────────────┐
│  DDoS Protection        │  ← Volumetric attack mitigation
├─────────────────────────┤
│  WAF Managed Rules      │  ← Known attack signatures (.env, SQLi, XSS)
├─────────────────────────┤
│  API Shield             │  ← Schema validation, BOLA detection
│  • Schema Validation    │     Only properly shaped requests pass
│  • Sequence Analytics   │     Detects unusual API call patterns
│  • BOLA Detection       │     Catches authorization abuse
├─────────────────────────┤
│  Rate Limiting          │  ← Prevents brute force / abuse
├─────────────────────────┤
│  Your Worker Code       │  ← Application-level validation
└─────────────────────────┘

Each layer catches different things. A malformed JSON payload might slip past DDoS protection and WAF rules (it’s not a known attack signature), but schema validation stops it cold. Someone changing /api/users/123 to /api/users/456 in the URL might pass schema validation (it’s a valid format), but BOLA detection flags the pattern.

Page Shield: Protecting the Other Side

While API Shield protects your server-side APIs, Page Shield protects the client-side browser environment. It monitors every third-party script, connection, and cookie running on your visitors’ browsers.

Why does this matter? Think about a hospital website that loads a chat widget, analytics, and a payment form. If the chat vendor gets compromised and starts exfiltrating data (a Magecart-style attack), Page Shield detects the malicious behavior, scores it, and alerts you before patient data leaks.

This is a PCI DSS 4.0 requirement for anyone processing payments. If your site loads third-party JavaScript, you need to monitor what those scripts are doing.

On my site, Page Shield’s Client-side Resources monitor is active across three categories:

My site currently shows a clean bill of health — no third-party scripts detected, because everything is first-party Astro-generated code. That’s actually the ideal state. For sites that do load payment processors, analytics, or chat widgets, Page Shield would be monitoring all of them and flagging anything suspicious.

Demo: Try It Yourself in 5 Minutes

Want to see API Shield in action? Here’s the step-by-step walkthrough you can follow live on this site. You can test from your browser console or from a terminal — both are making the same API call, just different tools.

What’s the browser console? Every browser has built-in developer tools. Press F12 (or right-click anywhere → Inspect → Console tab) and you get a command line where you can run JavaScript directly against the current page. It’s a quick way to fire API requests without leaving the browser.

Step 1: Send a valid request to the guestbook API

From the browser console (F12 → Console tab) on any page of this site:

fetch('/api/guestbook', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    name: 'Your Name',
    message: 'Testing API Shield — valid request'
  })
}).then(r => r.json()).then(console.log);

Or from your terminal using curl:

curl -X POST https://saltwaterbrc.com/api/guestbook \
  -H "Content-Type: application/json" \
  -d '{"name":"Your Name","message":"Testing API Shield — valid request"}'

You should see { success: true, id: <number> } — the request matched the schema and went through. Name and message were provided, no extra fields, proper JSON format. The bouncer checked the ID and let them in.

Step 2: Send a malicious request

Now send something that violates the schema — extra fields, missing required fields, wrong types:

From the browser console:

fetch('/api/guestbook', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    admin: true,
    deleteAll: true,
    escalatePrivileges: 'root'
  })
}).then(r => r.json()).then(console.log);

Or from terminal:

curl -X POST https://saltwaterbrc.com/api/guestbook \
  -H "Content-Type: application/json" \
  -d '{"admin":true,"deleteAll":true,"escalatePrivileges":"root"}'

You’ll get { error: "name and message are required" } — rejected. The Worker’s own validation caught the missing fields, AND Cloudflare’s schema validation flagged it as non-compliant because admin, deleteAll, and escalatePrivileges aren’t in the OpenAPI spec. Two layers of defense from one request.

Step 3: Check the Cloudflare Dashboard

Now open the Cloudflare dashboard to see what just happened. The bad request you fired shows up in two places:

  1. Security → Analytics → Events — this is the Security Events log. Your non-compliant request will appear here with details on why it was flagged. Since we set the schema action to Log, the request was allowed through but recorded. Switching to Block would reject it at the edge before it ever reaches the Worker.

  2. Security → Web Assets → Schema Validation — look at the “Non-compliant requests last 24hrs” column next to the /api/guestbook POST endpoint. You’ll see a count incrementing as bad requests come in.

It can take a few minutes for events to propagate. If you don’t see it immediately, give it 2-3 minutes and refresh.

Step 4: See what’s already being blocked

While you’re in Security Events, look at the Paths breakdown. You’ll see bots already probing for /.env, /wp-config.php.bak, and other common targets — real automated scanners trying to steal environment variables and configuration files. That’s Cloudflare’s WAF Managed Rules working alongside API Shield. The Events by service section breaks down which rules caught them:

This is the layered defense in action: WAF Managed Rules handle known attack signatures, API Shield enforces your specific schema, and together they create a security posture that’s both broad and precise.

The demo flow:

  1. Fire the good request → “See? Goes through. 201 Created.”
  2. Fire the bad request → “Rejected. 400 Error.”
  3. Open Security Events → “And here it is — Cloudflare caught it and logged it.”
  4. Show the Paths breakdown → “These are real bots scanning this site right now.”
  5. Show Schema Validation → “One click to switch from Log to Block.”

The whole flow: Discovery finds your endpoints → You upload a schema → Cloudflare validates every request → Bad requests get logged or blocked → You see it all in one dashboard. Twenty minutes from zero to protected.

The Sales Angle

This is a real setup on a real site with real attacks being blocked. When I show a customer the Security Events dashboard, those aren’t simulated threats — those are actual bots that scanned my site in the last 24 hours.

The conversation goes like this: “This is my personal portfolio site and it’s already getting probed by bots from the Netherlands and Lithuania trying to steal .env files and WordPress configs. Imagine what’s hitting your production applications.”

Then I show the API Shield setup: “Here’s my OpenAPI schema. Here’s a good request going through. Here’s a bad request getting flagged. This took 20 minutes to set up. And once you flip it from Log to Block, Cloudflare enforces it at the edge before bad requests even reach your servers.”

The full stack is live:

All running on saltwaterbrc.com — visit /ask-ai to hit the AI agent endpoint, or /guestbook to hit the guestbook API. Both are now protected by schema validation.


Share this post on:

Previous Post
Cloudflare Spectrum: Protecting Non-HTTP Traffic at the Edge
Next Post
Building an AI Agent on Cloudflare: From RAG to Multi-Turn Conversations