Cloudflare WAF Security Incident Triage: A Standard Operating Procedure

Overview
Cloudflare’s WAF generates security events every time a firewall rule triggers — whether from managed rules, custom rules, rate limiting, or bot detection. When incidents recur (scanner sweeps, CVE probes, credential stuffing), it’s valuable to have a consistent triage procedure so you can quickly identify what’s happening, which rules are firing, and whether any gaps exist.
This SOP covers how to pull and interpret security events for any zone using the Cloudflare GraphQL Analytics API and the wrangler CLI.
Prerequisites
wranglerCLI installed and authenticated (wrangler login)- Access to the target Cloudflare account and zone
- Your Account ID and Zone ID on hand
Quick Reference — mcmsp.dev
| Field | Value |
|---|---|
| Account | Master Concept Demo (mcmsp.dev) |
| Account ID | b326904912840c25f63808a1d1e479aa |
| Zone ID | f7e211c055a837203d618519e74665d9 |
The Prompt
Paste the following into any Claude Code session to run a full triage:
Check Cloudflare security analytics for mcmsp.dev (account: Master Concept Demo,
account_id: b326904912840c25f63808a1d1e479aa, zone_id: f7e211c055a837203d618519e74665d9).
Use the Cloudflare GraphQL API with wrangler auth token.
Steps:
1. Query `firewallEventsAdaptive` for the last 30 days (all actions, limit 100, orderBy datetime_DESC)
Fields: action, clientIP, clientRequestPath, clientRequestQuery, ruleId, source, datetime
2. Summarize:
- Total events, breakdown by action and source
- Top attacker IPs and hit counts
- Top blocked paths (most common first)
- Date range of events
3. List all events in a table: #, Datetime, Action, Source, Client IP, Path
4. For each unique ruleId found, re-query firewallEventsAdaptive with extra fields:
description, matchIndex, ref
Then summarize which managed rule triggered and what CVEs/attack category it covers.
5. Highlight any events with action = log, challenge, managed_challenge, or skip
— these are candidates to upgrade to block.
How It Works
Step 1 — Retrieve the Auth Token
wrangler auth token
This outputs a bearer token used for all subsequent API calls.
Step 2 — Query Security Events via GraphQL
Cloudflare exposes security analytics through its GraphQL API at https://api.cloudflare.com/client/v4/graphql. The key dataset is firewallEventsAdaptive.
CF_TOKEN="<your-token>"
ZONE_ID="f7e211c055a837203d618519e74665d9"
START=$(date -u -v-30d '+%Y-%m-%dT%H:%M:%SZ')
END=$(date -u '+%Y-%m-%dT%H:%M:%SZ')
curl -s -X POST "https://api.cloudflare.com/client/v4/graphql" \
-H "Authorization: Bearer $CF_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"query\": \"{ viewer { zones(filter: {zoneTag: \\\"$ZONE_ID\\\"}) {
firewallEventsAdaptive(
filter: { datetime_geq: \\\"$START\\\", datetime_leq: \\\"$END\\\" },
limit: 100,
orderBy: [datetime_DESC]
) { action clientIP clientRequestPath ruleId source datetime }
} } }\"
}"
Step 3 — Identify the Blocking Rule
Once you have a ruleId, re-query with the description field to get the human-readable rule name and associated CVEs:
curl -s -X POST "https://api.cloudflare.com/client/v4/graphql" \
-H "Authorization: Bearer $CF_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"query\": \"{ viewer { zones(filter: {zoneTag: \\\"$ZONE_ID\\\"}) {
firewallEventsAdaptive(
filter: { datetime_geq: \\\"$START\\\", datetime_leq: \\\"$END\\\",
ruleId: \\\"$RULE_ID\\\" },
limit: 1
) { action ruleId source description matchIndex ref }
} } }\"
}"
The description field returns the rule name, e.g.:
DotNetNuke - File Inclusion - CVE:CVE-2018-9126, CVE:CVE-2011-1892 2
Step 4 — Assess Gaps
| Action | Meaning | Recommendation |
|---|---|---|
block |
Already stopped | No action needed |
log |
Observed, not blocked | Review and consider upgrading to block |
managed_challenge |
CAPTCHA challenge served | Consider block if clearly malicious |
challenge |
JS challenge served | Same as above |
skip |
Rule bypassed | Verify bypass is intentional |
Real Example
Incident: Mar 15, 2026 — 100 requests from 185.177.72.22 over 2 seconds
| Field | Detail |
|---|---|
| Attacker IP | 185.177.72.22 |
| Paths targeted | /webhook/*, /form/* upload/file endpoints |
| Rule triggered | e7e4b386797e417c998d872956c390a1 |
| Rule name | DotNetNuke - File Inclusion |
| CVEs | CVE-2018-9126, CVE-2011-1892 |
| Action | Block (all 100 requests) |
| Source | firewallManaged |
Verdict: Scanner probing for DNN CMS file inclusion vulnerabilities. Cloudflare managed rules blocked everything. No action required.
Tips
- The API returns a maximum of 100 events per query. For high-traffic zones, narrow the time window or filter by IP/action.
firewallEventsAdaptiveis the recommended dataset — it adapts sampling based on traffic volume.- Keep your
wranglerCLI updated (npm install -g wrangler@latest) — older versions may have API compatibility issues. - Bookmark the Cloudflare dashboard path: Zone → Security → Analytics → Events for a visual view of the same data.
Created: 2026-03-19