From 289b6e39e8a557b8fcf5ed5768823ccda9aa9769 Mon Sep 17 00:00:00 2001 From: jens Date: Thu, 26 Mar 2026 20:31:12 +0100 Subject: [PATCH 01/21] Update libinjection to v4.0.0 --- others/libinjection | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/others/libinjection b/others/libinjection index b9fcaaf9e..211782219 160000 --- a/others/libinjection +++ b/others/libinjection @@ -1 +1 @@ -Subproject commit b9fcaaf9e50e9492807b23ffcc6af46ee1f203b9 +Subproject commit 211782219663f889f471650150df12b623c5766e From 38d93911ae0da70690e9962eaadcd8ab1cbafae2 Mon Sep 17 00:00:00 2001 From: Easton97-Jens <66330090+Easton97-Jens@users.noreply.github.com> Date: Thu, 26 Mar 2026 21:12:08 +0100 Subject: [PATCH 02/21] Stabilize detectSQLi/XSS regression coverage for full test run --- src/operators/detect_sqli.cc | 55 +++++++++++++------ src/operators/detect_xss.cc | 54 ++++++++++++------ .../regression/operator-detectsqli.json | 45 +++++++++++++++ .../regression/operator-detectxss.json | 45 +++++++++++++++ 4 files changed, 166 insertions(+), 33 deletions(-) diff --git a/src/operators/detect_sqli.cc b/src/operators/detect_sqli.cc index 49cef935c..0f28733e2 100644 --- a/src/operators/detect_sqli.cc +++ b/src/operators/detect_sqli.cc @@ -20,6 +20,7 @@ #include "src/operators/operator.h" #include "libinjection/src/libinjection.h" +#include "libinjection/src/libinjection_error.h" namespace modsecurity { namespace operators { @@ -28,32 +29,52 @@ namespace operators { bool DetectSQLi::evaluate(Transaction *t, RuleWithActions *rule, const std::string& input, RuleMessage &ruleMessage) { char fingerprint[8]; - int issqli; + injection_result_t sqli_result; + bool is_match = false; - issqli = libinjection_sqli(input.c_str(), input.length(), fingerprint); + sqli_result = libinjection_sqli(input.c_str(), input.length(), fingerprint); if (!t) { goto tisempty; } - if (issqli) { - t->m_matched.push_back(fingerprint); - ms_dbg_a(t, 4, "detected SQLi using libinjection with " \ - "fingerprint '" + std::string(fingerprint) + "' at: '" + - input + "'"); - if (rule && rule->hasCaptureAction()) { - t->m_collections.m_tx_collection->storeOrUpdateFirst( - "0", std::string(fingerprint)); - ms_dbg_a(t, 7, "Added DetectSQLi match TX.0: " + \ - std::string(fingerprint)); - } - } else { - ms_dbg_a(t, 9, "detected SQLi: not able to find an " \ - "inject on '" + input + "'"); + switch (sqli_result) { + case LIBINJECTION_RESULT_TRUE: + is_match = true; + t->m_matched.push_back(fingerprint); + ms_dbg_a(t, 4, "detected SQLi using libinjection with " \ + "fingerprint '" + std::string(fingerprint) + "' at: '" + + input + "'"); + if (rule && rule->hasCaptureAction()) { + t->m_collections.m_tx_collection->storeOrUpdateFirst( + "0", std::string(fingerprint)); + ms_dbg_a(t, 7, "Added DetectSQLi match TX.0: " + \ + std::string(fingerprint)); + } + break; + case LIBINJECTION_RESULT_ERROR: + is_match = true; + ms_dbg_a(t, 4, "libinjection parser error during SQLi " + "analysis; treating as match (fail-safe). Input: '" + input + "'"); + if (rule && rule->hasCaptureAction()) { + t->m_collections.m_tx_collection->storeOrUpdateFirst( + "0", std::string(input)); + ms_dbg_a(t, 7, "Added DetectSQLi error input TX.0: " + \ + std::string(input)); + } + break; + case LIBINJECTION_RESULT_FALSE: + ms_dbg_a(t, 9, "detected SQLi: not able to find an " \ + "inject on '" + input + "'"); + break; } tisempty: - return issqli != 0; + if (t == nullptr) { + is_match = sqli_result == LIBINJECTION_RESULT_TRUE + || sqli_result == LIBINJECTION_RESULT_ERROR; + } + return is_match; } diff --git a/src/operators/detect_xss.cc b/src/operators/detect_xss.cc index 014202e73..70d6f3e3f 100644 --- a/src/operators/detect_xss.cc +++ b/src/operators/detect_xss.cc @@ -19,6 +19,7 @@ #include "src/operators/operator.h" #include "libinjection/src/libinjection.h" +#include "libinjection/src/libinjection_error.h" namespace modsecurity { @@ -27,25 +28,46 @@ namespace operators { bool DetectXSS::evaluate(Transaction *t, RuleWithActions *rule, const std::string& input, RuleMessage &ruleMessage) { - int is_xss; - - is_xss = libinjection_xss(input.c_str(), input.length()); + injection_result_t xss_result = libinjection_xss(input.c_str(), + input.length()); + bool is_match = false; if (t) { - if (is_xss) { - ms_dbg_a(t, 5, "detected XSS using libinjection."); - if (rule && rule->hasCaptureAction()) { - t->m_collections.m_tx_collection->storeOrUpdateFirst( - "0", std::string(input)); - ms_dbg_a(t, 7, "Added DetectXSS match TX.0: " + \ - std::string(input)); - } - } else { - ms_dbg_a(t, 9, "libinjection was not able to " \ - "find any XSS in: " + input); - } + switch (xss_result) { + case LIBINJECTION_RESULT_TRUE: + is_match = true; + ms_dbg_a(t, 5, "detected XSS using libinjection."); + if (rule && rule->hasCaptureAction()) { + t->m_collections.m_tx_collection->storeOrUpdateFirst( + "0", std::string(input)); + ms_dbg_a(t, 7, "Added DetectXSS match TX.0: " + \ + std::string(input)); + } + break; + case LIBINJECTION_RESULT_ERROR: + is_match = true; + ms_dbg_a(t, 4, "libinjection parser error during XSS " + "analysis; treating as match (fail-safe). Input: " + input); + if (rule && rule->hasCaptureAction()) { + t->m_collections.m_tx_collection->storeOrUpdateFirst( + "0", std::string(input)); + ms_dbg_a(t, 7, "Added DetectXSS error input TX.0: " + \ + std::string(input)); + } + break; + case LIBINJECTION_RESULT_FALSE: + ms_dbg_a(t, 9, "libinjection was not able to " \ + "find any XSS in: " + input); + break; + } + } + + if (t == nullptr) { + is_match = xss_result == LIBINJECTION_RESULT_TRUE + || xss_result == LIBINJECTION_RESULT_ERROR; } - return is_xss != 0; + + return is_match; } diff --git a/test/test-cases/regression/operator-detectsqli.json b/test/test-cases/regression/operator-detectsqli.json index 657bdf388..36a49d97e 100644 --- a/test/test-cases/regression/operator-detectsqli.json +++ b/test/test-cases/regression/operator-detectsqli.json @@ -44,5 +44,50 @@ "SecRuleEngine On", "SecRule ARGS \"@detectSQLi\" \"id:1,phase:2,capture,pass,t:trim\"" ] + }, + { + "enabled": 1, + "version_min": 300000, + "title": "Testing Operator :: @detectSQLi benign input", + "client": { + "ip": "200.249.12.31", + "port": 123 + }, + "server": { + "ip": "200.249.12.31", + "port": 80 + }, + "request": { + "headers": { + "Host": "localhost", + "User-Agent": "curl/7.38.0", + "Accept": "*/*", + "Content-Length": "18", + "Content-Type": "application/x-www-form-urlencoded" + }, + "uri": "/", + "method": "POST", + "body": [ + "param1=just_a_value" + ] + }, + "response": { + "headers": { + "Date": "Mon, 13 Jul 2015 20:02:41 GMT", + "Last-Modified": "Sun, 26 Oct 2014 22:33:37 GMT", + "Content-Type": "text/html", + "Content-Length": "8" + }, + "body": [ + "no need." + ] + }, + "expected": { + "http_code": 200 + }, + "rules": [ + "SecRuleEngine On", + "SecRule ARGS \"@detectSQLi\" \"id:2,phase:2,capture,pass,t:trim\"" + ] } ] diff --git a/test/test-cases/regression/operator-detectxss.json b/test/test-cases/regression/operator-detectxss.json index 9e6fa24b2..9a27078df 100644 --- a/test/test-cases/regression/operator-detectxss.json +++ b/test/test-cases/regression/operator-detectxss.json @@ -44,5 +44,50 @@ "SecRuleEngine On", "SecRule ARGS \"@detectXSS\" \"id:1,phase:2,capture,pass,t:trim\"" ] + }, + { + "enabled": 1, + "version_min": 300000, + "title": "Testing Operator :: @detectXSS benign input", + "client": { + "ip": "200.249.12.31", + "port": 123 + }, + "server": { + "ip": "200.249.12.31", + "port": 80 + }, + "request": { + "headers": { + "Host": "localhost", + "User-Agent": "curl/7.38.0", + "Accept": "*/*", + "Content-Length": "19", + "Content-Type": "application/x-www-form-urlencoded" + }, + "uri": "/", + "method": "POST", + "body": [ + "param1=safevalue123" + ] + }, + "response": { + "headers": { + "Date": "Mon, 13 Jul 2015 20:02:41 GMT", + "Last-Modified": "Sun, 26 Oct 2014 22:33:37 GMT", + "Content-Type": "text/html", + "Content-Length": "8" + }, + "body": [ + "no need." + ] + }, + "expected": { + "http_code": 200 + }, + "rules": [ + "SecRuleEngine On", + "SecRule ARGS \"@detectXSS\" \"id:2,phase:2,capture,pass,t:trim\"" + ] } ] From 0c610c09cbf6a62cf10727f5146c4045b5205494 Mon Sep 17 00:00:00 2001 From: Easton97-Jens <66330090+Easton97-Jens@users.noreply.github.com> Date: Thu, 26 Mar 2026 21:57:06 +0100 Subject: [PATCH 03/21] Make benign detectSQLi/XSS regression cases assert no-match logs --- test/test-cases/regression/operator-detectsqli.json | 1 + test/test-cases/regression/operator-detectxss.json | 1 + 2 files changed, 2 insertions(+) diff --git a/test/test-cases/regression/operator-detectsqli.json b/test/test-cases/regression/operator-detectsqli.json index 36a49d97e..915285919 100644 --- a/test/test-cases/regression/operator-detectsqli.json +++ b/test/test-cases/regression/operator-detectsqli.json @@ -83,6 +83,7 @@ ] }, "expected": { + "debug_log": "detected SQLi: not able to find an inject on 'just_a_value'", "http_code": 200 }, "rules": [ diff --git a/test/test-cases/regression/operator-detectxss.json b/test/test-cases/regression/operator-detectxss.json index 9a27078df..018a0362d 100644 --- a/test/test-cases/regression/operator-detectxss.json +++ b/test/test-cases/regression/operator-detectxss.json @@ -83,6 +83,7 @@ ] }, "expected": { + "debug_log": "libinjection was not able to find any XSS in: safevalue123", "http_code": 200 }, "rules": [ From 46dabc0db26d1d60b0c3319a4651342ebbdba117 Mon Sep 17 00:00:00 2001 From: Easton97-Jens Date: Fri, 27 Mar 2026 20:12:00 +0100 Subject: [PATCH 04/21] Harden libinjection v4 handling in DetectSQLi/DetectXSS operators --- src/operators/detect_sqli.cc | 22 ++++------ src/operators/detect_xss.cc | 64 ++++++++++++++---------------- src/operators/libinjection_utils.h | 50 +++++++++++++++++++++++ 3 files changed, 88 insertions(+), 48 deletions(-) create mode 100644 src/operators/libinjection_utils.h diff --git a/src/operators/detect_sqli.cc b/src/operators/detect_sqli.cc index 0f28733e2..ec66aa8c2 100644 --- a/src/operators/detect_sqli.cc +++ b/src/operators/detect_sqli.cc @@ -19,6 +19,7 @@ #include #include "src/operators/operator.h" +#include "src/operators/libinjection_utils.h" #include "libinjection/src/libinjection.h" #include "libinjection/src/libinjection_error.h" @@ -29,18 +30,16 @@ namespace operators { bool DetectSQLi::evaluate(Transaction *t, RuleWithActions *rule, const std::string& input, RuleMessage &ruleMessage) { char fingerprint[8]; - injection_result_t sqli_result; - bool is_match = false; + injection_result_t sqli_result = LIBINJECTION_RESULT_FALSE; sqli_result = libinjection_sqli(input.c_str(), input.length(), fingerprint); - if (!t) { - goto tisempty; + if (t == nullptr) { + return isMaliciousLibinjectionResult(sqli_result); } switch (sqli_result) { case LIBINJECTION_RESULT_TRUE: - is_match = true; t->m_matched.push_back(fingerprint); ms_dbg_a(t, 4, "detected SQLi using libinjection with " \ "fingerprint '" + std::string(fingerprint) + "' at: '" + @@ -53,9 +52,9 @@ bool DetectSQLi::evaluate(Transaction *t, RuleWithActions *rule, } break; case LIBINJECTION_RESULT_ERROR: - is_match = true; ms_dbg_a(t, 4, "libinjection parser error during SQLi " - "analysis; treating as match (fail-safe). Input: '" + input + "'"); + "analysis (" + std::string(libinjectionResultToString(sqli_result)) + + "); treating as match (fail-safe). Input: '" + input + "'"); if (rule && rule->hasCaptureAction()) { t->m_collections.m_tx_collection->storeOrUpdateFirst( "0", std::string(input)); @@ -69,14 +68,9 @@ bool DetectSQLi::evaluate(Transaction *t, RuleWithActions *rule, break; } -tisempty: - if (t == nullptr) { - is_match = sqli_result == LIBINJECTION_RESULT_TRUE - || sqli_result == LIBINJECTION_RESULT_ERROR; - } - return is_match; + return isMaliciousLibinjectionResult(sqli_result); } } // namespace operators -} // namespace modsecurity +} // namespace modsecurity \ No newline at end of file diff --git a/src/operators/detect_xss.cc b/src/operators/detect_xss.cc index 70d6f3e3f..3ce51af34 100644 --- a/src/operators/detect_xss.cc +++ b/src/operators/detect_xss.cc @@ -18,6 +18,7 @@ #include #include "src/operators/operator.h" +#include "src/operators/libinjection_utils.h" #include "libinjection/src/libinjection.h" #include "libinjection/src/libinjection_error.h" @@ -30,46 +31,41 @@ bool DetectXSS::evaluate(Transaction *t, RuleWithActions *rule, const std::string& input, RuleMessage &ruleMessage) { injection_result_t xss_result = libinjection_xss(input.c_str(), input.length()); - bool is_match = false; - if (t) { - switch (xss_result) { - case LIBINJECTION_RESULT_TRUE: - is_match = true; - ms_dbg_a(t, 5, "detected XSS using libinjection."); - if (rule && rule->hasCaptureAction()) { - t->m_collections.m_tx_collection->storeOrUpdateFirst( - "0", std::string(input)); - ms_dbg_a(t, 7, "Added DetectXSS match TX.0: " + \ - std::string(input)); - } - break; - case LIBINJECTION_RESULT_ERROR: - is_match = true; - ms_dbg_a(t, 4, "libinjection parser error during XSS " - "analysis; treating as match (fail-safe). Input: " + input); - if (rule && rule->hasCaptureAction()) { - t->m_collections.m_tx_collection->storeOrUpdateFirst( - "0", std::string(input)); - ms_dbg_a(t, 7, "Added DetectXSS error input TX.0: " + \ - std::string(input)); - } - break; - case LIBINJECTION_RESULT_FALSE: - ms_dbg_a(t, 9, "libinjection was not able to " \ - "find any XSS in: " + input); - break; - } + if (t == nullptr) { + return isMaliciousLibinjectionResult(xss_result); } - if (t == nullptr) { - is_match = xss_result == LIBINJECTION_RESULT_TRUE - || xss_result == LIBINJECTION_RESULT_ERROR; + switch (xss_result) { + case LIBINJECTION_RESULT_TRUE: + ms_dbg_a(t, 5, "detected XSS using libinjection."); + if (rule && rule->hasCaptureAction()) { + t->m_collections.m_tx_collection->storeOrUpdateFirst( + "0", std::string(input)); + ms_dbg_a(t, 7, "Added DetectXSS match TX.0: " + \ + std::string(input)); + } + break; + case LIBINJECTION_RESULT_ERROR: + ms_dbg_a(t, 4, "libinjection parser error during XSS analysis (" + + std::string(libinjectionResultToString(xss_result)) + + "); treating as match (fail-safe). Input: " + input); + if (rule && rule->hasCaptureAction()) { + t->m_collections.m_tx_collection->storeOrUpdateFirst( + "0", std::string(input)); + ms_dbg_a(t, 7, "Added DetectXSS error input TX.0: " + \ + std::string(input)); + } + break; + case LIBINJECTION_RESULT_FALSE: + ms_dbg_a(t, 9, "libinjection was not able to " \ + "find any XSS in: " + input); + break; } - return is_match; + return isMaliciousLibinjectionResult(xss_result); } } // namespace operators -} // namespace modsecurity +} // namespace modsecurity \ No newline at end of file diff --git a/src/operators/libinjection_utils.h b/src/operators/libinjection_utils.h new file mode 100644 index 000000000..7a520469b --- /dev/null +++ b/src/operators/libinjection_utils.h @@ -0,0 +1,50 @@ +/* + * ModSecurity, http://www.modsecurity.org/ + * Copyright (c) 2015 - 2021 Trustwave Holdings, Inc. (http://www.trustwave.com/) + * + * You may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * If any of the files related to licensing are missing or if you have any + * other questions related to licensing please contact Trustwave Holdings, Inc. + * directly using the email address security@modsecurity.org. + * + */ + +#ifndef SRC_OPERATORS_LIBINJECTION_UTILS_H_ +#define SRC_OPERATORS_LIBINJECTION_UTILS_H_ + +#include "libinjection/src/libinjection_error.h" + +namespace modsecurity { +namespace operators { + +/* + * libinjection parser errors are handled in fail-safe mode as suspicious + * results, so callers can block on both confirmed detections and parser + * failures. + */ +static inline bool isMaliciousLibinjectionResult(injection_result_t result) { + return result == LIBINJECTION_RESULT_TRUE + || result == LIBINJECTION_RESULT_ERROR; +} + +static inline const char *libinjectionResultToString(injection_result_t result) { + switch (result) { + case LIBINJECTION_RESULT_TRUE: + return "attack-detected"; + case LIBINJECTION_RESULT_FALSE: + return "no-attack"; + case LIBINJECTION_RESULT_ERROR: + return "parser-error"; + } + + return "unexpected-result"; +} + +} // namespace operators +} // namespace modsecurity + +#endif // SRC_OPERATORS_LIBINJECTION_UTILS_H_ \ No newline at end of file From c816addccb2eca4ed4581b56e2079e58ac87f409 Mon Sep 17 00:00:00 2001 From: Easton97-Jens <66330090+Easton97-Jens@users.noreply.github.com> Date: Fri, 27 Mar 2026 20:21:39 +0100 Subject: [PATCH 05/21] Fix namespace declaration in libinjection_utils.h --- src/operators/libinjection_utils.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/operators/libinjection_utils.h b/src/operators/libinjection_utils.h index 7a520469b..c5932231e 100644 --- a/src/operators/libinjection_utils.h +++ b/src/operators/libinjection_utils.h @@ -18,8 +18,7 @@ #include "libinjection/src/libinjection_error.h" -namespace modsecurity { -namespace operators { +namespace modsecurity:operators { /* * libinjection parser errors are handled in fail-safe mode as suspicious @@ -47,4 +46,4 @@ static inline const char *libinjectionResultToString(injection_result_t result) } // namespace operators } // namespace modsecurity -#endif // SRC_OPERATORS_LIBINJECTION_UTILS_H_ \ No newline at end of file +#endif // SRC_OPERATORS_LIBINJECTION_UTILS_H_ From d94cbeb288e34e644d7d9958987c28c5703f6179 Mon Sep 17 00:00:00 2001 From: Easton97-Jens <66330090+Easton97-Jens@users.noreply.github.com> Date: Fri, 27 Mar 2026 20:22:09 +0100 Subject: [PATCH 06/21] Fix namespace declaration syntax in libinjection_utils.h --- src/operators/libinjection_utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/operators/libinjection_utils.h b/src/operators/libinjection_utils.h index c5932231e..8acc81280 100644 --- a/src/operators/libinjection_utils.h +++ b/src/operators/libinjection_utils.h @@ -18,7 +18,7 @@ #include "libinjection/src/libinjection_error.h" -namespace modsecurity:operators { +namespace modsecurity::operators { /* * libinjection parser errors are handled in fail-safe mode as suspicious From b4b81aa03389b7bafbc8cace69ff6c8336316a32 Mon Sep 17 00:00:00 2001 From: Easton97-Jens Date: Fri, 27 Mar 2026 20:51:59 +0100 Subject: [PATCH 07/21] fix(logging): remove trailing semicolon from debug macros (ms_dbg, ms_dbg_a) --- headers/modsecurity/transaction.h | 8 ++--- src/operators/detect_sqli.cc | 54 +++++++++++++++--------------- src/operators/detect_xss.cc | 46 ++++++++++++------------- src/operators/libinjection_utils.h | 5 ++- 4 files changed, 54 insertions(+), 59 deletions(-) diff --git a/headers/modsecurity/transaction.h b/headers/modsecurity/transaction.h index 3e70caa38..0f4d1cda9 100644 --- a/headers/modsecurity/transaction.h +++ b/headers/modsecurity/transaction.h @@ -59,10 +59,10 @@ typedef struct Rules_t RulesSet; if (m_rules && m_rules->m_debugLog && m_rules->m_debugLog->m_debugLevel >= b) { \ m_rules->debug(b, m_id, m_uri, c); \ } \ - } while (0); + } while (0) #else #define ms_dbg(b, c) \ - do { } while (0); + do { } while (0) #endif #ifndef NO_LOGS @@ -71,10 +71,10 @@ typedef struct Rules_t RulesSet; if (t && t->m_rules && t->m_rules->m_debugLog && t->m_rules->m_debugLog->m_debugLevel >= b) { \ t->debug(b, c); \ } \ - } while (0); + } while (0) #else #define ms_dbg_a(t, b, c) \ - do { } while (0); + do { } while (0) #endif diff --git a/src/operators/detect_sqli.cc b/src/operators/detect_sqli.cc index ec66aa8c2..8e4a1ef20 100644 --- a/src/operators/detect_sqli.cc +++ b/src/operators/detect_sqli.cc @@ -23,16 +23,15 @@ #include "libinjection/src/libinjection.h" #include "libinjection/src/libinjection_error.h" -namespace modsecurity { -namespace operators { - +namespace modsecurity::operators { bool DetectSQLi::evaluate(Transaction *t, RuleWithActions *rule, const std::string& input, RuleMessage &ruleMessage) { - char fingerprint[8]; - injection_result_t sqli_result = LIBINJECTION_RESULT_FALSE; - sqli_result = libinjection_sqli(input.c_str(), input.length(), fingerprint); + char fingerprint[8] = {0}; + + const injection_result_t sqli_result = + libinjection_sqli(input.c_str(), input.length(), fingerprint); if (t == nullptr) { return isMaliciousLibinjectionResult(sqli_result); @@ -41,36 +40,37 @@ bool DetectSQLi::evaluate(Transaction *t, RuleWithActions *rule, switch (sqli_result) { case LIBINJECTION_RESULT_TRUE: t->m_matched.push_back(fingerprint); - ms_dbg_a(t, 4, "detected SQLi using libinjection with " \ - "fingerprint '" + std::string(fingerprint) + "' at: '" + - input + "'"); - if (rule && rule->hasCaptureAction()) { - t->m_collections.m_tx_collection->storeOrUpdateFirst( - "0", std::string(fingerprint)); - ms_dbg_a(t, 7, "Added DetectSQLi match TX.0: " + \ - std::string(fingerprint)); + + ms_dbg_a(t, 4, + std::string("detected SQLi using libinjection with fingerprint '") + + fingerprint + "' at: '" + input + "'"); + + if (rule != nullptr && rule->hasCaptureAction()) { + t->m_collections.m_tx_collection->storeOrUpdateFirst("0", fingerprint); + ms_dbg_a(t, 7, std::string("Added DetectSQLi match TX.0: ") + fingerprint); } break; + case LIBINJECTION_RESULT_ERROR: - ms_dbg_a(t, 4, "libinjection parser error during SQLi " - "analysis (" + std::string(libinjectionResultToString(sqli_result)) - + "); treating as match (fail-safe). Input: '" + input + "'"); - if (rule && rule->hasCaptureAction()) { - t->m_collections.m_tx_collection->storeOrUpdateFirst( - "0", std::string(input)); - ms_dbg_a(t, 7, "Added DetectSQLi error input TX.0: " + \ - std::string(input)); + ms_dbg_a(t, 4, + std::string("libinjection parser error during SQLi analysis (") + + libinjectionResultToString(sqli_result) + + "); treating as match (fail-safe). Input: '" + + input + "'"); + + if (rule != nullptr && rule->hasCaptureAction()) { + t->m_collections.m_tx_collection->storeOrUpdateFirst("0", input); + ms_dbg_a(t, 7, std::string("Added DetectSQLi error input TX.0: ") + input); } break; + case LIBINJECTION_RESULT_FALSE: - ms_dbg_a(t, 9, "detected SQLi: not able to find an " \ - "inject on '" + input + "'"); + ms_dbg_a(t, 9, + std::string("libinjection was not able to find any SQLi in: ") + input); break; } return isMaliciousLibinjectionResult(sqli_result); } - -} // namespace operators -} // namespace modsecurity \ No newline at end of file +} // namespace modsecurity::operators \ No newline at end of file diff --git a/src/operators/detect_xss.cc b/src/operators/detect_xss.cc index 3ce51af34..575315397 100644 --- a/src/operators/detect_xss.cc +++ b/src/operators/detect_xss.cc @@ -22,15 +22,13 @@ #include "libinjection/src/libinjection.h" #include "libinjection/src/libinjection_error.h" - -namespace modsecurity { -namespace operators { - +namespace modsecurity::operators { bool DetectXSS::evaluate(Transaction *t, RuleWithActions *rule, const std::string& input, RuleMessage &ruleMessage) { - injection_result_t xss_result = libinjection_xss(input.c_str(), - input.length()); + + const injection_result_t xss_result = + libinjection_xss(input.c_str(), input.length()); if (t == nullptr) { return isMaliciousLibinjectionResult(xss_result); @@ -38,34 +36,32 @@ bool DetectXSS::evaluate(Transaction *t, RuleWithActions *rule, switch (xss_result) { case LIBINJECTION_RESULT_TRUE: - ms_dbg_a(t, 5, "detected XSS using libinjection."); - if (rule && rule->hasCaptureAction()) { - t->m_collections.m_tx_collection->storeOrUpdateFirst( - "0", std::string(input)); - ms_dbg_a(t, 7, "Added DetectXSS match TX.0: " + \ - std::string(input)); + ms_dbg_a(t, 5, std::string("detected XSS using libinjection.")); + if (rule != nullptr && rule->hasCaptureAction()) { + t->m_collections.m_tx_collection->storeOrUpdateFirst("0", input); + ms_dbg_a(t, 7, std::string("Added DetectXSS match TX.0: ") + input); } break; + case LIBINJECTION_RESULT_ERROR: - ms_dbg_a(t, 4, "libinjection parser error during XSS analysis (" - + std::string(libinjectionResultToString(xss_result)) - + "); treating as match (fail-safe). Input: " + input); - if (rule && rule->hasCaptureAction()) { - t->m_collections.m_tx_collection->storeOrUpdateFirst( - "0", std::string(input)); - ms_dbg_a(t, 7, "Added DetectXSS error input TX.0: " + \ - std::string(input)); + ms_dbg_a(t, 4, + std::string("libinjection parser error during XSS analysis (") + + libinjectionResultToString(xss_result) + + "); treating as match (fail-safe). Input: " + + input); + if (rule != nullptr && rule->hasCaptureAction()) { + t->m_collections.m_tx_collection->storeOrUpdateFirst("0", input); + ms_dbg_a(t, 7, std::string("Added DetectXSS error input TX.0: ") + input); } break; + case LIBINJECTION_RESULT_FALSE: - ms_dbg_a(t, 9, "libinjection was not able to " \ - "find any XSS in: " + input); + ms_dbg_a(t, 9, + std::string("libinjection was not able to find any XSS in: ") + input); break; } return isMaliciousLibinjectionResult(xss_result); } - -} // namespace operators -} // namespace modsecurity \ No newline at end of file +} // namespace modsecurity::operators \ No newline at end of file diff --git a/src/operators/libinjection_utils.h b/src/operators/libinjection_utils.h index 8acc81280..dde3cc0f4 100644 --- a/src/operators/libinjection_utils.h +++ b/src/operators/libinjection_utils.h @@ -43,7 +43,6 @@ static inline const char *libinjectionResultToString(injection_result_t result) return "unexpected-result"; } -} // namespace operators -} // namespace modsecurity +} // namespace modsecurity::operators -#endif // SRC_OPERATORS_LIBINJECTION_UTILS_H_ +#endif // SRC_OPERATORS_LIBINJECTION_UTILS_H_ \ No newline at end of file From 15fd15750afb9cfe26d8d5738cbf649e3f1eed0f Mon Sep 17 00:00:00 2001 From: Easton97-Jens <66330090+Easton97-Jens@users.noreply.github.com> Date: Fri, 27 Mar 2026 21:02:29 +0100 Subject: [PATCH 08/21] Update detect_sqli.cc --- src/operators/detect_sqli.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/operators/detect_sqli.cc b/src/operators/detect_sqli.cc index 8e4a1ef20..910079073 100644 --- a/src/operators/detect_sqli.cc +++ b/src/operators/detect_sqli.cc @@ -28,10 +28,10 @@ namespace modsecurity::operators { bool DetectSQLi::evaluate(Transaction *t, RuleWithActions *rule, const std::string& input, RuleMessage &ruleMessage) { - char fingerprint[8] = {0}; + std::array fingerprint{}; const injection_result_t sqli_result = - libinjection_sqli(input.c_str(), input.length(), fingerprint); + libinjection_sqli(input.c_str(), input.length(), fingerprint.data()); if (t == nullptr) { return isMaliciousLibinjectionResult(sqli_result); @@ -73,4 +73,4 @@ bool DetectSQLi::evaluate(Transaction *t, RuleWithActions *rule, return isMaliciousLibinjectionResult(sqli_result); } -} // namespace modsecurity::operators \ No newline at end of file +} // namespace modsecurity::operators From 4bacc361907327cf2405a20e3545bdcf54a9452f Mon Sep 17 00:00:00 2001 From: Easton97-Jens <66330090+Easton97-Jens@users.noreply.github.com> Date: Fri, 27 Mar 2026 21:03:58 +0100 Subject: [PATCH 09/21] Add array header to detect_sqli.cc --- src/operators/detect_sqli.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/operators/detect_sqli.cc b/src/operators/detect_sqli.cc index 910079073..2c8c3eece 100644 --- a/src/operators/detect_sqli.cc +++ b/src/operators/detect_sqli.cc @@ -17,7 +17,7 @@ #include #include - +#include #include "src/operators/operator.h" #include "src/operators/libinjection_utils.h" #include "libinjection/src/libinjection.h" From f9b28854b1b3b5f35a294e9f24407b1be68c03be Mon Sep 17 00:00:00 2001 From: Easton97-Jens <66330090+Easton97-Jens@users.noreply.github.com> Date: Fri, 27 Mar 2026 21:22:59 +0100 Subject: [PATCH 10/21] Fix formatting issues in transaction.h debug macros --- headers/modsecurity/transaction.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/headers/modsecurity/transaction.h b/headers/modsecurity/transaction.h index 0f4d1cda9..3e70caa38 100644 --- a/headers/modsecurity/transaction.h +++ b/headers/modsecurity/transaction.h @@ -59,10 +59,10 @@ typedef struct Rules_t RulesSet; if (m_rules && m_rules->m_debugLog && m_rules->m_debugLog->m_debugLevel >= b) { \ m_rules->debug(b, m_id, m_uri, c); \ } \ - } while (0) + } while (0); #else #define ms_dbg(b, c) \ - do { } while (0) + do { } while (0); #endif #ifndef NO_LOGS @@ -71,10 +71,10 @@ typedef struct Rules_t RulesSet; if (t && t->m_rules && t->m_rules->m_debugLog && t->m_rules->m_debugLog->m_debugLevel >= b) { \ t->debug(b, c); \ } \ - } while (0) + } while (0); #else #define ms_dbg_a(t, b, c) \ - do { } while (0) + do { } while (0); #endif From a8debeb320a5939552cd29240f8d842bd5b34bdc Mon Sep 17 00:00:00 2001 From: Easton97-Jens <66330090+Easton97-Jens@users.noreply.github.com> Date: Fri, 27 Mar 2026 21:29:47 +0100 Subject: [PATCH 11/21] Refactor fingerprint handling in detect_sqli.cc --- src/operators/detect_sqli.cc | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/operators/detect_sqli.cc b/src/operators/detect_sqli.cc index 2c8c3eece..ca099162c 100644 --- a/src/operators/detect_sqli.cc +++ b/src/operators/detect_sqli.cc @@ -18,6 +18,7 @@ #include #include #include + #include "src/operators/operator.h" #include "src/operators/libinjection_utils.h" #include "libinjection/src/libinjection.h" @@ -39,15 +40,19 @@ bool DetectSQLi::evaluate(Transaction *t, RuleWithActions *rule, switch (sqli_result) { case LIBINJECTION_RESULT_TRUE: - t->m_matched.push_back(fingerprint); + t->m_matched.push_back(std::string(fingerprint.data())); ms_dbg_a(t, 4, std::string("detected SQLi using libinjection with fingerprint '") - + fingerprint + "' at: '" + input + "'"); + + fingerprint.data() + "' at: '" + input + "'"); if (rule != nullptr && rule->hasCaptureAction()) { - t->m_collections.m_tx_collection->storeOrUpdateFirst("0", fingerprint); - ms_dbg_a(t, 7, std::string("Added DetectSQLi match TX.0: ") + fingerprint); + t->m_collections.m_tx_collection->storeOrUpdateFirst( + "0", std::string(fingerprint.data())); + + ms_dbg_a(t, 7, + std::string("Added DetectSQLi match TX.0: ") + + fingerprint.data()); } break; @@ -59,14 +64,19 @@ bool DetectSQLi::evaluate(Transaction *t, RuleWithActions *rule, + input + "'"); if (rule != nullptr && rule->hasCaptureAction()) { - t->m_collections.m_tx_collection->storeOrUpdateFirst("0", input); - ms_dbg_a(t, 7, std::string("Added DetectSQLi error input TX.0: ") + input); + t->m_collections.m_tx_collection->storeOrUpdateFirst( + "0", input); + + ms_dbg_a(t, 7, + std::string("Added DetectSQLi error input TX.0: ") + + input); } break; case LIBINJECTION_RESULT_FALSE: ms_dbg_a(t, 9, - std::string("libinjection was not able to find any SQLi in: ") + input); + std::string("libinjection was not able to find any SQLi in: ") + + input); break; } From c67f876c0486c3f0e2504b3d83abc5b4e70cb0e3 Mon Sep 17 00:00:00 2001 From: Easton97-Jens <66330090+Easton97-Jens@users.noreply.github.com> Date: Fri, 27 Mar 2026 21:41:13 +0100 Subject: [PATCH 12/21] Fix debug logging for XSS detection in detect_xss.cc --- src/operators/detect_xss.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/operators/detect_xss.cc b/src/operators/detect_xss.cc index 575315397..9782de537 100644 --- a/src/operators/detect_xss.cc +++ b/src/operators/detect_xss.cc @@ -36,10 +36,10 @@ bool DetectXSS::evaluate(Transaction *t, RuleWithActions *rule, switch (xss_result) { case LIBINJECTION_RESULT_TRUE: - ms_dbg_a(t, 5, std::string("detected XSS using libinjection.")); + ms_dbg_a(t, 5, std::string("detected XSS using libinjection.")) if (rule != nullptr && rule->hasCaptureAction()) { t->m_collections.m_tx_collection->storeOrUpdateFirst("0", input); - ms_dbg_a(t, 7, std::string("Added DetectXSS match TX.0: ") + input); + ms_dbg_a(t, 7, std::string("Added DetectXSS match TX.0: ") + input) } break; @@ -48,20 +48,20 @@ bool DetectXSS::evaluate(Transaction *t, RuleWithActions *rule, std::string("libinjection parser error during XSS analysis (") + libinjectionResultToString(xss_result) + "); treating as match (fail-safe). Input: " - + input); + + input) if (rule != nullptr && rule->hasCaptureAction()) { t->m_collections.m_tx_collection->storeOrUpdateFirst("0", input); - ms_dbg_a(t, 7, std::string("Added DetectXSS error input TX.0: ") + input); + ms_dbg_a(t, 7, std::string("Added DetectXSS error input TX.0: ") + input) } break; case LIBINJECTION_RESULT_FALSE: ms_dbg_a(t, 9, - std::string("libinjection was not able to find any XSS in: ") + input); + std::string("libinjection was not able to find any XSS in: ") + input) break; } return isMaliciousLibinjectionResult(xss_result); } -} // namespace modsecurity::operators \ No newline at end of file +} // namespace modsecurity::operators From 7b5bf7f4b5a5074f660e835f28b7f7bd7c1930b4 Mon Sep 17 00:00:00 2001 From: Easton97-Jens <66330090+Easton97-Jens@users.noreply.github.com> Date: Fri, 27 Mar 2026 21:42:18 +0100 Subject: [PATCH 13/21] Fix debug message formatting in detect_sqli.cc --- src/operators/detect_sqli.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/operators/detect_sqli.cc b/src/operators/detect_sqli.cc index ca099162c..2803a5c92 100644 --- a/src/operators/detect_sqli.cc +++ b/src/operators/detect_sqli.cc @@ -44,7 +44,7 @@ bool DetectSQLi::evaluate(Transaction *t, RuleWithActions *rule, ms_dbg_a(t, 4, std::string("detected SQLi using libinjection with fingerprint '") - + fingerprint.data() + "' at: '" + input + "'"); + + fingerprint.data() + "' at: '" + input + "'") if (rule != nullptr && rule->hasCaptureAction()) { t->m_collections.m_tx_collection->storeOrUpdateFirst( @@ -52,7 +52,7 @@ bool DetectSQLi::evaluate(Transaction *t, RuleWithActions *rule, ms_dbg_a(t, 7, std::string("Added DetectSQLi match TX.0: ") - + fingerprint.data()); + + fingerprint.data()) } break; @@ -61,7 +61,7 @@ bool DetectSQLi::evaluate(Transaction *t, RuleWithActions *rule, std::string("libinjection parser error during SQLi analysis (") + libinjectionResultToString(sqli_result) + "); treating as match (fail-safe). Input: '" - + input + "'"); + + input + "'") if (rule != nullptr && rule->hasCaptureAction()) { t->m_collections.m_tx_collection->storeOrUpdateFirst( @@ -69,14 +69,14 @@ bool DetectSQLi::evaluate(Transaction *t, RuleWithActions *rule, ms_dbg_a(t, 7, std::string("Added DetectSQLi error input TX.0: ") - + input); + + input) } break; case LIBINJECTION_RESULT_FALSE: ms_dbg_a(t, 9, std::string("libinjection was not able to find any SQLi in: ") - + input); + + input) break; } From e169d59f9cb47a4237e46ee9fbe296773cf488b6 Mon Sep 17 00:00:00 2001 From: Easton97-Jens <66330090+Easton97-Jens@users.noreply.github.com> Date: Fri, 27 Mar 2026 21:51:30 +0100 Subject: [PATCH 14/21] Replace push_back with emplace_back for efficiency --- src/operators/detect_sqli.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/operators/detect_sqli.cc b/src/operators/detect_sqli.cc index 2803a5c92..05cefc543 100644 --- a/src/operators/detect_sqli.cc +++ b/src/operators/detect_sqli.cc @@ -40,7 +40,7 @@ bool DetectSQLi::evaluate(Transaction *t, RuleWithActions *rule, switch (sqli_result) { case LIBINJECTION_RESULT_TRUE: - t->m_matched.push_back(std::string(fingerprint.data())); + t->m_matched.emplace_back(fingerprint.data()); ms_dbg_a(t, 4, std::string("detected SQLi using libinjection with fingerprint '") From 724b197b4ca371ac0f5314888b24d0b41bf1bd09 Mon Sep 17 00:00:00 2001 From: Easton97-Jens <66330090+Easton97-Jens@users.noreply.github.com> Date: Sat, 28 Mar 2026 18:14:12 +0100 Subject: [PATCH 15/21] Update operator-detectsqli.json --- .../regression/operator-detectsqli.json | 147 +++++++++++++++++- 1 file changed, 142 insertions(+), 5 deletions(-) diff --git a/test/test-cases/regression/operator-detectsqli.json b/test/test-cases/regression/operator-detectsqli.json index 915285919..0ce5c42dd 100644 --- a/test/test-cases/regression/operator-detectsqli.json +++ b/test/test-cases/regression/operator-detectsqli.json @@ -48,7 +48,7 @@ { "enabled": 1, "version_min": 300000, - "title": "Testing Operator :: @detectSQLi benign input", + "title": "Testing Operator :: @detectXSS :: basic script payload", "client": { "ip": "200.249.12.31", "port": 123 @@ -62,13 +62,13 @@ "Host": "localhost", "User-Agent": "curl/7.38.0", "Accept": "*/*", - "Content-Length": "18", + "Content-Length": "45", "Content-Type": "application/x-www-form-urlencoded" }, "uri": "/", "method": "POST", "body": [ - "param1=just_a_value" + "param1=alert(1)&p=1" + ] + }, + "response": { + "headers": { + "Date": "Mon, 13 Jul 2015 20:02:41 GMT", + "Last-Modified": "Sun, 26 Oct 2014 22:33:37 GMT", + "Content-Type": "text/html", + "Content-Length": "8" + }, + "body": [ + "no need." + ] + }, + "expected": { + "debug_log": "Added DetectXSS match TX.0: ", + "http_code": 200 + }, + "rules": [ + "SecRuleEngine On", + "SecRule ARGS \"@detectXSS\" \"id:3,phase:2,capture,pass,t:trim\"" + ] + }, + { + "enabled": 1, + "version_min": 300000, + "title": "Testing Operator :: @detectXSS :: benign input should not match", + "client": { + "ip": "200.249.12.31", + "port": 123 + }, + "server": { + "ip": "200.249.12.31", + "port": 80 + }, + "request": { + "headers": { + "Host": "localhost", + "User-Agent": "curl/7.38.0", + "Accept": "*/*", + "Content-Length": "24", + "Content-Type": "application/x-www-form-urlencoded" + }, + "uri": "/", + "method": "POST", + "body": [ + "param1=hello-world&x=1" + ] + }, + "response": { + "headers": { + "Date": "Mon, 13 Jul 2015 20:02:41 GMT", + "Last-Modified": "Sun, 26 Oct 2014 22:33:37 GMT", + "Content-Type": "text/html", + "Content-Length": "8" + }, + "body": [ + "no need." + ] + }, + "expected": { + "http_code": 200 + }, + "rules": [ + "SecRuleEngine On", + "SecRule ARGS \"@detectXSS\" \"id:4,phase:2,capture,pass,t:trim\"" ] } ] From b9393e74cc094d5a231aaf761ffe277b51723f7c Mon Sep 17 00:00:00 2001 From: Easton97-Jens <66330090+Easton97-Jens@users.noreply.github.com> Date: Sat, 28 Mar 2026 18:15:04 +0100 Subject: [PATCH 16/21] Update XSS test cases with new payloads --- .../regression/operator-detectxss.json | 145 +++++++++++++++++- 1 file changed, 141 insertions(+), 4 deletions(-) diff --git a/test/test-cases/regression/operator-detectxss.json b/test/test-cases/regression/operator-detectxss.json index 018a0362d..1fa751e1c 100644 --- a/test/test-cases/regression/operator-detectxss.json +++ b/test/test-cases/regression/operator-detectxss.json @@ -48,7 +48,7 @@ { "enabled": 1, "version_min": 300000, - "title": "Testing Operator :: @detectXSS benign input", + "title": "Testing Operator :: @detectXSS :: basic script payload", "client": { "ip": "200.249.12.31", "port": 123 @@ -62,13 +62,13 @@ "Host": "localhost", "User-Agent": "curl/7.38.0", "Accept": "*/*", - "Content-Length": "19", + "Content-Length": "45", "Content-Type": "application/x-www-form-urlencoded" }, "uri": "/", "method": "POST", "body": [ - "param1=safevalue123" + "param1=alert(1)&p=1" + ] + }, + "response": { + "headers": { + "Date": "Mon, 13 Jul 2015 20:02:41 GMT", + "Last-Modified": "Sun, 26 Oct 2014 22:33:37 GMT", + "Content-Type": "text/html", + "Content-Length": "8" + }, + "body": [ + "no need." + ] + }, + "expected": { + "debug_log": "Added DetectXSS match TX.0: ", + "http_code": 200 + }, + "rules": [ + "SecRuleEngine On", + "SecRule ARGS \"@detectXSS\" \"id:3,phase:2,capture,pass,t:trim\"" + ] + }, + { + "enabled": 1, + "version_min": 300000, + "title": "Testing Operator :: @detectXSS :: benign input should not match", + "client": { + "ip": "200.249.12.31", + "port": 123 + }, + "server": { + "ip": "200.249.12.31", + "port": 80 + }, + "request": { + "headers": { + "Host": "localhost", + "User-Agent": "curl/7.38.0", + "Accept": "*/*", + "Content-Length": "24", + "Content-Type": "application/x-www-form-urlencoded" + }, + "uri": "/", + "method": "POST", + "body": [ + "param1=hello-world&x=1" + ] + }, + "response": { + "headers": { + "Date": "Mon, 13 Jul 2015 20:02:41 GMT", + "Last-Modified": "Sun, 26 Oct 2014 22:33:37 GMT", + "Content-Type": "text/html", + "Content-Length": "8" + }, + "body": [ + "no need." + ] + }, + "expected": { + "http_code": 200 + }, + "rules": [ + "SecRuleEngine On", + "SecRule ARGS \"@detectXSS\" \"id:4,phase:2,capture,pass,t:trim\"" + ] } ] From d1eaa0453e25b431d6fa746de0d4a9e9be3cf69a Mon Sep 17 00:00:00 2001 From: Easton97-Jens <66330090+Easton97-Jens@users.noreply.github.com> Date: Sat, 28 Mar 2026 18:15:34 +0100 Subject: [PATCH 17/21] Update operator-detectsqli.json --- .../regression/operator-detectsqli.json | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/test/test-cases/regression/operator-detectsqli.json b/test/test-cases/regression/operator-detectsqli.json index 0ce5c42dd..718f7a209 100644 --- a/test/test-cases/regression/operator-detectsqli.json +++ b/test/test-cases/regression/operator-detectsqli.json @@ -44,11 +44,11 @@ "SecRuleEngine On", "SecRule ARGS \"@detectSQLi\" \"id:1,phase:2,capture,pass,t:trim\"" ] - }, + },[ { "enabled": 1, "version_min": 300000, - "title": "Testing Operator :: @detectXSS :: basic script payload", + "title": "Testing Operator :: @detectSQLi :: known fingerprint payload", "client": { "ip": "200.249.12.31", "port": 123 @@ -62,13 +62,13 @@ "Host": "localhost", "User-Agent": "curl/7.38.0", "Accept": "*/*", - "Content-Length": "45", + "Content-Length": "61", "Content-Type": "application/x-www-form-urlencoded" }, "uri": "/", "method": "POST", "body": [ - "param1=alert(1)&p=1" + "param1=' or 1=1 -- ¶m2=x" ] }, "response": { @@ -175,18 +175,17 @@ ] }, "expected": { - "debug_log": "Added DetectXSS match TX.0: ", "http_code": 200 }, "rules": [ "SecRuleEngine On", - "SecRule ARGS \"@detectXSS\" \"id:3,phase:2,capture,pass,t:trim\"" + "SecRule ARGS \"@detectSQLi\" \"id:3,phase:2,capture,pass,t:trim\"" ] }, { "enabled": 1, "version_min": 300000, - "title": "Testing Operator :: @detectXSS :: benign input should not match", + "title": "Testing Operator :: @detectSQLi :: benign input should not match", "client": { "ip": "200.249.12.31", "port": 123 @@ -225,7 +224,7 @@ }, "rules": [ "SecRuleEngine On", - "SecRule ARGS \"@detectXSS\" \"id:4,phase:2,capture,pass,t:trim\"" + "SecRule ARGS \"@detectSQLi\" \"id:4,phase:2,capture,pass,t:trim\"" ] } ] From de17a7c9926ebe62db3621e495c148bc5d39943d Mon Sep 17 00:00:00 2001 From: Easton97-Jens <66330090+Easton97-Jens@users.noreply.github.com> Date: Sat, 28 Mar 2026 18:47:21 +0100 Subject: [PATCH 18/21] test: expand libinjection detectxss and detectsqli regression cases --- .../regression/operator-detectsqli.json | 218 ++++++++++++++---- .../regression/operator-detectxss.json | 204 +++++++++++----- 2 files changed, 323 insertions(+), 99 deletions(-) diff --git a/test/test-cases/regression/operator-detectsqli.json b/test/test-cases/regression/operator-detectsqli.json index 718f7a209..969cfcf76 100644 --- a/test/test-cases/regression/operator-detectsqli.json +++ b/test/test-cases/regression/operator-detectsqli.json @@ -2,7 +2,6 @@ { "enabled": 1, "version_min": 300000, - "title": "Testing Operator :: @detectSQLi", "client": { "ip": "200.249.12.31", "port": 123 @@ -11,6 +10,18 @@ "ip": "200.249.12.31", "port": 80 }, + "response": { + "headers": { + "Date": "Mon, 13 Jul 2015 20:02:41 GMT", + "Last-Modified": "Sun, 26 Oct 2014 22:33:37 GMT", + "Content-Type": "text/html", + "Content-Length": "8" + }, + "body": [ + "no need." + ] + }, + "title": "Testing Operator :: @detectSQLi :: known stable fingerprint ascii substring", "request": { "headers": { "Host": "localhost", @@ -25,30 +36,18 @@ "param1=ascii(substring(version() from 1 for 1))¶m2=value2" ] }, - "response": { - "headers": { - "Date": "Mon, 13 Jul 2015 20:02:41 GMT", - "Last-Modified": "Sun, 26 Oct 2014 22:33:37 GMT", - "Content-Type": "text/html", - "Content-Length": "8" - }, - "body": [ - "no need." - ] - }, "expected": { "debug_log": "Added DetectSQLi match TX.0: f\\(f\\(f", "http_code": 200 }, "rules": [ "SecRuleEngine On", - "SecRule ARGS \"@detectSQLi\" \"id:1,phase:2,capture,pass,t:trim\"" + "SecRule ARGS \"@detectSQLi\" \"id:1201,phase:2,capture,pass,t:trim\"" ] - },[ + }, { "enabled": 1, "version_min": 300000, - "title": "Testing Operator :: @detectSQLi :: known fingerprint payload", "client": { "ip": "200.249.12.31", "port": 123 @@ -57,29 +56,30 @@ "ip": "200.249.12.31", "port": 80 }, + "response": { + "headers": { + "Date": "Mon, 13 Jul 2015 20:02:41 GMT", + "Last-Modified": "Sun, 26 Oct 2014 22:33:37 GMT", + "Content-Type": "text/html", + "Content-Length": "8" + }, + "body": [ + "no need." + ] + }, + "title": "Testing Operator :: @detectSQLi :: trim still detects stable fingerprint", "request": { "headers": { "Host": "localhost", "User-Agent": "curl/7.38.0", "Accept": "*/*", - "Content-Length": "61", + "Content-Length": "67", "Content-Type": "application/x-www-form-urlencoded" }, "uri": "/", "method": "POST", "body": [ - "param1=ascii(substring(version() from 1 for 1))¶m2=value2" - ] - }, - "response": { - "headers": { - "Date": "Mon, 13 Jul 2015 20:02:41 GMT", - "Last-Modified": "Sun, 26 Oct 2014 22:33:37 GMT", - "Content-Type": "text/html", - "Content-Length": "8" - }, - "body": [ - "no need." + "param1= ascii(substring(version() from 1 for 1)) ¶m2=value2" ] }, "expected": { @@ -88,13 +88,12 @@ }, "rules": [ "SecRuleEngine On", - "SecRule ARGS \"@detectSQLi\" \"id:1,phase:2,capture,pass,t:trim\"" + "SecRule ARGS \"@detectSQLi\" \"id:1202,phase:2,capture,pass,t:trim\"" ] }, { "enabled": 1, "version_min": 300000, - "title": "Testing Operator :: @detectSQLi :: trim still captures fingerprint", "client": { "ip": "200.249.12.31", "port": 123 @@ -103,20 +102,51 @@ "ip": "200.249.12.31", "port": 80 }, + "response": { + "headers": { + "Date": "Mon, 13 Jul 2015 20:02:41 GMT", + "Last-Modified": "Sun, 26 Oct 2014 22:33:37 GMT", + "Content-Type": "text/html", + "Content-Length": "8" + }, + "body": [ + "no need." + ] + }, + "title": "Testing Operator :: @detectSQLi :: boolean based payload", "request": { "headers": { "Host": "localhost", "User-Agent": "curl/7.38.0", "Accept": "*/*", - "Content-Length": "67", + "Content-Length": "33", "Content-Type": "application/x-www-form-urlencoded" }, "uri": "/", "method": "POST", "body": [ - "param1= ascii(substring(version() from 1 for 1)) ¶m2=value2" + "param1=' or 1=1 -- ¶m2=value2" ] }, + "expected": { + "http_code": 200 + }, + "rules": [ + "SecRuleEngine On", + "SecRule ARGS \"@detectSQLi\" \"id:1203,phase:2,capture,pass,t:trim\"" + ] + }, + { + "enabled": 1, + "version_min": 300000, + "client": { + "ip": "200.249.12.31", + "port": 123 + }, + "server": { + "ip": "200.249.12.31", + "port": 80 + }, "response": { "headers": { "Date": "Mon, 13 Jul 2015 20:02:41 GMT", @@ -128,19 +158,32 @@ "no need." ] }, + "title": "Testing Operator :: @detectSQLi :: union select variation", + "request": { + "headers": { + "Host": "localhost", + "User-Agent": "curl/7.38.0", + "Accept": "*/*", + "Content-Length": "46", + "Content-Type": "application/x-www-form-urlencoded" + }, + "uri": "/", + "method": "POST", + "body": [ + "param1=-1 union select 1,2,3 -- ¶m2=value2" + ] + }, "expected": { - "debug_log": "Added DetectSQLi match TX.0: f\\(f\\(f", "http_code": 200 }, "rules": [ "SecRuleEngine On", - "SecRule ARGS \"@detectSQLi\" \"id:2,phase:2,capture,pass,t:trim\"" + "SecRule ARGS \"@detectSQLi\" \"id:1204,phase:2,capture,pass,t:trim\"" ] }, { "enabled": 1, "version_min": 300000, - "title": "Testing Operator :: @detectSQLi :: boolean style payload", "client": { "ip": "200.249.12.31", "port": 123 @@ -149,20 +192,51 @@ "ip": "200.249.12.31", "port": 80 }, + "response": { + "headers": { + "Date": "Mon, 13 Jul 2015 20:02:41 GMT", + "Last-Modified": "Sun, 26 Oct 2014 22:33:37 GMT", + "Content-Type": "text/html", + "Content-Length": "8" + }, + "body": [ + "no need." + ] + }, + "title": "Testing Operator :: @detectSQLi :: time function payload", "request": { "headers": { "Host": "localhost", "User-Agent": "curl/7.38.0", "Accept": "*/*", - "Content-Length": "31", + "Content-Length": "38", "Content-Type": "application/x-www-form-urlencoded" }, "uri": "/", "method": "POST", "body": [ - "param1=' or 1=1 -- ¶m2=x" + "param1=1;select sleep(1)¶m2=value2" ] }, + "expected": { + "http_code": 200 + }, + "rules": [ + "SecRuleEngine On", + "SecRule ARGS \"@detectSQLi\" \"id:1205,phase:2,capture,pass,t:trim\"" + ] + }, + { + "enabled": 1, + "version_min": 300000, + "client": { + "ip": "200.249.12.31", + "port": 123 + }, + "server": { + "ip": "200.249.12.31", + "port": 80 + }, "response": { "headers": { "Date": "Mon, 13 Jul 2015 20:02:41 GMT", @@ -174,18 +248,32 @@ "no need." ] }, + "title": "Testing Operator :: @detectSQLi :: inline comment obfuscation", + "request": { + "headers": { + "Host": "localhost", + "User-Agent": "curl/7.38.0", + "Accept": "*/*", + "Content-Length": "35", + "Content-Type": "application/x-www-form-urlencoded" + }, + "uri": "/", + "method": "POST", + "body": [ + "param1=1/**/or/**/1=1¶m2=value2" + ] + }, "expected": { "http_code": 200 }, "rules": [ "SecRuleEngine On", - "SecRule ARGS \"@detectSQLi\" \"id:3,phase:2,capture,pass,t:trim\"" + "SecRule ARGS \"@detectSQLi\" \"id:1206,phase:2,capture,pass,t:trim\"" ] }, { "enabled": 1, "version_min": 300000, - "title": "Testing Operator :: @detectSQLi :: benign input should not match", "client": { "ip": "200.249.12.31", "port": 123 @@ -194,20 +282,51 @@ "ip": "200.249.12.31", "port": 80 }, + "response": { + "headers": { + "Date": "Mon, 13 Jul 2015 20:02:41 GMT", + "Last-Modified": "Sun, 26 Oct 2014 22:33:37 GMT", + "Content-Type": "text/html", + "Content-Length": "8" + }, + "body": [ + "no need." + ] + }, + "title": "Testing Operator :: @detectSQLi :: benign identifier with sql words", "request": { "headers": { "Host": "localhost", "User-Agent": "curl/7.38.0", "Accept": "*/*", - "Content-Length": "24", + "Content-Length": "38", "Content-Type": "application/x-www-form-urlencoded" }, "uri": "/", "method": "POST", "body": [ - "param1=hello-world&x=1" + "param1=selective_catalog¶m2=normal" ] }, + "expected": { + "http_code": 200 + }, + "rules": [ + "SecRuleEngine On", + "SecRule ARGS \"@detectSQLi\" \"id:1207,phase:2,capture,pass,t:trim\"" + ] + }, + { + "enabled": 1, + "version_min": 300000, + "client": { + "ip": "200.249.12.31", + "port": 123 + }, + "server": { + "ip": "200.249.12.31", + "port": 80 + }, "response": { "headers": { "Date": "Mon, 13 Jul 2015 20:02:41 GMT", @@ -219,12 +338,27 @@ "no need." ] }, + "title": "Testing Operator :: @detectSQLi :: numeric edge case should not match", + "request": { + "headers": { + "Host": "localhost", + "User-Agent": "curl/7.38.0", + "Accept": "*/*", + "Content-Length": "23", + "Content-Type": "application/x-www-form-urlencoded" + }, + "uri": "/", + "method": "POST", + "body": [ + "param1=100001¶m2=42" + ] + }, "expected": { "http_code": 200 }, "rules": [ "SecRuleEngine On", - "SecRule ARGS \"@detectSQLi\" \"id:4,phase:2,capture,pass,t:trim\"" + "SecRule ARGS \"@detectSQLi\" \"id:1208,phase:2,capture,pass,t:trim\"" ] } ] diff --git a/test/test-cases/regression/operator-detectxss.json b/test/test-cases/regression/operator-detectxss.json index 1fa751e1c..c0fc21ca9 100644 --- a/test/test-cases/regression/operator-detectxss.json +++ b/test/test-cases/regression/operator-detectxss.json @@ -2,7 +2,6 @@ { "enabled": 1, "version_min": 300000, - "title": "Testing Operator :: @detectXSS", "client": { "ip": "200.249.12.31", "port": 123 @@ -11,44 +10,44 @@ "ip": "200.249.12.31", "port": 80 }, + "response": { + "headers": { + "Date": "Mon, 13 Jul 2015 20:02:41 GMT", + "Last-Modified": "Sun, 26 Oct 2014 22:33:37 GMT", + "Content-Type": "text/html", + "Content-Length": "8" + }, + "body": [ + "no need." + ] + }, + "title": "Testing Operator :: @detectXSS :: script tag payload", "request": { "headers": { "Host": "localhost", "User-Agent": "curl/7.38.0", "Accept": "*/*", - "Content-Length": "45", + "Content-Length": "46", "Content-Type": "application/x-www-form-urlencoded" }, "uri": "/", "method": "POST", "body": [ - "param1=¶m2=value2" ] }, "expected": { - "debug_log": "Added DetectXSS match TX.0: ", "http_code": 200 }, "rules": [ "SecRuleEngine On", - "SecRule ARGS \"@detectXSS\" \"id:1,phase:2,capture,pass,t:trim\"" + "SecRule ARGS \"@detectXSS\" \"id:1101,phase:2,capture,pass,t:trim\"" ] }, { "enabled": 1, "version_min": 300000, - "title": "Testing Operator :: @detectXSS :: basic script payload", "client": { "ip": "200.249.12.31", "port": 123 @@ -57,44 +56,44 @@ "ip": "200.249.12.31", "port": 80 }, + "response": { + "headers": { + "Date": "Mon, 13 Jul 2015 20:02:41 GMT", + "Last-Modified": "Sun, 26 Oct 2014 22:33:37 GMT", + "Content-Type": "text/html", + "Content-Length": "8" + }, + "body": [ + "no need." + ] + }, + "title": "Testing Operator :: @detectXSS :: trim preserves captured payload", "request": { "headers": { "Host": "localhost", "User-Agent": "curl/7.38.0", "Accept": "*/*", - "Content-Length": "45", + "Content-Length": "52", "Content-Type": "application/x-www-form-urlencoded" }, "uri": "/", "method": "POST", "body": [ - "param1= ¶m2=value2" ] }, "expected": { - "debug_log": "Added DetectXSS match TX.0: ", "http_code": 200 }, "rules": [ "SecRuleEngine On", - "SecRule ARGS \"@detectXSS\" \"id:1,phase:2,capture,pass,t:trim\"" + "SecRule ARGS \"@detectXSS\" \"id:1102,phase:2,capture,pass,t:trim\"" ] }, { "enabled": 1, "version_min": 300000, - "title": "Testing Operator :: @detectXSS :: trim preserves captured payload", "client": { "ip": "200.249.12.31", "port": 123 @@ -103,44 +102,44 @@ "ip": "200.249.12.31", "port": 80 }, + "response": { + "headers": { + "Date": "Mon, 13 Jul 2015 20:02:41 GMT", + "Last-Modified": "Sun, 26 Oct 2014 22:33:37 GMT", + "Content-Type": "text/html", + "Content-Length": "8" + }, + "body": [ + "no need." + ] + }, + "title": "Testing Operator :: @detectXSS :: img onerror payload", "request": { "headers": { "Host": "localhost", "User-Agent": "curl/7.38.0", "Accept": "*/*", - "Content-Length": "53", + "Content-Length": "49", "Content-Type": "application/x-www-form-urlencoded" }, "uri": "/", "method": "POST", "body": [ - "param1= ¶m2=value2" ] }, "expected": { - "debug_log": "Added DetectXSS match TX.0: ", + "http_code": 200 + }, + "rules": [ + "SecRuleEngine On", + "SecRule ARGS \"@detectXSS\" \"id:1104,phase:2,capture,pass,t:urlDecodeUni,t:trim\"" + ] + }, + { + "enabled": 1, + "version_min": 300000, + "client": { + "ip": "200.249.12.31", + "port": 123 + }, + "server": { + "ip": "200.249.12.31", + "port": 80 + }, "response": { "headers": { "Date": "Mon, 13 Jul 2015 20:02:41 GMT", @@ -174,19 +205,32 @@ "no need." ] }, + "title": "Testing Operator :: @detectXSS :: mixed-case javascript URI", + "request": { + "headers": { + "Host": "localhost", + "User-Agent": "curl/7.38.0", + "Accept": "*/*", + "Content-Length": "40", + "Content-Type": "application/x-www-form-urlencoded" + }, + "uri": "/", + "method": "POST", + "body": [ + "param1=JaVaScRiPt:alert(1)¶m2=value2" + ] + }, "expected": { - "debug_log": "Added DetectXSS match TX.0: ", "http_code": 200 }, "rules": [ "SecRuleEngine On", - "SecRule ARGS \"@detectXSS\" \"id:3,phase:2,capture,pass,t:trim\"" + "SecRule ARGS \"@detectXSS\" \"id:1105,phase:2,capture,pass,t:trim\"" ] }, { "enabled": 1, "version_min": 300000, - "title": "Testing Operator :: @detectXSS :: benign input should not match", "client": { "ip": "200.249.12.31", "port": 123 @@ -195,20 +239,51 @@ "ip": "200.249.12.31", "port": 80 }, + "response": { + "headers": { + "Date": "Mon, 13 Jul 2015 20:02:41 GMT", + "Last-Modified": "Sun, 26 Oct 2014 22:33:37 GMT", + "Content-Type": "text/html", + "Content-Length": "8" + }, + "body": [ + "no need." + ] + }, + "title": "Testing Operator :: @detectXSS :: benign html should not match", "request": { "headers": { "Host": "localhost", "User-Agent": "curl/7.38.0", "Accept": "*/*", - "Content-Length": "24", + "Content-Length": "33", "Content-Type": "application/x-www-form-urlencoded" }, "uri": "/", "method": "POST", "body": [ - "param1=hello-world&x=1" + "param1=hello¶m2=value2" ] }, + "expected": { + "http_code": 200 + }, + "rules": [ + "SecRuleEngine On", + "SecRule ARGS \"@detectXSS\" \"id:1106,phase:2,capture,pass,t:trim\"" + ] + }, + { + "enabled": 1, + "version_min": 300000, + "client": { + "ip": "200.249.12.31", + "port": 123 + }, + "server": { + "ip": "200.249.12.31", + "port": 80 + }, "response": { "headers": { "Date": "Mon, 13 Jul 2015 20:02:41 GMT", @@ -220,12 +295,27 @@ "no need." ] }, + "title": "Testing Operator :: @detectXSS :: benign plain text should not match", + "request": { + "headers": { + "Host": "localhost", + "User-Agent": "curl/7.38.0", + "Accept": "*/*", + "Content-Length": "33", + "Content-Type": "application/x-www-form-urlencoded" + }, + "uri": "/", + "method": "POST", + "body": [ + "param1=welcome-to-modsecurity&x=1" + ] + }, "expected": { "http_code": 200 }, "rules": [ "SecRuleEngine On", - "SecRule ARGS \"@detectXSS\" \"id:4,phase:2,capture,pass,t:trim\"" + "SecRule ARGS \"@detectXSS\" \"id:1107,phase:2,capture,pass,t:trim\"" ] } ] From 0f8bc6c449883200a5e6a9d14ed9b28133e0f8cb Mon Sep 17 00:00:00 2001 From: Easton97-Jens <66330090+Easton97-Jens@users.noreply.github.com> Date: Sat, 28 Mar 2026 22:30:47 +0100 Subject: [PATCH 19/21] test: make detectxss regression checks deterministic via tx flag --- .../regression/operator-detectxss.json | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/test/test-cases/regression/operator-detectxss.json b/test/test-cases/regression/operator-detectxss.json index c0fc21ca9..5cb781083 100644 --- a/test/test-cases/regression/operator-detectxss.json +++ b/test/test-cases/regression/operator-detectxss.json @@ -37,12 +37,12 @@ ] }, "expected": { - "debug_log": "Added DetectXSS match TX.0: ", - "http_code": 200 + "http_code": 403 }, "rules": [ "SecRuleEngine On", - "SecRule ARGS \"@detectXSS\" \"id:1101,phase:2,capture,pass,t:trim\"" + "SecRule ARGS \"@detectXSS\" \"id:1101,phase:2,pass,t:trim,setvar:tx.xss_hit=1\"", + "SecRule TX:xss_hit \"@eq 1\" \"id:2101,phase:2,deny,status:403\"" ] }, { @@ -67,7 +67,7 @@ "no need." ] }, - "title": "Testing Operator :: @detectXSS :: trim preserves captured payload", + "title": "Testing Operator :: @detectXSS :: trim preserves detection", "request": { "headers": { "Host": "localhost", @@ -83,12 +83,12 @@ ] }, "expected": { - "debug_log": "Added DetectXSS match TX.0: ", - "http_code": 200 + "http_code": 403 }, "rules": [ "SecRuleEngine On", - "SecRule ARGS \"@detectXSS\" \"id:1102,phase:2,capture,pass,t:trim\"" + "SecRule ARGS \"@detectXSS\" \"id:1102,phase:2,pass,t:trim,setvar:tx.xss_hit=1\"", + "SecRule TX:xss_hit \"@eq 1\" \"id:2102,phase:2,deny,status:403\"" ] }, { @@ -129,12 +129,12 @@ ] }, "expected": { - "debug_log": "Added DetectXSS match TX.0: ", - "http_code": 200 + "http_code": 403 }, "rules": [ "SecRuleEngine On", - "SecRule ARGS \"@detectXSS\" \"id:1103,phase:2,capture,pass,t:trim\"" + "SecRule ARGS \"@detectXSS\" \"id:1103,phase:2,pass,t:trim,setvar:tx.xss_hit=1\"", + "SecRule TX:xss_hit \"@eq 1\" \"id:2103,phase:2,deny,status:403\"" ] }, { @@ -175,12 +175,12 @@ ] }, "expected": { - "debug_log": "Added DetectXSS match TX.0: ", - "http_code": 200 + "http_code": 403 }, "rules": [ "SecRuleEngine On", - "SecRule ARGS \"@detectXSS\" \"id:1104,phase:2,capture,pass,t:urlDecodeUni,t:trim\"" + "SecRule ARGS \"@detectXSS\" \"id:1104,phase:2,pass,t:urlDecodeUni,t:trim,setvar:tx.xss_hit=1\"", + "SecRule TX:xss_hit \"@eq 1\" \"id:2104,phase:2,deny,status:403\"" ] }, { @@ -221,11 +221,12 @@ ] }, "expected": { - "http_code": 200 + "http_code": 403 }, "rules": [ "SecRuleEngine On", - "SecRule ARGS \"@detectXSS\" \"id:1105,phase:2,capture,pass,t:trim\"" + "SecRule ARGS \"@detectXSS\" \"id:1105,phase:2,pass,t:trim,setvar:tx.xss_hit=1\"", + "SecRule TX:xss_hit \"@eq 1\" \"id:2105,phase:2,deny,status:403\"" ] }, { @@ -270,7 +271,8 @@ }, "rules": [ "SecRuleEngine On", - "SecRule ARGS \"@detectXSS\" \"id:1106,phase:2,capture,pass,t:trim\"" + "SecRule ARGS \"@detectXSS\" \"id:1106,phase:2,pass,t:trim,setvar:tx.xss_hit=1\"", + "SecRule TX:xss_hit \"@eq 1\" \"id:2106,phase:2,deny,status:403\"" ] }, { @@ -315,7 +317,8 @@ }, "rules": [ "SecRuleEngine On", - "SecRule ARGS \"@detectXSS\" \"id:1107,phase:2,capture,pass,t:trim\"" + "SecRule ARGS \"@detectXSS\" \"id:1107,phase:2,pass,t:trim,setvar:tx.xss_hit=1\"", + "SecRule TX:xss_hit \"@eq 1\" \"id:2107,phase:2,deny,status:403\"" ] } ] From 9b370437c85fbe65ccce0c87d985f39ba7718a12 Mon Sep 17 00:00:00 2001 From: Easton97-Jens <66330090+Easton97-Jens@users.noreply.github.com> Date: Sun, 29 Mar 2026 00:10:18 +0100 Subject: [PATCH 20/21] test: add deterministic sqli match assertions via tx.sqli_hit --- .../regression/operator-detectsqli.json | 40 +++++++++++-------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/test/test-cases/regression/operator-detectsqli.json b/test/test-cases/regression/operator-detectsqli.json index 969cfcf76..fc49b0754 100644 --- a/test/test-cases/regression/operator-detectsqli.json +++ b/test/test-cases/regression/operator-detectsqli.json @@ -37,12 +37,13 @@ ] }, "expected": { - "debug_log": "Added DetectSQLi match TX.0: f\\(f\\(f", - "http_code": 200 + "http_code": 403, + "debug_log": "Added DetectSQLi match TX.0: f\\(f\\(f" }, "rules": [ "SecRuleEngine On", - "SecRule ARGS \"@detectSQLi\" \"id:1201,phase:2,capture,pass,t:trim\"" + "SecRule ARGS \"@detectSQLi\" \"id:1201,phase:2,capture,pass,t:trim,setvar:tx.sqli_hit=1\"", + "SecRule TX:sqli_hit \"@eq 1\" \"id:2201,phase:2,deny,status:403\"" ] }, { @@ -83,12 +84,13 @@ ] }, "expected": { - "debug_log": "Added DetectSQLi match TX.0: f\\(f\\(f", - "http_code": 200 + "http_code": 403, + "debug_log": "Added DetectSQLi match TX.0: f\\(f\\(f" }, "rules": [ "SecRuleEngine On", - "SecRule ARGS \"@detectSQLi\" \"id:1202,phase:2,capture,pass,t:trim\"" + "SecRule ARGS \"@detectSQLi\" \"id:1202,phase:2,capture,pass,t:trim,setvar:tx.sqli_hit=1\"", + "SecRule TX:sqli_hit \"@eq 1\" \"id:2202,phase:2,deny,status:403\"" ] }, { @@ -129,11 +131,12 @@ ] }, "expected": { - "http_code": 200 + "http_code": 403 }, "rules": [ "SecRuleEngine On", - "SecRule ARGS \"@detectSQLi\" \"id:1203,phase:2,capture,pass,t:trim\"" + "SecRule ARGS \"@detectSQLi\" \"id:1203,phase:2,capture,pass,t:trim,setvar:tx.sqli_hit=1\"", + "SecRule TX:sqli_hit \"@eq 1\" \"id:2203,phase:2,deny,status:403\"" ] }, { @@ -174,11 +177,12 @@ ] }, "expected": { - "http_code": 200 + "http_code": 403 }, "rules": [ "SecRuleEngine On", - "SecRule ARGS \"@detectSQLi\" \"id:1204,phase:2,capture,pass,t:trim\"" + "SecRule ARGS \"@detectSQLi\" \"id:1204,phase:2,capture,pass,t:trim,setvar:tx.sqli_hit=1\"", + "SecRule TX:sqli_hit \"@eq 1\" \"id:2204,phase:2,deny,status:403\"" ] }, { @@ -219,11 +223,12 @@ ] }, "expected": { - "http_code": 200 + "http_code": 403 }, "rules": [ "SecRuleEngine On", - "SecRule ARGS \"@detectSQLi\" \"id:1205,phase:2,capture,pass,t:trim\"" + "SecRule ARGS \"@detectSQLi\" \"id:1205,phase:2,capture,pass,t:trim,setvar:tx.sqli_hit=1\"", + "SecRule TX:sqli_hit \"@eq 1\" \"id:2205,phase:2,deny,status:403\"" ] }, { @@ -264,11 +269,12 @@ ] }, "expected": { - "http_code": 200 + "http_code": 403 }, "rules": [ "SecRuleEngine On", - "SecRule ARGS \"@detectSQLi\" \"id:1206,phase:2,capture,pass,t:trim\"" + "SecRule ARGS \"@detectSQLi\" \"id:1206,phase:2,capture,pass,t:trim,setvar:tx.sqli_hit=1\"", + "SecRule TX:sqli_hit \"@eq 1\" \"id:2206,phase:2,deny,status:403\"" ] }, { @@ -313,7 +319,8 @@ }, "rules": [ "SecRuleEngine On", - "SecRule ARGS \"@detectSQLi\" \"id:1207,phase:2,capture,pass,t:trim\"" + "SecRule ARGS \"@detectSQLi\" \"id:1207,phase:2,capture,pass,t:trim,setvar:tx.sqli_hit=1\"", + "SecRule TX:sqli_hit \"@eq 1\" \"id:2207,phase:2,deny,status:403\"" ] }, { @@ -358,7 +365,8 @@ }, "rules": [ "SecRuleEngine On", - "SecRule ARGS \"@detectSQLi\" \"id:1208,phase:2,capture,pass,t:trim\"" + "SecRule ARGS \"@detectSQLi\" \"id:1208,phase:2,capture,pass,t:trim,setvar:tx.sqli_hit=1\"", + "SecRule TX:sqli_hit \"@eq 1\" \"id:2208,phase:2,deny,status:403\"" ] } ] From 830a3406c2b2ae7d528ef2ec29b095fb92aa5ffb Mon Sep 17 00:00:00 2001 From: Easton97-Jens <66330090+Easton97-Jens@users.noreply.github.com> Date: Sun, 29 Mar 2026 00:25:23 +0100 Subject: [PATCH 21/21] test: harden mixed-case javascript xss regression payload --- test/test-cases/regression/operator-detectxss.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test-cases/regression/operator-detectxss.json b/test/test-cases/regression/operator-detectxss.json index 5cb781083..8cc651f6d 100644 --- a/test/test-cases/regression/operator-detectxss.json +++ b/test/test-cases/regression/operator-detectxss.json @@ -205,19 +205,19 @@ "no need." ] }, - "title": "Testing Operator :: @detectXSS :: mixed-case javascript URI", + "title": "Testing Operator :: @detectXSS :: mixed-case javascript URI in href", "request": { "headers": { "Host": "localhost", "User-Agent": "curl/7.38.0", "Accept": "*/*", - "Content-Length": "40", + "Content-Length": "54", "Content-Type": "application/x-www-form-urlencoded" }, "uri": "/", "method": "POST", "body": [ - "param1=JaVaScRiPt:alert(1)¶m2=value2" + "param1=x¶m2=value2" ] }, "expected": {