Skip to content

blog: crs migration part 6#507

Open
fzipi wants to merge 7 commits intomainfrom
blog/crs-migration-part-6
Open

blog: crs migration part 6#507
fzipi wants to merge 7 commits intomainfrom
blog/crs-migration-part-6

Conversation

@fzipi
Copy link
Copy Markdown
Member

@fzipi fzipi commented May 3, 2026

Summary by CodeRabbit

  • Documentation
    • Added a new blog post (2026-05-04) on CRS 4 false-positive tuning and production cutover workflows.
    • Describes two tuning approaches, a three-phase rollout (detection validation, log-based checks, cutover), common post-migration FP sources, and how to create narrowly scoped exclusions (per-path/parameter).
    • Notes CRS 4.25 LTS maintenance expectations and links to the next installment on engine-specific considerations.

fzipi and others added 5 commits March 31, 2026 09:10
Covers two migration strategies (start fresh vs carry over), safe
production cut-over phases (parallel detection, validation, cut-over),
common false positive areas after the migration, and the new per-PL
reporting model for systematic tuning.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sets refLinksErrorLevel=WARNING so cross-post ref links don't break
the build when sibling posts don't yet exist on the same branch.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The author is already shown from the front matter. Adds the
related-pages shortcode to cross-link migration series posts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@fzipi fzipi requested a review from theseion May 3, 2026 13:38
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 3, 2026

Review Change Stack
No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2a8f2cdf-10b4-4182-ba1b-9883771c17a9

📥 Commits

Reviewing files that changed from the base of the PR and between e6e3edf and 2130fd3.

📒 Files selected for processing (1)
  • content/blog/2026-05-04-migrating-from-crs-3-to-crs-4-part-6-tuning.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • content/blog/2026-05-04-migrating-from-crs-3-to-crs-4-part-6-tuning.md

📝 Walkthrough

Walkthrough

Adds a new blog post (Part 6) describing two CRS 4 false-positive tuning strategies, a three-phase production migration workflow, common post-migration false-positive categories, per-paranoia-level scoped exclusion techniques with an example SecRule, and CRS 4.25.0 LTS maintenance notes; links to Part 7.

Changes

CRS Migration Part 6 Blog Post

Layer / File(s) Summary
Front Matter & Introduction
content/blog/2026-05-04-migrating-from-crs-3-to-crs-4-part-6-tuning.md (lines 1–14)
Blog metadata (author, date, categories/tags, image, title, slug) and opening context for false-positive tuning workflow.
Migration Strategies
content/blog/2026-05-04-migrating-from-crs-3-to-crs-4-part-6-tuning.md (lines 16–63)
Two tuning strategies: start fresh with CRS 4 and run extended detection-mode validation, or carry over CRS 3 exclusions with mapping/removal and a shorter detection pass; includes step-by-step procedures.
Production Migration Phases
content/blog/2026-05-04-migrating-from-crs-3-to-crs-4-part-6-tuning.md (lines 66–94)
Three-phase production sequence: detection-mode validation (options A/B/C), validation review checklist after detection logging, and blocking cutover while preserving enhanced logging temporarily.
False-Positive Sources & Tuning Guidance
content/blog/2026-05-04-migrating-from-crs-3-to-crs-4-part-6-tuning.md (lines 95–108)
Lists common FP sources (response-phase web shell patterns, restricted headers, PL redistribution, plugin exclusion ID differences).
Per-Paranoia Reporting & Scoped Exclusions
content/blog/2026-05-04-migrating-from-crs-3-to-crs-4-part-6-tuning.md (lines 109–128)
Explains per-PL reporting for rule/parameter-level FP identification; favors narrowly scoped exclusions and shows example SecRule with ctl:ruleRemoveTargetById=...;ARGS:... targeted to a URI path/parameter.
Maintenance & Navigation
content/blog/2026-05-04-migrating-from-crs-3-to-crs-4-part-6-tuning.md (lines 129–137)
Documents CRS 4.25.0 LTS maintenance expectations (stability with security backports) and links to Part 7 plus related-page metadata.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested reviewers

  • theseion

Poem

🐰 A tuning post hops to the fore,
Rules pared down to just what's right,
Per-PL maps the false alarms,
Detection logs shine guiding light,
LTS steadies the path tonight.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'blog: crs migration part 6' accurately reflects the main change: adding a new blog post for part 6 of the CRS 3 to CRS 4 migration series covering false-positive tuning.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch blog/crs-migration-part-6

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Microsoft Presidio Analyzer (2.2.362)
content/blog/2026-05-04-migrating-from-crs-3-to-crs-4-part-6-tuning.md

Microsoft Presidio Analyzer failed to scan this file

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented May 3, 2026

Deploying website with  Cloudflare Pages  Cloudflare Pages

Latest commit: 2130fd3
Status: ✅  Deploy successful!
Preview URL: https://97dd8466.website-1u6.pages.dev
Branch Preview URL: https://blog-crs-migration-part-6.website-1u6.pages.dev

View logs

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (4)
content/blog/2026-05-04-migrating-from-crs-3-to-crs-4-part-6-tuning.md (4)

16-17: 💤 Low value

Minor editorial: consider removing duplicate/indirect framing.

The opening references “Part 6 … tuning phase” and also points back to Part 5; that’s good, but it may be slightly redundant with the next-line “This post covers the tuning phase itself…” framing. A small tightening would reduce scroll friction.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@content/blog/2026-05-04-migrating-from-crs-3-to-crs-4-part-6-tuning.md`
around lines 16 - 17, Tighten the duplicate framing in the intro by removing or
rephrasing the second sentence ("This post covers the tuning phase itself — the
practical work of establishing a clean CRS 4 baseline for your applications.")
so it doesn't repeat the opener ("This is Part 6..."). Edit the sentence
containing "This post covers the tuning phase itself" to either merge it with
the Part 6 line or replace it with a brief lead-in that adds new value (e.g., a
one-line summary of the post's specific goal), updating the lines that contain
"This is Part 6..." and "This post covers the tuning phase itself" accordingly.

68-92: ⚡ Quick win

Soften fixed time windows into “coverage-based” criteria.

The post uses fixed durations (e.g., “1–2 weeks”, “at least two weeks”, “one to two weeks”, and “first week after cut-over”). In practice, traffic patterns differ (seasonality, rollout timing, low-traffic endpoints), so a reader might disable enhanced logging/exclusions before all workflows have been exercised. Consider adding a brief criterion such as “until you’ve observed peak traffic + all critical workflows at least once” (or “one full business cycle”) while keeping the suggested defaults as examples.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@content/blog/2026-05-04-migrating-from-crs-3-to-crs-4-part-6-tuning.md`
around lines 68 - 92, Update the fixed-duration recommendations in the Phase
1/Phase 2/Phase 3 guidance to include a coverage-based stopping criterion: keep
the example durations (e.g., “1–2 weeks”, “first week after cut-over”) but add a
sentence such as “or until you’ve observed peak traffic and all critical
workflows at least once (one full business cycle),” and apply this to the
detection phase, the validation phase, and the post-cutover logging guidance;
edit the headings/paragraphs referencing “detection mode”, “anomaly threshold
9999”, and the cut-over week to incorporate the new coverage-based criterion
while retaining the example time windows as defaults.

103-106: 💤 Low value

Narrow the “PL redistribution” explanation to avoid overgeneralization.

