Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Comprehensive Cloudflare platform skill covering Workers, D1, R2, KV, AI, Durable Objects, and security.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/waf/gotchas.md
1# Gotchas & Troubleshooting23## Execution Order45**Problem:** Rules execute in unexpected order6**Cause:** Misunderstanding phase execution7**Solution:**89Phases execute sequentially (can't be changed):101. `http_request_firewall_custom` - Custom rules112. `http_request_firewall_managed` - Managed rulesets123. `http_ratelimit` - Rate limiting1314Within phase: top-to-bottom, first match wins (unless `skip`)1516```typescript17// WRONG: Can't mix phase-specific actions18await client.rulesets.create({19phase: 'http_request_firewall_custom',20rules: [21{ action: 'block', expression: 'cf.waf.score gt 50' },22{ action: 'execute', action_parameters: { id: 'managed_id' } }, // WRONG23],24});2526// CORRECT: Separate rulesets per phase27await client.rulesets.create({ phase: 'http_request_firewall_custom', rules: [...] });28await client.rulesets.create({ phase: 'http_request_firewall_managed', rules: [...] });29```3031## Expression Errors3233**Problem:** Syntax errors prevent deployment34**Cause:** Invalid field/operator/syntax35**Solution:**3637```typescript38// Common mistakes39'http.request.path' → 'http.request.uri.path' // Correct field40'ip.geoip.country eq US' → 'ip.geoip.country eq "US"' // Quote strings41'http.user_agent eq "Mozilla"' → 'lower(http.user_agent) contains "mozilla"' // Case sensitivity42'matches ".*[.jpg"' → 'matches ".*\\.jpg$"' // Valid regex43```4445Test expressions in Security Events before deploying.4647## Skip Rule Pitfalls4849**Problem:** Skip rules don't work as expected50**Cause:** Misunderstanding skip scope51**Solution:**5253Skip types:54- `ruleset: 'current'` - Skip remaining rules in current ruleset only55- `phases: ['phase_name']` - Skip entire phases5657```typescript58// WRONG: Trying to skip managed rules from custom phase59// In http_request_firewall_custom:60{61action: 'skip',62action_parameters: { ruleset: 'current' },63expression: 'ip.src in {192.0.2.0/24}',64}65// This only skips remaining custom rules, not managed rules6667// CORRECT: Skip specific phases68{69action: 'skip',70action_parameters: {71phases: ['http_request_firewall_managed', 'http_ratelimit'],72},73expression: 'ip.src in {192.0.2.0/24}',74}75```7677## Update Replaces All Rules7879**Problem:** Updating ruleset deletes other rules80**Cause:** `update()` replaces entire rule list81**Solution:**8283```typescript84// WRONG: This deletes all existing rules!85await client.rulesets.update({86zone_id: 'zone_id',87ruleset_id: 'ruleset_id',88rules: [{ action: 'block', expression: 'cf.waf.score gt 50' }],89});9091// CORRECT: Get existing rules first92const ruleset = await client.rulesets.get({ zone_id: 'zone_id', ruleset_id: 'ruleset_id' });93await client.rulesets.update({94zone_id: 'zone_id',95ruleset_id: 'ruleset_id',96rules: [...ruleset.rules, { action: 'block', expression: 'cf.waf.score gt 50' }],97});98```99100## Override Conflicts101102**Problem:** Managed ruleset overrides don't apply103**Cause:** Rule ID doesn't exist or category name incorrect104**Solution:**105106```typescript107// List managed ruleset rules to find IDs108const ruleset = await client.rulesets.get({109zone_id: 'zone_id',110ruleset_id: 'efb7b8c949ac4650a09736fc376e9aee',111});112console.log(ruleset.rules.map(r => ({ id: r.id, description: r.description })));113114// Use correct IDs in overrides115{ action: 'execute', action_parameters: { id: 'efb7b8c949ac4650a09736fc376e9aee',116overrides: { rules: [{ id: '5de7edfa648c4d6891dc3e7f84534ffa', action: 'log' }] } } }117```118119## False Positives120121**Problem:** Legitimate traffic blocked122**Cause:** Aggressive rules/thresholds123**Solution:**1241251. Start with log mode: `overrides: { action: 'log' }`1262. Review Security Events to identify false positives1273. Override specific rules: `overrides: { rules: [{ id: 'rule_id', action: 'log' }] }`128129## Rate Limiting NAT Issues130131**Problem:** Users behind NAT hit rate limits too quickly132**Cause:** Multiple users sharing single IP133**Solution:**134135Add more characteristics: User-Agent, session cookie, or authorization header136```typescript137{138action: 'block',139expression: 'http.request.uri.path starts_with "/api"',140action_parameters: {141ratelimit: {142characteristics: ['cf.colo.id', 'ip.src', 'http.request.cookies["session"][0]'],143period: 60,144requests_per_period: 100,145},146},147}148```149150## Performance Issues151152**Problem:** Increased latency153**Cause:** Complex expressions, excessive rules154**Solution:**1551561. Skip static assets early: `action: 'skip'` for `\\.(jpg|css|js)$`1572. Path-based deployment: Only run managed on `/api` or `/admin`1583. Disable unused categories: `{ category: 'wordpress', enabled: false }`1594. Prefer string operators over regex: `starts_with` vs `matches`160161## Limits & Quotas162163| Resource | Free | Pro | Business | Enterprise |164|----------|------|-----|----------|------------|165| Custom rules | 5 | 20 | 100 | 1000 |166| Rate limiting rules | 1 | 10 | 25 | 100 |167| Rule expression length | 4096 chars | 4096 chars | 4096 chars | 4096 chars |168| Rules per ruleset | 75 | 75 | 400 | 1000 |169| Managed rulesets | Yes | Yes | Yes | Yes |170| Rate limit characteristics | 2 | 3 | 5 | 5 |171172**Important Notes:**173- Rules execute in order; first match wins (except skip rules)174- Expression evaluation stops at first `false` in AND chains175- `matches` regex operator is slower than string operators176- Rate limit counting happens before mitigation177178## API Errors179180**Problem:** API calls fail with cryptic errors181**Cause:** Invalid parameters or permissions182**Solution:**183184```typescript185// Error: "Invalid phase" → Use exact phase name186phase: 'http_request_firewall_custom'187188// Error: "Ruleset already exists" → Use update() or list first189const rulesets = await client.rulesets.list({ zone_id, phase: 'http_request_firewall_custom' });190if (rulesets.result.length > 0) {191await client.rulesets.update({ zone_id, ruleset_id: rulesets.result[0].id, rules: [...] });192}193194// Error: "Action not supported" → Check phase/action compatibility195// 'execute' only in http_request_firewall_managed196// Rate limit config only in http_ratelimit phase197198// Error: "Expression parse error" → Common fixes:199'ip.geoip.country eq "US"' // Quote strings200'cf.waf.score gt 40' // Use 'gt' not '>'201'http.request.uri.path' // Not 'http.request.path'202```203204**Tip**: Test expressions in dashboard Security Events before deploying.205