Technology

Cloudflare WAF and Rate Limiting for WordPress

Abusive bot traffic can slow WordPress and WooCommerce even when legitimate traffic is steady. Cloudflare WAF and rate limiting can reject unwanted requests before they reach the origin. Effective protection depends on identifying the affected endpoints and preserving login, checkout and integration flows.

This guide explains managed rules, custom expressions, endpoint-specific rate limits and a test-and-rollback process. The numerical limits are examples for evaluation, not universal recommendations or results from a customer deployment. Check current plan features and your site’s request patterns before enabling a rule.

Why WordPress Attracts Abusive Traffic

A traffic spike is not proof of a DDoS attack. Login attempts, XML-RPC requests, product scraping and repeated cart operations can exhaust resources in different ways. Compare request volume with PHP worker usage, response latency and completed customer operations before choosing a control.

The default /wp-login.php and /xmlrpc.php endpoints are easy to locate. The REST API intentionally exposes public data while permissions govern private operations. Cart fragments, Store API requests and plugin AJAX actions can also trigger expensive work. Identify the actual transport and handler; these are not interchangeable endpoints.

Managed WAF rules inspect known attack patterns. Custom rules match conditions on an individual request. Rate limiting maintains counters over a defined period. These controls complement application authentication and authorization; they do not replace them or guarantee that legitimate users will never be interrupted.

The Foundation: How Cloudflare Sees WordPress Traffic

What the Edge Can Evaluate

Cloudflare evaluates web requests to proxied hostnames. Requests that reach an exposed origin directly bypass this path. Available matching fields vary by product and plan: a field supported in a custom WAF rule is not necessarily available in a rate limiting expression.

Rejecting abusive traffic at the edge can reduce origin work. Choose an action compatible with the client: a browser page can sometimes complete Managed Challenge, while an API, XML-RPC client, webhook or background AJAX request generally cannot handle a full HTML challenge page.

Check Proxying, Origin Access and Critical Flows

Confirm the intended web hostnames are proxied and plan origin access separately. Restricting origin traffic to Cloudflare ranges is one layer; the shared network or default origin-pull certificate does not identify your own zone. Consider a properly configured Tunnel or origin authentication bound to your deployment, with expected hostnames and required operational access. Inventory login, public forms, checkout, REST routes, webhooks and third-party integrations before setting restrictions.

Use the CDN caching guide for WordPress and WooCommerce to plan cacheable content and bypasses. Cache hits can reduce PHP work, but Cloudflare’s WAF still evaluates requests served from cache. Keep personalized sessions, carts, checkout and authenticated responses out of shared caching.

WordPress Endpoints and Their Requirements

1) Login Requests

For /wp-login.php, distinguish a request matcher from an attempt counter. A path-and-method custom rule matches every matching POST. A rate limiting rule can count those requests over time, but does not know whether each password was wrong unless you supply a reliable, supported counting signal.

Managed Challenge can be evaluated for an interactive browser login, allowing for possible user interaction and retries. A shared office or mobile carrier IP may represent several people. Measure normal bursts and test login, password reset and required automation before selecting a threshold.

2) XML-RPC Integrations

Disable XML-RPC only after checking remote publishing, mobile clients and other integrations. It can still attract abuse, but current WordPress stops additional authentication attempts on the same XML-RPC server instance after an authentication failure; this limits the historical multicall password amplification technique. Required machine clients need authentication, appropriate source restrictions and measured limits, without browser challenges.

3) REST API and Store API

WordPress REST requests can use /wp-json/ or the rest_route query form. Discover the actual API root and any subdirectory installation. WooCommerce Store API routes serve customer-facing cart and checkout operations; separate wc-ajax and admin-ajax requests may also be present. Public GET requests can be abused, but write methods alone do not indicate an attack.

4) Public AJAX Handlers

/wp-admin/admin-ajax.php can serve logged-out visitors through wp_ajax_nopriv_* hooks. The action value may arrive in the POST body, not the query string. Inspect actual requests and plugin handlers before narrowing a limit. Cloudflare query argument fields do not inspect POST form data; http.request.body.form requires Enterprise and has parsing and body-size limits. Field access in rate limiting also depends on the relevant plan and Advanced Rate Limiting capabilities.

Cloudflare WAF Rules for WordPress

The examples below assume WordPress is installed at the hostname root. Adapt the host and base path, inspect rewrites and URL normalization, and test every accepted endpoint representation. These are independent options: enabling every example together can change which later rules run.

Login: Matching vs Counting

Decide whether you need a challenge on every login POST or only after a request-rate threshold. For most tuning exercises, start from measured traffic rather than a blanket challenge.

Optional custom-rule expression for every POST to the default login endpoint:

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

Managed Challenge on this expression applies to every matching login POST, subject to challenge clearance behavior; it does not count retries or failed passwords. Use the rate limiting example below if a threshold is intended. Do not add a global verified-bot or office-IP bypass. Custom rules run before rate limiting and managed rules; a terminating action can prevent later evaluation, so do not assume their counters see all attempts.

Block Unused XML-RPC

Optional custom-rule expression, only after confirming XML-RPC is unused:

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

Action: Block. If an integration requires XML-RPC, do not activate an unconditional block or browser challenge. Where reliable provider IP ranges exist, limit an exception to this endpoint and the specific blocking condition while retaining application authentication. User-agent strings and entire ASNs are not sufficient proof of an authorized integration.

Restrict Staff Administration Carefully

A network restriction is suitable only for staff-only administration with a tested recovery path. The example excludes two public handlers. Other public plugin handlers, alternate paths and subdirectory installs require additional review. It deliberately leaves the login endpoint outside this rule because sites can use it for customer or subscriber access.

(http.request.uri.path eq "/wp-admin" or starts_with(http.request.uri.path, "/wp-admin/"))
and not http.request.uri.path in {"/wp-admin/admin-ajax.php" "/wp-admin/admin-post.php"}
and not ip.src in {203.0.113.10 2001:db8::10}

Action: Block only after replacing both documentation addresses with your real static IPv4/IPv6 addresses and testing access from those networks. The addresses above are examples, not usable office addresses. This rule must not block the known public AJAX and form handlers. Inventory additional required handlers before enabling it. Restrict /wp-login.php separately only if it is exclusively for staff. An Access application also needs correctly scoped public-handler exclusions and tested service access.

Target Specific REST Routes

Select the exact abused route and preserve its authentication and authorization checks. Cover pretty-permalink and query-based REST access, rewrites and the actual installation path. Country or ASN alone does not establish abuse. Browser challenges are unsuitable for API consumers, webhooks and background requests expecting JSON.

Scope Verified-Bot Exceptions

Use Cloudflare’s verified bot signal when deciding access to appropriate public read routes. A verified identity does not grant unrestricted permission to log in, write through an API or bypass all security checks. Keep exemptions limited to the intended endpoint and rule; a user-agent claiming “Googlebot” is not verification.

Rate Limiting for WordPress and WooCommerce

Rate limits should reflect each endpoint’s normal volume and cost. A sale, a shared IP or plugin retries can create legitimate bursts. A block still rejects real operations if its threshold is wrong; replacing it with an HTML challenge does not solve API compatibility.

Plan Limits and Counter Scope

The method-based examples below require Business or a compatible Enterprise entitlement. Current standard limits are one rate rule on Free, two on Pro and five on Business. Free supports Path/Verified Bot matching and a 10-second counting period; Pro adds URI/host/query fields but not Method; Business adds Method and custom counting expressions. Check current limits and action options in your account.

Counters are scoped by data center, with sharing among data centers in the same geographical location; they are not one global per-IP counter. Updates can lag, so a rule is not a precise cap on requests reaching the origin.

These are dashboard-style settings, not API request payloads. The dashboard adds cf.colo.id to the characteristics automatically; API configurations must include it explicitly, and it must not be used as an expression field.

Login Rate Limit

Illustrative Business-compatible rate rule; adjust the threshold after measuring traffic:

Expression: (http.request.uri.path eq "/wp-login.php" and http.request.method eq "POST")
Counting: same expression; IP characteristic
Threshold: 10 requests / 60 seconds
Action: Managed Challenge
Mitigation timeout: 0 (challenge request throttling)

This counts login POST requests, including successful submissions, rather than failed passwords. Free/Pro/Business challenge actions use request throttling with mitigation timeout zero; a successful challenge resets the counter and another threshold crossing can challenge again. This is not an automatic Challenge-to-Block ladder. Any office exception must be limited to this rule and endpoint. Avoid assuming a response code of 401/403 means a failed WordPress password without verifying actual application behavior.

By default, the counting expression equals the matching expression. A custom counting expression does not inherit that filter: repeat the required endpoint and method conditions explicitly. Response-field counting happens after the response is sent.

Rate Limiting Required XML-RPC

Expression: (http.request.uri.path eq "/xmlrpc.php")
Counting: same expression; IP characteristic
Threshold: 5 requests / 60 seconds
Action: Block
Mitigation timeout: 10 seconds

The 5-per-minute threshold and 10-second block are illustrative and may interrupt valid integrations. A path-only 60-second rule fits Pro or higher, subject to current account options; it is not a Free 60-second recipe. This counts requests, not the XML-RPC methods or password attempts inside each request. Keep required integrations authenticated and test their legitimate bursts. A timed Block continues for its mitigation period even if the rate drops; it is not Enterprise-style Block throttling with timeout zero.

REST API and WooCommerce

Target a demonstrated abuse pattern. The following Business-compatible example covers only POST to the canonical Store API add-item path. It is a candidate for a controlled test, not a recommendation to throttle every shop or every REST write. It excludes other routes and cannot distinguish legitimate buyers sharing an IP.

Expression: (http.request.uri.path eq "/wp-json/wc/store/v1/cart/add-item" and http.request.method eq "POST")
Counting: same expression; IP characteristic
Threshold: 30 requests / 60 seconds
Action: Block
Mitigation timeout: 10 seconds

Before enabling this rule, inventory and cover equivalent query-based rest_route access, installation prefixes and rewritten paths in appropriate additional expressions or origin/application controls. A path-only rule is not complete route protection. The 30-per-minute threshold and 10-second block need measured justification; test the client’s 429 handling and checkout recovery. Do not return Managed Challenge to this JSON endpoint.

Action-Specific AJAX Limits

Do not start with a broad challenge on all AJAX POST requests. Determine which handler is expensive, whether it is public, and how its action value is submitted. If your plan cannot match the required POST body field, implement an action-aware limit in the application or a supported origin layer. Query-only filtering misses body actions.

AJAX review worksheet (not an executable Cloudflare rule)
Identify: actual base path and plugin handler
Inspect: action in query, form body or another transport
Measure: normal requests per client and shared-IP bursts
Select: supported counter, justified threshold, API-compatible response
Test: public forms, cart, checkout, retries and rollback

The review worksheet above is intentionally not a deployable rule. A 120-per-minute blanket threshold cannot establish safety for unknown plugins. Keep checkout, cart refreshes and public forms in the test matrix; correlate the selected handler with origin cost before deciding on a count and response.

Tuning Actions and Rule Order

Promotions require observed capacity and traffic baselines. Change only the affected rule and retain a rollback path. Neither challenges nor short blocks are automatically harmless, and one rule does not escalate to another without explicit configuration. Check ordering and the counters actually reached by each request.

Testing and Observability

Check Preview and Logging Availability

Use the preview or Rules simulator capabilities available in your account, and inspect existing traffic before enforcement. Log for custom rules is Enterprise-only; a universal Log/Simulate mode cannot be assumed. Without it, use a narrow controlled test with a known rollback. Log matching on a Skip rule records a real bypass and is not a harmless substitute for a dry run.

Inspect Security Events

Review Security Events for matched rule IDs, actions, endpoints and timing, then compare with origin and application logs. Available event detail, retention and analytics depend on the plan. A quiet dashboard alone does not prove success: legitimate actions and origin resource use must also be measured.

Review Public Crawler Access

If a public search crawler is affected, confirm its verified identity and the specific rule involved. The verified bots documentation describes the signal. Exempt only the necessary public-read scope; preserve login and API write protections and respect your own crawler access policy.

Correlate Edge and Origin Logs

Correlate timestamps and request identifiers where available. A request blocked at Cloudflare normally never reaches PHP, so an absent origin log entry is expected for that request. An origin-generated 403 and an edge-generated 403 are different events; do not infer one from the other.

Choose a Review Schedule

Review after deployment, plugin changes and traffic shifts; a weekly review during rollout and a later monthly review are example schedules. Record false positives, unprotected routes, resource use and the reason for each threshold change. Choose the cadence against your risk and traffic.

Compatibility and Deployment Pitfalls