“New firings are most common in SQL injection and XSS detection rules” is plausible, but it’s still a broad expectation. Readers may over-focus their triage and miss other classes (e.g., request-method/header handling rules). Consider phrasing this as “often includes …” and adding a tip to sort/frequency-rank by rule ID firing counts before deciding where to tune first.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@content/blog/2026-05-04-migrating-from-crs-3-to-crs-4-part-6-tuning.md`
around lines 103 - 106, Revise the "PL redistribution" paragraph to avoid
overgeneralization: change "The new firings are most common in SQL injection and
XSS detection rules." to a softer phrasing like "New firings often include SQL
injection and XSS detection rules, but can affect other categories (for example,
request-method or header-handling rules)." Then add a concise tip sentence
recommending readers frequency-rank or sort rule-ID firing counts before tuning
(e.g., "Tip: frequency-rank rule ID firing counts to prioritize tuning
efforts"). Update the "PL redistribution" heading paragraph and include the
brief ranking tip so readers don’t over-focus on only SQLi/XSS.

115-126: ⚡ Quick win

Make the SecRule exclusion example slightly more robust/readable for copy-paste.

The example is internally consistent, but copy/paste readers may miss subtle ordering/placement requirements. You already mention the filename (REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf), but consider also adding one extra line in the example comment like “Load this before CRS core rules” and/or clarifying why the actions are pass,nolog (it’s an exclusion ctl, not a detection rule). This reduces the chance of someone accidentally deploying it in the wrong include file or expecting it to “block” something.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@content/blog/2026-05-04-migrating-from-crs-3-to-crs-4-part-6-tuning.md`
around lines 115 - 126, Update the SecRule example to make placement and intent
explicit: in the comment above the rule (in
REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf) add a note like “Load this file
before CRS core rules” and a short explanation that the actions pass,nolog are
used because this is an exclusion ctl
(ctl:ruleRemoveTargetById=941100;ARGS:content) not a blocking detection rule;
keep the SecRule signature (SecRule REQUEST_URI "@beginsWith /editor/save"
"id:1001,phase:2,pass,nolog,ctl:ruleRemoveTargetById=941100;ARGS:content") but
ensure the example comment clarifies file ordering and the reason for pass,nolog
so copy-paste users won’t place it after the CRS core rules or expect it to
block requests.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@content/blog/2026-05-04-migrating-from-crs-3-to-crs-4-part-6-tuning.md`:
- Around line 16-17: Tighten the duplicate framing in the intro by removing or
rephrasing the second sentence ("This post covers the tuning phase itself — the
practical work of establishing a clean CRS 4 baseline for your applications.")
so it doesn't repeat the opener ("This is Part 6..."). Edit the sentence
containing "This post covers the tuning phase itself" to either merge it with
the Part 6 line or replace it with a brief lead-in that adds new value (e.g., a
one-line summary of the post's specific goal), updating the lines that contain
"This is Part 6..." and "This post covers the tuning phase itself" accordingly.
- Around line 68-92: Update the fixed-duration recommendations in the Phase
1/Phase 2/Phase 3 guidance to include a coverage-based stopping criterion: keep
the example durations (e.g., “1–2 weeks”, “first week after cut-over”) but add a
sentence such as “or until you’ve observed peak traffic and all critical
workflows at least once (one full business cycle),” and apply this to the
detection phase, the validation phase, and the post-cutover logging guidance;
edit the headings/paragraphs referencing “detection mode”, “anomaly threshold
9999”, and the cut-over week to incorporate the new coverage-based criterion
while retaining the example time windows as defaults.
- Around line 103-106: Revise the "PL redistribution" paragraph to avoid
overgeneralization: change "The new firings are most common in SQL injection and
XSS detection rules." to a softer phrasing like "New firings often include SQL
injection and XSS detection rules, but can affect other categories (for example,
request-method or header-handling rules)." Then add a concise tip sentence
recommending readers frequency-rank or sort rule-ID firing counts before tuning
(e.g., "Tip: frequency-rank rule ID firing counts to prioritize tuning
efforts"). Update the "PL redistribution" heading paragraph and include the
brief ranking tip so readers don’t over-focus on only SQLi/XSS.
- Around line 115-126: Update the SecRule example to make placement and intent
explicit: in the comment above the rule (in
REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf) add a note like “Load this file
before CRS core rules” and a short explanation that the actions pass,nolog are
used because this is an exclusion ctl
(ctl:ruleRemoveTargetById=941100;ARGS:content) not a blocking detection rule;
keep the SecRule signature (SecRule REQUEST_URI "@beginsWith /editor/save"
"id:1001,phase:2,pass,nolog,ctl:ruleRemoveTargetById=941100;ARGS:content") but
ensure the example comment clarifies file ordering and the reason for pass,nolog
so copy-paste users won’t place it after the CRS core rules or expect it to
block requests.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9fc19c04-e0b2-4dc0-9e23-390368499184

📥 Commits

Reviewing files that changed from the base of the PR and between 1bbaae1 and e6e3edf.

⛔ Files ignored due to path filters (1)
  • static/images/2026/04/pexels-northern-29268627.jpg is excluded by !**/*.jpg
📒 Files selected for processing (1)
  • content/blog/2026-05-04-migrating-from-crs-3-to-crs-4-part-6-tuning.md


There are two approaches to handling false positive tuning during the migration. Neither is universally better — choose based on the size and complexity of your existing setup.

### Strategy A: Start Fresh
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A think these two subsections are a bit misleading. Reading them, I come to the conclusion that I will have to run detection mode without an active WAF, i.e., replace CRS 3 with 4 immediately. Only when reading "Running a Safe Production Migration" does it become clear that it's possible to run both versions in parallel. I think that needs to be part of the introduction: you can migrate without having to turn off your WAF.


**Dual WAF deployment.** Route a copy of your traffic (via mirroring or a dedicated logging endpoint) through CRS 4 in detection mode, while CRS 3 continues blocking for real traffic. Compare the CRS 4 detection results against known good requests in your access logs.

**Single WAF, detection mode.** If a parallel setup is not practical, swap CRS 3 for CRS 4 in pure detection mode. You lose blocking during this phase, so only do this if your threat model allows a temporary blocking gap (e.g. you have another upstream protection layer).
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't parallel detection. Either rename the section or split into a separate section.


**Single WAF, detection mode.** If a parallel setup is not practical, swap CRS 3 for CRS 4 in pure detection mode. You lose blocking during this phase, so only do this if your threat model allows a temporary blocking gap (e.g. you have another upstream protection layer).

**WAF-engine anomaly logging.** Some WAF engine setups allow you to log anomaly score results without blocking, even when blocking is technically enabled, by setting the anomaly threshold very high (e.g. `9999`). Set your CRS 4 thresholds to `9999` during the detection phase so that nothing is blocked even if the score exceeds the normal threshold.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not clear how this is meant to work. Would CRS 3 continue to run with CRS 4 running in the same engine? Probably not, since that would lead to rule ID conflicts. So is this an alternative to "detection only mode" when that is not supported by the engine?

**Single WAF, detection mode.** If a parallel setup is not practical, swap CRS 3 for CRS 4 in pure detection mode. You lose blocking during this phase, so only do this if your threat model allows a temporary blocking gap (e.g. you have another upstream protection layer).

**WAF-engine anomaly logging.** Some WAF engine setups allow you to log anomaly score results without blocking, even when blocking is technically enabled, by setting the anomaly threshold very high (e.g. `9999`). Set your CRS 4 thresholds to `9999` during the detection phase so that nothing is blocked even if the score exceeds the normal threshold.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the migration option that Fränzi presented should be the recommended one, even though it's more complicated. Did you omit it on purpose?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, that is an official blogpost from a company, not CRS 🤷 . Are we making the official migration recommendation something outside CRS?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I'm not saying to point there, but to describe the method. It's not like the method is patented. It's just a bit of extra work, but at the huge benefit that you can run both rulesets at the same time. Of course, we should talk to Fränzi and Christian first.


**Response-phase web shell rules.** Applications that return debugging output or verbose error messages containing shell-like text. Check your application's error pages, debug endpoints, and admin panels.

**Restricted headers — basic list.** Requests that include `Content-Encoding`, `X-HTTP-Method-Override`, or `Expect`. These are blocked at all paranoia levels. Common sources: upload clients that set `Content-Encoding`, JavaScript frameworks using `X-HTTP-Method-Override` for form method override, and .NET clients using `Expect: 100-continue`.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIRC, at least for .NET that behaviour is configurable. Maybe at least mention that possibility here. Seeing such a header does not necessarily mean that a change to the WAF is necessary, maybe the application can be configured differently.

# In REQUEST-900-EXCLUSION-RULES-BEFORE-CRS.conf
# Exclude rule 941100 (XSS via libinjection) for the /editor/save path
SecRule REQUEST_URI "@beginsWith /editor/save" \
"id:1001,phase:2,pass,nolog,\
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this rule be in phase 1?

- Clarify that migration strategies are independent of rollout, and you do
  not have to turn off your WAF to validate CRS 4
- Restructure Phase 1 detection options: rename to "Detection-Mode
  Validation" and label dual-WAF as the only true parallel option;
  clarify single-WAF and anomaly-threshold-override approaches swap CRS
  3 for CRS 4 (no rule ID conflicts) and call out the anomaly-threshold
  trick as a fallback when the engine has no detection-only switch
- Suggest configuring the client (e.g. .NET Expect: 100-continue) before
  adding a WAF exclusion for restricted headers
- Move SecRule exclusion example from phase 2 to phase 1
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants