WordPress powers over 40% of the web, making it the single most targeted CMS by automated bots, script kiddies, and sophisticated attackers alike. Every unprotected WordPress site faces thousands of malicious requests daily — brute force login attempts, XML-RPC amplification attacks, SQL injection probes, and directory traversal scans. Cloudflare’s Web Application Firewall (WAF) provides a powerful free defense layer that stops these attacks at the edge, before they ever reach your server. In this guide, you will configure custom WAF rules that block the most common WordPress attack vectors.

Prerequisites

  • A Cloudflare account (free plan works for up to 5 custom rules)
  • Your domain’s DNS managed by Cloudflare (orange-cloud proxied)
  • A running WordPress installation
  • Admin access to the Cloudflare dashboard
  • Your current public IP address (for whitelisting admin access)

Why WordPress Needs WAF Protection

WordPress sites face a relentless barrage of automated attacks. According to Wordfence data, a typical WordPress site sees 90,000+ malicious login attempts per month. The most exploited endpoints are:

  • xmlrpc.php — used for brute force amplification (one request can test hundreds of passwords), DDoS via pingback abuse, and SSRF attacks
  • wp-login.php — targeted by credential stuffing bots running leaked password lists
  • wp-admin/ — probed for unauthenticated access to admin functions
  • wp-json/wp/v2/ — REST API enumeration exposes usernames and content structure
  • Query strings — SQL injection attempts via ?id=1 UNION SELECT, path traversal via ../../etc/passwd

A server-level firewall like iptables only sees IP addresses. Cloudflare WAF inspects HTTP requests at layer 7 — it can match URI paths, query strings, headers, request methods, and user agents. This lets you write precise rules that block attacks without affecting legitimate visitors.

Essential WAF Rules

Navigate to your Cloudflare dashboard: Security > WAF > Custom rules. You will create these rules in order of priority.

Rule 1: Block xmlrpc.php

This is the single most impactful rule. xmlrpc.php accounts for the majority of brute force traffic on most WordPress sites.

Expression:
(http.request.uri.path eq "/xmlrpc.php")

Action: Block

If you rely on Jetpack or the WordPress mobile app, change the action to Managed Challenge instead of Block. But if you can disable xmlrpc entirely, block it.

Rule 2: Challenge wp-login.php

Rather than blocking the login page outright, use a managed challenge so legitimate admins can still get through while bots are stopped.

Expression:
(http.request.uri.path eq "/wp-login.php")

Action: Managed Challenge

This forces Cloudflare’s smart challenge (CAPTCHA or JS challenge) on every login page request. Automated bots fail the challenge; real humans pass it transparently.

Rule 3: Restrict wp-admin by IP

Lock down the admin area to your IP address. The critical detail here is excluding admin-ajax.php, which WordPress uses for frontend AJAX calls (contact forms, WooCommerce cart updates, etc.).

Expression:
(http.request.uri.path contains "/wp-admin"
  and not http.request.uri.path contains "admin-ajax.php"
  and not ip.src in {203.0.113.50})

Action: Block

Replace 203.0.113.50 with your actual IP. You can add multiple IPs using a list: {203.0.113.50 198.51.100.25}.

Rule 4: Block SQL Injection and Path Traversal

Catch common injection patterns in the full URI, including query strings.

Expression:
(http.request.uri contains "union select"
  or http.request.uri contains "concat("
  or http.request.uri contains "../"
  or http.request.uri contains "eval("
  or http.request.uri contains "<script"
  or http.request.uri contains "etc/passwd")

Action: Block

This rule catches the most frequent SQLi and XSS payloads. The patterns cover UNION-based injection, path traversal, JavaScript injection, and local file inclusion attempts.

Rule 5: Block Malicious User Agents

Many attack tools use identifiable user agents. Combine bot blocking into one rule to save your free-plan rule slots.

Expression:
(http.request.uri.path contains "/wp-"
  and (http.user_agent contains "sqlmap"
    or http.user_agent contains "nikto"
    or http.user_agent contains "wpscan"
    or http.user_agent contains "masscan"
    or http.user_agent eq ""))

