Skip to content

Security Level — Challenge Sensitivity

DodaTech 5 min read

Cloudflare Security Level determines how aggressively to challenge visitors based on their IP reputation score — offering a sliding scale from essentially trust-everything to challenge-everything.

What You Will Learn

You will learn how Security Level interacts with IP reputation scores, how to tune it for different parts of your site, and how to override it for specific paths using page rules or WAF expressions.

Why It Matters

A single security level for the entire site is rarely optimal. Login pages and admin panels benefit from higher sensitivity, while static content and public APIs should have lower sensitivity to avoid false positives.

Real-World Use Case

A community forum uses Security Level set to High for all /login/* and /register/* paths using a page rule, while the public content pages remain at Medium. This keeps spammers out of signup flows without challenging legitimate readers browsing forum threads.

How Security Level Works

Cloudflare assigns every IP address a threat score based on factors including known attack sources, behaviour patterns, and global threat intelligence. The Security Level setting maps threat score ranges to challenge thresholds.

flowchart LR
  A[Visitor IP] --> B{Check Threat Score}
  B -->|Score 0-49| C["Low / No Challenge"]
  B -->|Score 50-69| D[Medium Challenge]
  B -->|Score 70-99| E[High Challenge]
  B -->|Score 100+| F[I'm Under Attack!]
  C --> G[Origin]
  D --> G
  E -->|JS Challenge| G
  F -->|5-second wait| G

Security Level Tiers

Level Threat Score Threshold Behavior
Essentially Off Ignores threat scores No IP-based challenges
Low Scores above 80 Challenges highly suspicious IPs
Medium (default) Scores above 60 Balances protection and friction
High Scores above 40 More aggressive challenges
I'm Under Attack! Scores above 20 JS challenge + 5s delay

Setting Security Level via API

curl -X PATCH "https://api.cloudflare.com/client/v4/zones/ZONE_ID/settings/security_level" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"value": "high"}'

Expected output:

{
  "result": {
    "id": "security_level",
    "value": "high",
    "modified_on": "2026-06-23T10:00:00Z"
  },
  "success": true
}

Page Rule: Different Levels per Path

Apply different security levels to different URL patterns using page rules:

curl -X POST "https://api.cloudflare.com/client/v4/zones/ZONE_ID/pagerules" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "targets": [
      {"target": "url", "constraint": {"operator": "matches", "value": "*example.com/admin*"}}
    ],
    "actions": [
      {"id": "security_level", "value": "high"}
    ],
    "status": "active"
  }'

Expected output:

{
  "result": {
    "id": "page_rule_id",
    "status": "active",
    "targets": [{"target": "url", "constraint": {"operator": "matches", "value": "*example.com/admin*"}}],
    "actions": [{"id": "security_level", "value": "high"}]
  },
  "success": true
}

Python: Analyse Threat Score Distribution

import os
import requests

ZONE_ID = os.environ["CLOUDFLARE_ZONE_ID"]
TOKEN = os.environ["CLOUDFLARE_API_TOKEN"]
URL = f"https://api.cloudflare.com/client/v4/zones/{ZONE_ID}/analytics/dashboard"

headers = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}
resp = requests.get(URL, headers=headers)
data = resp.json()

# Extract threat score buckets from analytics (simplified)
col = data["result"]["totals"].get("threats", {})
print(f"Threats blocked: {col.get('blocked', 0)}")
print(f"Threats challenged: {col.get('challenged', 0)}")
print(f"Threats passed: {col.get('passed', 0)}")

Expected output:

Threats blocked: 2341
Threats challenged: 892
Threats passed: 45

Node.js: Toggle Security Level on Schedule

const fetch = require("node-fetch");

const ZONE_ID = process.env.CLOUDFLARE_ZONE_ID;
const TOKEN = process.env.CLOUDFLARE_API_TOKEN;
const HOUR = new Date().getHours();
const isBusinessHours = HOUR >= 8 && HOUR <= 20;
const level = isBusinessHours ? "medium" : "high";

fetch(
  `https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/settings/security_level`,
  {
    method: "PATCH",
    headers: {
      Authorization: `Bearer ${TOKEN}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ value: level }),
  }
)
  .then((r) => r.json())
  .then((d) => console.log("Set security_level to", d.result.value));

Expected output:

Set security_level to medium

Common Mistakes

Mistake Consequence
Setting to I'm Under Attack! permanently Poor user experience for all visitors
Using Low on login pages Allows brute force from suspicious IPs
Not creating overrides for API paths API clients hit JS challenge walls
Forgetting that page rules cost plan credits Page rules consume your plan quota
Not reviewing threat analytics Blind to whether level is effective

Practice Questions

  1. What is the default Security Level and what threat score threshold does it use?
  2. How can you use page rules to apply a different Security Level to your checkout page?
  3. Why is I'm Under Attack! unsuitable as a permanent setting?

Challenge

Create a Cloudflare Worker or cron job that checks the current time and automatically switches Security Level from Medium (daytime) to High (nighttime) for a zone using the API. Log each change to a file.

Real-World Task

Your site has an API endpoint at /api/v1/* that receives requests from mobile apps. Apply a Security Level override for this path so it uses Essentially Off while keeping the rest of the site at Medium. Test that API clients are not challenged while web visitors still have protection.

FAQ

What threat sources does Cloudflare use to compute IP reputation?

Cloudflare combines data from Project Honey Pot, its own global attack telemetry across 330+ data centres, and feedback from the Cloudflare community. Scores are updated in near real-time as new threats are identified across the network.

Does Security Level affect cached content delivery?

No. Security Level and its associated challenges are evaluated before the cache check. Visitors blocked or challenged never reach the cache. But once a Visitor passes a challenge, their subsequent requests to cached resources are served normally from edge cache.

Can I see which visitors were challenged due to Security Level?

Yes. The Security Events log under Security > Events shows all challenged and blocked requests. Each event includes the threat score, the action taken, and the Cloudflare data centre that handled the request. Filter by Security Level action type to isolate these events.


Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro — security-first tools for the modern web.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro