From cce2c2a2791d74556aea04c800691c34a746ebe7 Mon Sep 17 00:00:00 2001 From: Felipe Zipitria Date: Mon, 26 Oct 2026 18:04:53 -0300 Subject: [PATCH 1/2] Document TX:MSC_PCRE_ERROR in ModSecurity v2 Since owasp-modsecurity/ModSecurity#3709 (released in 2.9.16), v2 sets TX:MSC_PCRE_ERROR when an @rx pattern is invalid after macro expansion or a regex execution fails, and a negated !@rx no longer matches on a regex error. The MSC_PCRE_ERROR entry still called the flag v3-only. Update the variable entry, the reserved TX names list, the @rx notes and the explanation of rule 200005 in the recommended configuration. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01RiUJuqXNvvpytiGRiDFyTy --- .../3-10-recommended-base-configuration.md | 6 ++++-- content/3-reference-manual/3-3-variables.md | 5 ++++- content/3-reference-manual/3-6-operators.md | 2 ++ 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/content/3-reference-manual/3-10-recommended-base-configuration.md b/content/3-reference-manual/3-10-recommended-base-configuration.md index 796d947..2e75625 100644 --- a/content/3-reference-manual/3-10-recommended-base-configuration.md +++ b/content/3-reference-manual/3-10-recommended-base-configuration.md @@ -156,8 +156,10 @@ SecRule TX:/^MSC_/ "!@streq 0" \ The PCRE limits cap the work a single regular expression may do, against regular-expression denial of service. When a limit is hit the engine sets `TX:MSC_PCRE_LIMITS_EXCEEDED` instead of matching, and rule 200005 turns any such -`MSC_` flag into a denial. In v3 `SecPcreMatchLimitRecursion` is accepted but ignored, and the match limit is -honored since 3.0.10. +`MSC_` flag into a denial. Since 2.9.16, v2 also sets `TX:MSC_PCRE_ERROR` when a pattern is invalid after macro +expansion, and this rule catches it too. In v3 `SecPcreMatchLimitRecursion` is accepted but ignored, and the match limit +is honored since 3.0.10. v3 reports other regex errors in the standalone `MSC_PCRE_ERROR` variable, which +`TX:/^MSC_/` does not see. ## Response body handling diff --git a/content/3-reference-manual/3-3-variables.md b/content/3-reference-manual/3-3-variables.md index 5b32be6..cf52e33 100644 --- a/content/3-reference-manual/3-3-variables.md +++ b/content/3-reference-manual/3-3-variables.md @@ -412,7 +412,9 @@ SecRule ARGS "@pm some key words" "id:12345,deny,status:500" {{< secmeta v2="no" v3="3.0.10" >}} -libModSecurity v3 only: set to 1 when the @rx or @rxGlobal operator fails with any PCRE error, for example an invalid pattern after macro expansion or a match-limit error (in the latter case MSC_PCRE_LIMITS_EXCEEDED is set as well). ModSecurity v2 has no equivalent variable. +MSC_PCRE_ERROR will be set to 1 when the @rx or @rxGlobal operator fails with any PCRE error, for example an invalid pattern after macro expansion or a match-limit error (in the latter case MSC_PCRE_LIMITS_EXCEEDED is set as well). + +ModSecurity v2 does not provide this as a standalone variable. Since 2.9.16, when the @rx pattern is invalid after macro expansion, or a regex execution fails with an error other than a PCRE limit, v2 sets the transaction variable TX:MSC_PCRE_ERROR to 1. Rule 200005 in modsecurity.conf-recommended (`SecRule TX:/^MSC_/ "!@streq 0"`) catches it. libModSecurity v3 does not set TX:MSC_PCRE_ERROR, so on v3 test the standalone variable instead. ## MSC_PCRE_LIMITS_EXCEEDED @@ -1391,6 +1393,7 @@ Some variable names in the TX collection are reserved and cannot be used: - TX:1-TX:9: the captured subexpression value when using the @rx operator with capturing parens and the capture action. ModSecurity v2 stores at most nine captures (TX:1 to TX:9); libModSecurity v3 stores every capturing group of the expression (the v3 manual documents TX:1 to TX:99). - TX:MSC_.*: ModSecurity processing flags - MSC_PCRE_LIMITS_EXCEEDED: Set to nonzero if PCRE match limits are exceeded. See SecPcreMatchLimit and SecPcreMatchLimitRecursion for more information. +- MSC_PCRE_ERROR: Set to 1 by ModSecurity v2 (since 2.9.16) when a regular expression fails with an error other than a PCRE limit, for example an invalid pattern after macro expansion. See MSC_PCRE_ERROR. ## UNIQUE_ID diff --git a/content/3-reference-manual/3-6-operators.md b/content/3-reference-manual/3-6-operators.md index 61bb746..fc155ad 100644 --- a/content/3-reference-manual/3-6-operators.md +++ b/content/3-reference-manual/3-6-operators.md @@ -661,6 +661,8 @@ Regular expressions are a very powerful tool. You are strongly advised to read t Macro expansion is supported since ModSecurity 2.6.2: a pattern containing `%{...}` is expanded and compiled on every evaluation instead of once at startup. +If the expanded pattern is not a valid regular expression, or a PCRE limit is exceeded, neither @rx nor !@rx matches. The error is visible through the TX:MSC_PCRE_ERROR or TX:MSC_PCRE_LIMITS_EXCEEDED flag. Before 2.9.16, v2 did not set TX:MSC_PCRE_ERROR, and a negated !@rx matched on these errors. + {{% notice note %}} libModSecurity v3 compiles patterns with PCRE2_DOTALL and PCRE2_MULTILINE instead, so `^` and `$` also match at inner line boundaries. Rules that need line anchors should write `(?m)` explicitly to behave the same in both versions. In v3 a pattern that is invalid at load time rejects the rule, a pattern that becomes invalid after macro expansion does not match and sets MSC_PCRE_ERROR, and an empty pattern matches everything. SecPcreMatchLimit is honored since 3.0.10: when the limit is exceeded the operator does not match and MSC_PCRE_LIMITS_EXCEEDED and TX:MSC_PCRE_LIMITS_EXCEEDED are set to 1. From 9eded1aa60e60d588d9b3ee2613462dcda870f7c Mon Sep 17 00:00:00 2001 From: Felipe Zipitria Date: Mon, 26 Oct 2026 18:09:18 -0300 Subject: [PATCH 2/2] Document TX:MSC_PCRE_ERROR in libModSecurity v3 owasp-modsecurity/ModSecurity#3711 makes @rx and @rxGlobal set TX:MSC_PCRE_ERROR next to the standalone variable, including on match limit errors, so rule 200005 sees every regex error. Replace the statement that v3 does not set the TX flag. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01RiUJuqXNvvpytiGRiDFyTy --- .../3-reference-manual/3-10-recommended-base-configuration.md | 4 ++-- content/3-reference-manual/3-3-variables.md | 4 ++-- content/3-reference-manual/3-6-operators.md | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/content/3-reference-manual/3-10-recommended-base-configuration.md b/content/3-reference-manual/3-10-recommended-base-configuration.md index 2e75625..d3867df 100644 --- a/content/3-reference-manual/3-10-recommended-base-configuration.md +++ b/content/3-reference-manual/3-10-recommended-base-configuration.md @@ -158,8 +158,8 @@ The PCRE limits cap the work a single regular expression may do, against regular a limit is hit the engine sets `TX:MSC_PCRE_LIMITS_EXCEEDED` instead of matching, and rule 200005 turns any such `MSC_` flag into a denial. Since 2.9.16, v2 also sets `TX:MSC_PCRE_ERROR` when a pattern is invalid after macro expansion, and this rule catches it too. In v3 `SecPcreMatchLimitRecursion` is accepted but ignored, and the match limit -is honored since 3.0.10. v3 reports other regex errors in the standalone `MSC_PCRE_ERROR` variable, which -`TX:/^MSC_/` does not see. +is honored since 3.0.10. v3 sets `TX:MSC_PCRE_ERROR` on any regex error since 3.0.18. Earlier v3 releases report +these errors only in the standalone `MSC_PCRE_ERROR` variable, which `TX:/^MSC_/` does not see. ## Response body handling diff --git a/content/3-reference-manual/3-3-variables.md b/content/3-reference-manual/3-3-variables.md index cf52e33..4452024 100644 --- a/content/3-reference-manual/3-3-variables.md +++ b/content/3-reference-manual/3-3-variables.md @@ -414,7 +414,7 @@ SecRule ARGS "@pm some key words" "id:12345,deny,status:500" MSC_PCRE_ERROR will be set to 1 when the @rx or @rxGlobal operator fails with any PCRE error, for example an invalid pattern after macro expansion or a match-limit error (in the latter case MSC_PCRE_LIMITS_EXCEEDED is set as well). -ModSecurity v2 does not provide this as a standalone variable. Since 2.9.16, when the @rx pattern is invalid after macro expansion, or a regex execution fails with an error other than a PCRE limit, v2 sets the transaction variable TX:MSC_PCRE_ERROR to 1. Rule 200005 in modsecurity.conf-recommended (`SecRule TX:/^MSC_/ "!@streq 0"`) catches it. libModSecurity v3 does not set TX:MSC_PCRE_ERROR, so on v3 test the standalone variable instead. +ModSecurity v2 does not provide this as a standalone variable. Since 2.9.16, when the @rx pattern is invalid after macro expansion, or a regex execution fails with an error other than a PCRE limit, v2 sets the transaction variable TX:MSC_PCRE_ERROR to 1. Rule 200005 in modsecurity.conf-recommended (`SecRule TX:/^MSC_/ "!@streq 0"`) catches it. Since 3.0.18, libModSecurity v3 also sets TX:MSC_PCRE_ERROR next to the standalone variable, for every @rx or @rxGlobal error including an exceeded match limit. Earlier v3 releases set only the standalone variable, which rule 200005 does not see. ## MSC_PCRE_LIMITS_EXCEEDED @@ -1393,7 +1393,7 @@ Some variable names in the TX collection are reserved and cannot be used: - TX:1-TX:9: the captured subexpression value when using the @rx operator with capturing parens and the capture action. ModSecurity v2 stores at most nine captures (TX:1 to TX:9); libModSecurity v3 stores every capturing group of the expression (the v3 manual documents TX:1 to TX:99). - TX:MSC_.*: ModSecurity processing flags - MSC_PCRE_LIMITS_EXCEEDED: Set to nonzero if PCRE match limits are exceeded. See SecPcreMatchLimit and SecPcreMatchLimitRecursion for more information. -- MSC_PCRE_ERROR: Set to 1 by ModSecurity v2 (since 2.9.16) when a regular expression fails with an error other than a PCRE limit, for example an invalid pattern after macro expansion. See MSC_PCRE_ERROR. +- MSC_PCRE_ERROR: Set to 1 when a regular expression fails, for example an invalid pattern after macro expansion. Set since ModSecurity 2.9.16, which leaves it unset for PCRE limit errors, and since libModSecurity 3.0.18. See MSC_PCRE_ERROR. ## UNIQUE_ID diff --git a/content/3-reference-manual/3-6-operators.md b/content/3-reference-manual/3-6-operators.md index fc155ad..7572bb2 100644 --- a/content/3-reference-manual/3-6-operators.md +++ b/content/3-reference-manual/3-6-operators.md @@ -665,7 +665,7 @@ If the expanded pattern is not a valid regular expression, or a PCRE limit is ex {{% notice note %}} -libModSecurity v3 compiles patterns with PCRE2_DOTALL and PCRE2_MULTILINE instead, so `^` and `$` also match at inner line boundaries. Rules that need line anchors should write `(?m)` explicitly to behave the same in both versions. In v3 a pattern that is invalid at load time rejects the rule, a pattern that becomes invalid after macro expansion does not match and sets MSC_PCRE_ERROR, and an empty pattern matches everything. SecPcreMatchLimit is honored since 3.0.10: when the limit is exceeded the operator does not match and MSC_PCRE_LIMITS_EXCEEDED and TX:MSC_PCRE_LIMITS_EXCEEDED are set to 1. +libModSecurity v3 compiles patterns with PCRE2_DOTALL and PCRE2_MULTILINE instead, so `^` and `$` also match at inner line boundaries. Rules that need line anchors should write `(?m)` explicitly to behave the same in both versions. In v3 a pattern that is invalid at load time rejects the rule, a pattern that becomes invalid after macro expansion does not match and sets MSC_PCRE_ERROR (and, since 3.0.18, TX:MSC_PCRE_ERROR), and an empty pattern matches everything. SecPcreMatchLimit is honored since 3.0.10: when the limit is exceeded the operator does not match and MSC_PCRE_LIMITS_EXCEEDED and TX:MSC_PCRE_LIMITS_EXCEEDED are set to 1. {{% /notice %}}