Debug Cloudflare 403 Blocks
Step-by-step guide for diagnosing why Cloudflare is returning a 403 for an API request. You will need the Ray ID from the blocked response.
Prerequisites
- Access to the Cloudflare Dashboard
- The Ray ID from the 403 response (found in the
cf-rayresponse header or on the block page itself)
Where to Find the Ray ID
The Ray ID appears in two places:
- Response header:
cf-ray: 8a1b2c3d4e5f6g7h-DFW(the suffix is the Cloudflare data center) - Block page HTML: displayed at the bottom of Cloudflare’s default 403 page
If the caller is an API client, capture the cf-ray
header from the response. Example with curl:
curl -v https://api.example.com/endpoint 2>&1 | grep -i cf-rayStep 1: Look Up the Ray ID in Security Events
- Log in to Cloudflare Dashboard
- Select the appropriate zone (domain)
- Go to Security > Events (under the Security section in the left sidebar)
- In the filter bar, add a filter: Ray ID equals
<your-ray-id> - Click the matching event to expand the details
This tells you exactly what blocked the request and why.
Step 2: Identify What Blocked the Request
The event detail shows a Service and Rule that triggered the block. Common sources:
| Service | What It Means |
|---|---|
| Security Rules (Managed) | Cloudflare Managed Ruleset or OWASP Core Ruleset flagged something in the request |
| Security Rules (Custom) | A custom security rule written by your team matched the request |
| Rate Limiting | Request exceeded a rate limit threshold |
| Bot Fight Mode | Cloudflare classified the caller as bot traffic |
| Cloudflare Access | The request failed an Access policy (missing/invalid JWT, wrong identity provider, IP not in policy) |
| IP Access Rules | The source IP is on a block list |
| Hotlink Protection | Hotlink protection is interfering with API calls (should not be enabled on API paths) |
Record the Rule ID, Rule name, and Action (Block, Challenge, JS Challenge, etc.).
Step 3: Inspect the Request Details
The event also shows the full request that was evaluated:
- Source IP and ASN
- Country
- URI path and query string
- HTTP method
- User-Agent
- Request headers
Compare these against what you expect. Common issues:
- Missing or generic
User-Agent(triggers bot detection) - Request body containing patterns that look like SQL injection or XSS to the managed ruleset (common with JSON payloads that include code snippets, HTML, or special characters)
- IP address from an unexpected region or cloud provider ASN
- Missing Cloudflare Access JWT (
cf-access-tokencookie orCF-Access-Client-Id/CF-Access-Client-Secretheaders)
Step 4: Fix the Block
If Security Rules (Managed Rules) blocked it
Managed rules live under Security > Security rules > Managed rules in the Cloudflare dashboard. THB currently has two active managed rulesets:
- Cloudflare Managed Ruleset (order 1) — matches all incoming requests
- Cloudflare OWASP Core Ruleset (order 2) — may have path exclusions configured (e.g., specific URI paths skipped via the “Match against” filter)
To investigate and fix:
- Note the Rule ID from the Security Event
- Go to Security > Security rules and select the Managed rules tab
- Click the ruleset name (e.g., “Cloudflare Managed Ruleset”) to see which individual rules are active
- Search for the Rule ID to find the specific rule that triggered
To add a path exclusion to a managed ruleset:
- Click the three-dot menu on the ruleset row
- Select Edit
- In the Match against filter, add a condition to
exclude the affected path. For example, if the OWASP ruleset is blocking
/ProviderDocuments/CreateAjax, add:URI Path does not equal /ProviderDocuments/CreateAjax - Save the rule
To create an exception (skip a specific rule):
- On the Security rules page, click Create rule
- Define a narrow match expression, for example:
- URI Path contains
/api/v1/specific-endpoint - AND Source IP is in
<your-known-IP-range>
- URI Path contains
- Set the action to Skip and select which managed rule(s) to skip
- Save and deploy
Other options (use sparingly):
- Set the rule to Log instead of Block while you investigate (click into the ruleset, find the rule, change its action)
- Disable the rule entirely (last resort, reduces security posture)
If a Custom Security Rule blocked it
Custom rules are also under Security > Security rules. Switch to the custom rules view (or look for rules not part of a managed ruleset).
- Find the rule by its name or ID from the Security Event
- Review the rule expression (it might be overly broad, e.g., blocking all non-browser User-Agents)
- Click the rule to edit its expression
- Adjust the expression to exclude the legitimate API traffic, or add an exception for the specific path/IP
- Save and deploy
If Rate Limiting blocked it
- Go to Security > Security rules and use the rule-type dropdown (defaults to Managed rules) or Show all rule types to find Rate limiting rules
- Find the matching rule
- Check the threshold (requests per period) and whether it’s appropriate for the API’s expected traffic volume
- Adjust the threshold, or add an exception for the caller’s IP/path
If Bot Fight Mode blocked it
Bot Fight Mode is designed for browser-facing sites and aggressively blocks automated traffic. It should not be enabled for API endpoints.
- Go to Security > Settings and find the Bots section (Bot Fight Mode lives here, not under a separate WAF/Bots menu)
- Check if Bot Fight Mode or Super Bot Fight Mode is enabled
- If the zone serves both browser and API traffic, create a custom
security rule to skip bot checks on API paths:
- Go to Security > Security rules
- Create a rule:
URI Path starts with /api/with action Skip and select Bot Fight Mode
If Cloudflare Access blocked it
THB uses Cloudflare Access with tunnels for internal services. A 403 from Access means the request failed the Access policy.
- Go to Access > Applications
- Find the application matching the blocked hostname
- Check the policies to understand who/what is allowed
- Common causes:
- Missing service token headers: API clients
authenticating via service tokens must include
CF-Access-Client-IdandCF-Access-Client-Secretheaders - Expired service token: check the token’s expiration in Access > Service Auth > Service Tokens
- IP not in policy: if the policy restricts by IP, confirm the caller’s egress IP is included
- Wrong identity provider: the user authenticated with a provider not allowed by the policy
- Missing service token headers: API clients
authenticating via service tokens must include
For service-to-service calls through Cloudflare tunnels, verify the
cloudflared service is running and the tunnel is
healthy:
# On the origin VM
docker service ls | grep cloudflared
docker service logs --tail 50 <cloudflared-service-name>If IP Access Rules blocked it
- Go to Security > Security rules, then use the rule-type dropdown or Show all rule types to find IP access rules
- Search for the blocked IP
- If it’s legitimately blocked, coordinate with whoever added the rule
- If it was added in error, remove or change the action to Allow
Step 5: Verify the Fix
After making changes, have the caller retry the request and confirm:
- The response is no longer a 403
- The
cf-rayheader is still present (confirms traffic is still going through Cloudflare) - Check Security > Events again to verify no new blocks
Quick Reference: Cloudflare Access Service Tokens
For API clients that need to authenticate through Cloudflare Access without browser-based login:
curl -H "CF-Access-Client-Id: <client-id>" \
-H "CF-Access-Client-Secret: <client-secret>" \
https://internal-app.thehelperbees.com/api/endpointService tokens are managed in Access > Service Auth > Service Tokens. They have configurable expiration and can be rotated without downtime by creating a new token before revoking the old one.
Not Cloudflare?
If the Ray ID returns no results in Security Events, the 403 may not be from Cloudflare:
- Check the response headers. A real Cloudflare block
will have
server: cloudflareand acf-rayheader. If these are absent, the 403 is coming from the origin application or reverse proxy (Caddy). - Wrong zone. Verify which Cloudflare zone the domain belongs to. You may be searching the wrong one.
- Check Caddy logs on the origin VM. Caddy sits between cloudflared and the application and can return its own 403s.