Test the Actual Checkout Flow

A hypothetical checkout failure may come from limiting a shared AJAX endpoint. Capture the store’s actual request flow: it may use Store API routes, wc-ajax, admin-ajax or a plugin-specific combination. Test guest and signed-in checkout, coupons, cart updates, payment callbacks and retries in a sandbox. Use only a narrow, justified exception if a required action is blocked.

Keep Caching and WAF Roles Clear

Caching and WAF solve different problems. Cache eligible static or anonymous content, while preserving private-response bypasses; cached requests still pass through WAF evaluation. The WordPress and WooCommerce CDN caching guide covers those policies. A cache hit reduces origin work, not the need to evaluate edge security.

Do Not Trust User Agents Alone

User-agent strings are client-controlled. Combine appropriate verified identity, endpoint context and measured behavior instead of treating a familiar header as authorization. Ordinary custom rules do not track arbitrary sequences such as “submitted a form and immediately retried”; use supported counters or application signals for that.

Use Country and ASN Filters Carefully

Country and ASN restrictions can affect legitimate customers, traveling administrators and service providers. ASN means autonomous system number; an ASN-wide filter can cover many unrelated users and is not inherently more precise than country filtering. Apply either only with a documented reason, narrow scope and tested access recovery.

Check Bot Product Capabilities

Bot Fight Mode on Free and Super Bot Fight Mode on Pro/Business have different controls. WAF Skip can target the Super Bot Fight Mode phase; it cannot skip Free Bot Fight Mode. Do not assume an “allow” rule fixes every bot-product false positive. Review Cloudflare bot product setup, available settings and WordPress compatibility, then test required clients before enabling broader protection.

Retire Obsolete Threat-Score Rules

The current cf.threat_score field always returns zero and must not be used as a working risk signal. Other scores have their own product and plan requirements. Select documented, available signals and verify their meaning rather than copying older threat-score recipes.

Deployment Checklist

1) Check Available Managed Rules

Cloudflare Free Managed Ruleset is available on all plans; the Cloudflare Managed Ruleset and OWASP Core Ruleset require Pro or higher. Review the managed rules overview and available account controls. Managed rules reduce some known attack patterns; they neither repair vulnerable plugins nor cover every OWASP risk. Document any managed-rule exception and place it before the ruleset execution it is intended to skip.

2) Select Custom Controls

Choose the controls your site needs; these options are not a mandatory three-rule bundle. Current custom-rule allowances are Free 5, Pro 20 and Business 100, with Enterprise entitlements checked separately.

Login: prefer a measured rate rule when the goal is counting requests. Use a custom Managed Challenge on every login POST only with an explicit browser-flow requirement and an understanding that it can terminate processing before later phases.

XML-RPC: block only when unused. Otherwise retain required integrations with authentication and an appropriately scoped rate or source restriction; do not use browser challenges.

Administration: restrict staff-only paths with a tested network or identity policy. Preserve public admin-ajax/admin-post handlers and any additional plugin endpoints. Restrict login separately only when the site does not use that endpoint for public accounts.

3) Select Endpoint-Specific Rate Limits

Allocate the rate rules your plan supports to measured risks. The following numbers summarize the illustrative examples; they do not constitute universal safe limits:

Login POST: 10 requests per 60 seconds per IP, Managed Challenge, on Business or compatible Enterprise. It counts requests, not failed credentials, and uses the plan’s challenge-throttling semantics.

Required XML-RPC: 5 requests per 60 seconds per IP, Block for 10 seconds, as a Pro-or-higher path-only example. Validate integration bursts and action options before use.

Selected Store API add-item POST: 30 requests per 60 seconds per IP, Block for 10 seconds, as a Business-compatible canonical-path example. Cover alternate routing and test 429 recovery before enabling; no blanket REST write challenge.

AJAX: choose a verified handler and transport first. There is no generic 120-per-minute challenge recommendation. If the required body field is unavailable at the edge, enforce the selected action’s limit in a supported application or origin layer.

4) Test Application Flows

Use an authorized test environment and sandbox payment mode. Exercise guest and staff login, password reset, cart/checkout, public forms, API clients and payment callbacks. Test allowed and disallowed staff networks, shared-IP bursts, alternate REST forms, installation prefixes and rewritten paths. Record expected matches and actual rule IDs; verify rollback without sending real payments or customer messages.

5) Observe and Adjust

Investigate missing events before changing thresholds: the route may differ, an earlier action may terminate processing, or a bypass may skip the rule. Check source restrictions and analytics availability. For false positives, identify the affected condition and client flow, then narrow or disable that rule; do not automatically switch APIs from Block to Challenge.

Application and Integration Controls

Preserve Required Services

Payment, inventory and monitoring services may not be verified bots. Preserve application authentication or signed callbacks. If a WAF exception is necessary, scope it to the relevant endpoint, method and rule using reliable provider restrictions where available. Modify the offending rule when practical; a phase-wide Skip can bypass every rate rule, so it is broader than a single-rule exception. Avoid global IP Allow and user-agent-only trust.

Keep WordPress Updated

Keep WordPress, plugins and themes supported and updated; remove unused components and require appropriate authentication and privileges. Hiding a login link is not access control. Check that application security and edge controls do not create incompatible authentication, rate or challenge behavior.

Validate Turnstile on the Server

Turnstile can add verification to a browser form when integrated correctly. The widget alone is insufficient: the backend must call Siteverify and reject invalid results before processing the action. Tokens expire after five minutes and are single-use. Test hostname/action binding and error handling as appropriate; Turnstile is not a replacement for authentication or a general fix for machine-client challenges.

Document Expected Behavior and Recovery

Give editors and support staff a way to report the affected URL, time and request identifier without sharing credentials. Document expected login verification, recovery access and the rollback owner. Treat a new checkout or integration failure as something to investigate, not proof that a challenge is working.

Hypothetical Store Tuning Scenario

Consider a hypothetical store where PHP workers spike while ordinary visitor volume remains steady. Logs show repeated product lookups and cart operations. This suggests endpoints to investigate; it does not establish the cause until requests are correlated with resource use and normal customer behavior.

In that scenario, separate public reads from cart writes and identify the exact transports. Evaluate narrowly scoped limits with client-compatible responses, covering alternate route forms and shared-IP bursts. Compare origin load, latency and completed sandbox orders before and after the controlled change. No customer result, one-day improvement or interruption-free checkout is claimed here.

Measure Security and Performance Together

A useful result is measured reduction in abusive origin work while required operations continue to succeed. Track resource use, latency, blocked legitimate requests and completed orders over comparable periods. WAF configuration alone cannot promise lower hosting bills, zero spikes or smooth checkout during every promotion.

Pair that evaluation with the WordPress and WooCommerce CDN caching guide. Keep private responses out of shared caches and remember that edge security still evaluates cache hits. Attribute performance changes to measured behavior, including cache misses and revalidation.

Maintain and Validate the Configuration

Inventory endpoints first, confirm plan capabilities, and choose actions compatible with each client. Protect login, required XML-RPC and selected REST/AJAX operations without blanket exceptions. Check custom-rule → rate-limiting → managed-rule ordering, test real application flows in a safe environment and retain a documented rollback.

Maintain the configuration as routes, integrations and traffic change. Use the official references below alongside your own event and application evidence. A correct expression is only one part of a deployment: accepted syntax, plan entitlement, routing coverage and business-flow validation must all be checked in the target account.

Technical References

Frequently Asked Questions

False positives are possible. Measure normal traffic, choose client-compatible actions and test guest checkout, login and required integrations. Verified-bot exceptions should cover only appropriate public read routes and the relevant rule, not login or all API writes. Managed Challenge can interrupt background requests expecting JSON. Investigate affected rule IDs and narrow or roll back the rule instead of assuming a generous threshold is always safe.

Block it only after confirming remote publishing and integrations do not need it. Required XML-RPC clients should retain authentication and suitable source or rate restrictions; they generally cannot complete browser challenges. A request counter does not count every method or password attempt inside a request, and current WordPress limits the historical multicall authentication amplification behavior.

Identify the actual Store API, wc-ajax, admin-ajax and plugin routes before choosing limits. Target demonstrated abuse, cover alternate REST routing and account for shared-IP bursts. An action value may be in a POST body; query fields do not inspect it, and required body fields have plan restrictions. Do not challenge every REST write or AJAX POST. Test 429 handling, cart, coupons, guest and signed-in checkout, callbacks and retries in a sandbox; retain narrow exceptions and a rollback.
↑