feat: add opt-in build flag to match v2's @rx anchor semantics (#3295)#3600
Open
fzipi wants to merge 3 commits into
Open
feat: add opt-in build flag to match v2's @rx anchor semantics (#3295)#3600fzipi wants to merge 3 commits into
fzipi wants to merge 3 commits into
Conversation
libmodsecurity's shared Regex class compiles all patterns with PCRE(2)_MULTILINE, while ModSecurity v2's @rx operator uses PCRE(2)_DOLLAR_ENDONLY, so ^/$ anchor differently against multi-line values between the two engines (owasp-modsecurity#3295). Add --enable-regex-dollar-endonly, off by default, mirroring the build-flag rollout Coraza used for the same issue (corazawaf/coraza#876). When enabled, only @rx and @rxglobal compile with DOLLAR_ENDONLY instead of MULTILINE; every other Regex caller (verifyCC, verifySSN, verifyCPF, internal chain/audit-log regexes) keeps its current behavior, matching how v2 itself only applies DOLLAR_ENDONLY to @rx. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds an opt-in build-time switch to make libmodsecurity v3’s @rx/@rxGlobal anchor behavior match ModSecurity v2 by compiling those operators with DOLLAR_ENDONLY instead of MULTILINE, while keeping existing behavior as the default.
Changes:
- Introduces
--enable-regex-dollar-endonlyto defineMODSEC_REGEX_DOLLAR_ENDONLYat build time. - Extends
Utils::Regexwith amultiLineconstructor parameter controlling whetherMULTILINEorDOLLAR_ENDONLYis used. - Updates
@rxand@rxGlobalto use the new mode when the build flag is enabled and documents the flag inREADME.md.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| configure.ac | Adds a new --enable-regex-dollar-endonly configure switch that injects -DMODSEC_REGEX_DOLLAR_ENDONLY=1 into build flags. |
| src/utils/regex.h | Extends the Regex constructor with a multiLine parameter (defaulting to current behavior). |
| src/utils/regex.cc | Switches regex compilation options between MULTILINE and DOLLAR_ENDONLY based on multiLine. |
| src/operators/rx.cc | Makes @rx select multiLine=false when MODSEC_REGEX_DOLLAR_ENDONLY is enabled. |
| src/operators/rx_global.cc | Makes @rxGlobal select multiLine=false when MODSEC_REGEX_DOLLAR_ENDONLY is enabled. |
| README.md | Documents the new build flag and the intended behavioral difference for anchors. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- README: clarify that MULTILINE controls where ^/$ can anchor (per-line vs. whole-subject), while DOLLAR_ENDONLY only further refines $ against a trailing newline; DOTALL is unchanged either way so . still matches across internal line breaks. - Add test/unit/regex_multiline_test.cc, a standalone regression test for the multiLine constructor parameter added to Utils::Regex, covering both the multiLine=true (default) and multiLine=false paths. Wired into test/Makefile.am as its own noinst_PROGRAMS binary and into test/test-suite.in / test-suite.sh (the existing dispatcher only knew how to run JSON test-case files against unit_tests/regression_tests). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
airween
reviewed
Jul 19, 2026
…ndalone test binary Per @airween's review feedback: the regression test framework already supports skipping a JSON test case at runtime via a "resource" key (test/regression/regression.cc), matching it against a list of compile-time-enabled features (WITH_CURL, WITH_LUA, WITH_LIBXML2, etc.). Register "regex-dollar-endonly" the same way under MODSEC_REGEX_DOLLAR_ENDONLY, and add test/test-cases/regression/operator-rx-dollar-endonly.json gated on it, covering both a single-line match (still blocks) and a multi-line ARGS value (anchors no longer span line breaks). Builds without the flag skip these two cases; builds with it pass. This replaces the standalone regex_multiline_test.cc binary and its Makefile.am/test-suite.in/test-suite.sh wiring from the previous commit, which needlessly diverged from how every other test in this project is structured. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
Closes the behavioral gap described in #3295:
@rxin libmodsecurity (v3) compiles patterns withPCRE(2)_DOTALL | PCRE(2)_MULTILINE, while ModSecurity v2's@rx(msre_op_rx_param_init) usesPCRE(2)_DOTALL | PCRE(2)_DOLLAR_ENDONLY. This means^/$anchors behave differently against multi-line values (e.g. multi-lineARGS) between the two engines, which is what surfaced as a CRS false-positive/negative report in coreruleset/coreruleset#3277.Both commenters on #3295 agreed the target behavior should be v2's flags; the open question was only the rollout mechanism. This PR follows airween's proposal to use a build flag, mirroring the approach Coraza already shipped for the same issue (corazawaf/coraza#876, merged, gated behind
coraza.rule.no_regex_multiline, off by default).configure.ac: adds--enable-regex-dollar-endonly(off by default), definingMODSEC_REGEX_DOLLAR_ENDONLYwhen enabled.src/utils/regex.h/regex.cc:Regexgains amultiLineconstructor parameter, defaulting totrue(current behavior). All existing callers (verifyCC,verifySSN,verifyCPF, internal chain/audit-log/collection regexes, etc.) are unaffected since they don't pass the new parameter.src/operators/rx.cc/rx_global.cc: only@rxand@rxGlobalpassmultiLine=falsewhen the build flag is set, compiling withDOTALL | DOLLAR_ENDONLYinstead ofDOTALL | MULTILINE. This mirrors v2, where only@rxusesDOLLAR_ENDONLYwhile other operators (verifyCC,verifySSN,gsbLookup) keepMULTILINEunconditionally.README.md: documents the new flag next to the existing PCRE2/PCRE section.Test plan
Utils::Regexdirectly against both the PCRE2 and legacy PCRE1 backends, confirmingmultiLine=falsereproduces v2's dollar-endonly anchor semantics (no match across internal line breaks; trailing-newline$behavior matches PCRE'sDOLLAR_ENDONLYdocs) whilemultiLine=truepreserves current behavior../configure && makesucceeds with the flag both off (default) and on (--enable-regex-dollar-endonly=yes).SecRule ARGS:param1 "^hello.*world$" "deny"evaluated against a multi-lineARGSvalue. Default build blocks (reproducing the current v3 behavior described in Operator @rx has different flags in two engines #3295); with the flag enabled it does not block (matching v2).🤖 Generated with Claude Code