Skip to content

blog: crs migration part 6#507

Open
fzipi wants to merge 9 commits into
mainfrom
blog/crs-migration-part-6
Open

blog: crs migration part 6#507
fzipi wants to merge 9 commits into
mainfrom
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

Warning

Review limit reached

@fzipi, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 23 minutes and 35 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 83331b60-4683-46ec-94f1-b94bce9883e6

📥 Commits

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

📒 Files selected for processing (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

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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: a77469e
Status: ✅  Deploy successful!
Preview URL: https://b6519717.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.

Comment thread content/blog/2026-05-04-migrating-from-crs-3-to-crs-4-part-6-tuning.md Outdated
Comment thread content/blog/2026-05-04-migrating-from-crs-3-to-crs-4-part-6-tuning.md Outdated
**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.

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.

Added as Option D in Phase 1 (commit a77469e). It describes the netnea CRS Upgrading Plugin approach: renumbering CRS 4's rule IDs and renaming its anomaly-score variables so both rule sets run in a single engine — CRS 3 keeps blocking while CRS 4 records, with per-request tagging to diff the two, and path/percentage-based cutover.

I also corrected the earlier claim that running both rule sets in one engine "is not supported because of rule ID conflicts" — that's exactly what the plugin solves.

Kept it to a brief mention + link rather than reproducing the full implementation, since the plugin is the canonical version. Flagging that this still needs sign-off from Fränzi and Christian before we merge, as you suggested — happy to hold until they've confirmed they're OK with us pointing here.

Comment thread content/blog/2026-05-04-migrating-from-crs-3-to-crs-4-part-6-tuning.md Outdated
Comment thread content/blog/2026-05-04-migrating-from-crs-3-to-crs-4-part-6-tuning.md Outdated
fzipi and others added 3 commits May 7, 2026 11:41
- 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
Add Option D to Phase 1 covering the single-engine parallel approach
(rule-ID renumbering and score-variable renaming) and correct the claim
that both rule sets cannot run in one engine.

Pending sign-off from netnea (Fränzi/Christian) before merge.
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