Introduction
Cloudflare's Web Application Firewall (WAF) protects against common attacks like SQL injection, XSS, and OWASP vulnerabilities. However, legitimate traffic can trigger WAF rules when requests contain patterns that resemble attack payloads. API requests with complex parameters, webhook payloads, form submissions with special characters, and certain application frameworks can all trigger false positives. Resolving these requires identifying which rule is blocking traffic and creating appropriate exceptions.
Symptoms
- Users seeing 403 Forbidden or WAF block page
- API requests returning WAF block instead of application response
- Webhook deliveries from Stripe, GitHub, or other services failing
- Form submissions blocked on specific fields
- Admin panel or CMS functionality blocked
- Security Events showing high false positive count
Common Causes
- Managed WAF rules too aggressive for application type
- OWASP Core Rule Set triggering on legitimate request patterns
- Request body containing strings resembling SQL/XSS
- API payloads with special characters flagged as injection
- Specific URL paths matching attack patterns
- Rule sensitivity level too high (High vs Medium vs Low)
- Missing rule exceptions for known application patterns
Step-by-Step Fix
- 1.Identify which WAF rule is causing the block:
Navigate to: Cloudflare Dashboard > Security > Events
Filter by: - Action: Block - Source: WAF - Time range: when block occurred
Click on blocked request to see: - Rule ID (e.g., OWASP CRS rule ID) - Rule description - Matched pattern/field - Request details
- 1.Examine the blocked request details:
# Check Security Events for request details
# Look at:
# - URI path that triggered block
# - Request body content
# - Query parameters
# - Headers
# - Which rule matched- 1.Determine if block is legitimate or false positive:
``` # Signs of false positive: # - Known internal IP or trusted user # - API call from registered webhook source # - Form submission with expected special characters # - Request pattern matches application functionality
# Signs of actual attack: # - Unknown suspicious IP # - Request contains actual SQL injection attempt # - XSS payload with script tags # - Path traversal or command injection patterns ```
- 1.Adjust rule sensitivity level:
Navigate to: Security > WAF > Managed Rules
For OWASP Core Rule Set: - Change sensitivity from High to Medium or Low - Each level disables more aggressive rules - Medium is good balance for most applications
# OWASP Paranoia Levels:
# PL1 (Low): Minimal rules, few false positives
# PL2 (Medium): Standard rules, balanced protection
# PL3 (High): More rules, more false positives
# PL4 (Very High): All rules, many false positives- 1.Disable specific problematic rules:
In Managed Rules > OWASP Core Rule Set: - Click "View rules" - Find the specific rule ID causing false positives - Change action from "Block" to "Log" temporarily - Or disable the rule entirely for your zone
# Via API - disable specific rule
curl -X PATCH "https://api.cloudflare.com/client/v4/zones/ZONE_ID/rulesets/phases/http_request_firewall_managed/entrypoint" \
-H "Authorization: Bearer API_TOKEN" \
-H "Content-Type: application/json" \
--data '{
"rules": [{
"id": "rule_id_here",
"action": "skip",
"expression": "true"
}]
}'- 1.Create skip rule for specific paths:
Navigate to: Security > WAF > Custom Rules
Create rule: - Expression: URL path matches specific endpoint - Action: Skip - Select which WAF rules to skip
``` # Example: Skip WAF for API webhook endpoints # Expression: (http.request.uri.path contains "/api/webhooks/") # Action: Skip > All remaining custom rules and WAF managed rules
# Or skip specific rule groups: # Skip > OWASP Core Rule Set ```
- 1.Create skip rule for trusted IPs:
``` # Expression: IP address in trusted range # Expression: (ip.src in {192.0.2.0/24 203.0.113.0/24})
# For known webhook sources, find their IPs: # Stripe: https://stripe.com/docs/ips # GitHub: https://docs.github.com/en/github/authenticating-to-github/about-githubs-ip-addresses # Slack: varies, use domain-based or hostname matching ```
- 1.Skip WAF for specific request methods:
``` # Skip WAF for OPTIONS requests (CORS preflight) # Expression: (http.request.method eq "OPTIONS")
# Skip for GET requests to safe paths # Expression: (http.request.method eq "GET" and http.request.uri.path in {"/api/public/*"}) ```
- 1.Use request body inspection settings:
Navigate to: Security > WAF
``` # For APIs with complex JSON payloads: # - Consider disabling request body inspection # - Or increase body size limit for inspection
# Settings: # - Request Body Inspection: Off (for APIs) # - Or set higher size limit ```
- 1.Configure rule for specific content types:
``` # Skip WAF for specific content types # Expression: (http.request.headers["content-type"] contains "application/json")
# This allows JSON API payloads without WAF inspection # Combine with path-based rule for API endpoints ```
- 1.Test fix with simulated request:
```bash # Test previously blocked request curl -X POST https://yourdomain.com/api/webhooks \ -H "Content-Type: application/json" \ -d '{"data": {"field": "value with special chars: <>&\\"}'
# Should return 200, not 403 or WAF block ```
- 1.Monitor Security Events after changes:
```bash # Watch for new false positives # Dashboard > Security > Events
# If still seeing blocks: # - Further adjust sensitivity # - Add more specific skip rules # - Check if new rules are triggering ```
Verification
After applying fixes:
- 1.Legitimate requests return 200 instead of 403
- 2.API endpoints function without WAF blocks
- 3.Webhook deliveries succeed
- 4.Security Events show reduced false positives
- 5.Actual attack patterns still blocked (verify with test payloads)