Action: Block

Empty user agents on WordPress endpoints are almost always malicious scanners. This rule blocks them along with known attack tool signatures.

Free vs Pro vs Business WAF Features

FeatureFreePro ($20/mo)Business ($200/mo)
Custom WAF rules520100
Managed rulesets (OWASP)NoYesYes
Rate limiting rules11050
Bot managementBasicEnhancedAdvanced
Custom error pagesNoYesYes
WAF analyticsBasic eventsDetailedFull with logs
IP access rulesUnlimitedUnlimitedUnlimited
Response header modificationNoYesYes

For most WordPress sites, the free plan with 5 well-crafted custom rules covers 90% of attack traffic. Upgrade to Pro if you need managed OWASP rulesets or more rule slots.

Real-World Scenario

You run a WordPress e-commerce site on WooCommerce that processes 500 orders per day. Your server logs show 1,200+ failed login attempts daily to wp-login.php, your xmlrpc.php gets hit 8,000 times a day from botnets, and you have noticed SQL injection strings appearing in your query logs. Your hosting provider warns you about CPU spikes from processing all these malicious requests.

After enabling the five WAF rules above, Cloudflare blocks 95% of this traffic at the edge. Your server CPU drops by 40%, page load times improve because your PHP workers are not busy processing attack requests, and your hosting costs stay flat instead of scaling up. The managed challenge on wp-login.php stops credential stuffing while your editorial team logs in without issues. The wp-admin IP restriction means even if an attacker gets credentials, they cannot reach the dashboard from their IP.

Rate Limiting for WordPress

Rate limiting adds a time-based dimension to your protection. Navigate to Security > WAF > Rate limiting rules.

Login Page Rate Limit

Expression:
(http.request.uri.path eq "/wp-login.php" and http.request.method eq "POST")

Rate: 5 requests per 10 seconds
Action: Block for 600 seconds (10 minutes)
Counting expression: Same as rule expression

REST API Rate Limit

Expression:
(http.request.uri.path contains "/wp-json/")

Rate: 30 requests per 10 seconds
Action: Managed Challenge

This prevents API enumeration and abuse while allowing normal REST API usage from themes and plugins.

Gotchas and Edge Cases

admin-ajax.php must be excluded — WordPress uses admin-ajax.php for frontend AJAX requests even for logged-out visitors. Contact forms, WooCommerce add-to-cart, and infinite scroll all use this endpoint. Blocking it behind an IP restriction breaks your entire frontend.

WooCommerce REST API — if you use the WooCommerce REST API for external integrations (shipping providers, inventory sync, POS systems), ensure your rate limiting on /wp-json/ does not block these services. Whitelist their IPs or use a higher threshold.

Cron and scheduled taskswp-cron.php is hit by Cloudflare cached pages. If you use server-side cron (recommended), you can block external access to wp-cron.php in a WAF rule.

Plugin updates and file uploads — some plugins make requests to wp-admin paths during auto-updates. Your IP restriction rule handles this as long as the server itself is not proxied through an external service that changes the source IP.

Country blocking caution — avoid blocking entire countries unless you truly have no users there. Country-level blocks can inadvertently block search engine crawlers that route through those countries, impacting your SEO.

Test thoroughly — after enabling rules, open an incognito window and test: visit the homepage, navigate to a product page, submit a contact form, and log in to wp-admin. Check Security > Events for any false positives.

Summary

  • Block xmlrpc.php completely — it is the most abused WordPress endpoint and most sites do not need it
  • Use managed challenges on wp-login.php to stop bots while allowing human admins through
  • Restrict wp-admin by IP but always exclude admin-ajax.php to avoid breaking frontend functionality
  • Add SQL injection and XSS pattern matching to catch common injection payloads at the edge
  • Configure rate limiting on login and REST API endpoints to throttle brute force attempts
  • Cloudflare’s free plan gives you 5 custom rules — enough to cover the critical WordPress attack surface
  • Monitor Security Events after deploying rules and adjust for false positives
  • Consider Cloudflare Access (Zero Trust) for dynamic IP scenarios instead of IP whitelisting