Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
58fc3da
Update libinjection to v4.0.0
Mar 29, 2026
e1a527e
Make detect_sqli and detect_xss compatible with libinjection v4
Mar 29, 2026
d2cef41
Update regression tests for libinjection v4 compatibility
Mar 29, 2026
9e66822
syntax adjustment
Mar 30, 2026
633f2eb
Add capture/non-capture regression coverage for detectSQLi/XSS
Easton97-Jens Mar 30, 2026
b264dbf
Merge pull request #27 from Easton97-Jens/codex/add-regression-tests-…
Easton97-Jens Mar 30, 2026
7cd1d67
Fix Windows test include path and case-insensitive override matching
Easton97-Jens Mar 31, 2026
2aed15b
Merge pull request #31 from Easton97-Jens/codex/add-regression-tests-…
Easton97-Jens Mar 31, 2026
0af7e13
Update libinjection_adapter.cc
Easton97-Jens Apr 1, 2026
d8c7395
Merge branch 'owasp-modsecurity:v3/master' into v3/master-libinjectio…
Easton97-Jens Apr 1, 2026
d6648d1
Add libinjection_error.h to Makefile.am
Easton97-Jens Apr 1, 2026
19ea6d0
Isolate transaction state in multithreaded unit tests
Easton97-Jens Apr 1, 2026
e152a09
Merge pull request #32 from Easton97-Jens/codex/review-multithreaded-…
Easton97-Jens Apr 1, 2026
719d172
Merge branch 'v3/master' into v3/master-libinjection-v4.0-final
Easton97-Jens Apr 1, 2026
468f681
Update libinjection_adapter.cc
Easton97-Jens Apr 1, 2026
d19f58b
Update libinjection_adapter.h
Easton97-Jens Apr 1, 2026
91fbf35
Hide testing override functions from symbol table
Easton97-Jens Apr 3, 2026
e10e9e0
Log input in hex format for SQLi detection
Easton97-Jens Apr 3, 2026
29a461b
Add logging for input in XSS detection
Easton97-Jens Apr 3, 2026
7c104e4
Update multithreaded unit test implementation
Easton97-Jens Apr 3, 2026
0cf4f3c
Update libinjection_adapter.h
Easton97-Jens Apr 3, 2026
3e98c81
Guard log-only detect operator variables under NO_LOGS
Easton97-Jens Apr 3, 2026
e500702
Merge pull request #42 from Easton97-Jens/codex/fix-cppcheck-unreadva…
Easton97-Jens Apr 3, 2026
383da50
Harden libinjection result handling to fail-safe defaults
Easton97-Jens Apr 3, 2026
e6ce0f8
Merge pull request #44 from Easton97-Jens/codex/review-libinjection-r…
Easton97-Jens Apr 3, 2026
098ae12
operators: use shared safeLogValue in DetectXSS/DetectSQLi
Easton97-Jens Apr 4, 2026
9493ea3
Merge pull request #45 from Easton97-Jens/codex/review-xss-and-sqli-p…
Easton97-Jens Apr 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions build/win32/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ project(libModSecurityTests)

function(setTestTargetProperties executable)
target_compile_definitions(${executable} PRIVATE WITH_PCRE2)
target_include_directories(${executable} PRIVATE ${BASE_DIR} ${BASE_DIR}/headers)
target_include_directories(${executable} PRIVATE ${BASE_DIR} ${BASE_DIR}/headers ${BASE_DIR}/others)
target_link_libraries(${executable} PRIVATE libModSecurity pcre2::pcre2 dirent::dirent)
add_package_dependency(${executable} WITH_YAJL yajl::yajl HAVE_YAJL)
endfunction()
Expand Down Expand Up @@ -239,7 +239,7 @@ setTestTargetProperties(rules_optimization)
project(libModSecurityExamples)

function(setExampleTargetProperties executable)
target_include_directories(${executable} PRIVATE ${BASE_DIR} ${BASE_DIR}/headers)
target_include_directories(${executable} PRIVATE ${BASE_DIR} ${BASE_DIR}/headers ${BASE_DIR}/others)
target_link_libraries(${executable} PRIVATE libModSecurity)
endfunction()

Expand Down
1 change: 1 addition & 0 deletions others/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ noinst_HEADERS = \
libinjection/src/libinjection_sqli.h \
libinjection/src/libinjection_sqli_data.h \
libinjection/src/libinjection_xss.h \
libinjection/src/libinjection_error.h \
mbedtls/include/mbedtls/base64.h \
mbedtls/include/mbedtls/check_config.h \
mbedtls/include/mbedtls/mbedtls_config.h \
Expand Down
2 changes: 1 addition & 1 deletion others/libinjection
Submodule libinjection updated 155 files
1 change: 1 addition & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ OPERATORS = \
operators/contains_word.cc \
operators/detect_sqli.cc \
operators/detect_xss.cc \
operators/libinjection_adapter.cc \
operators/ends_with.cc \
operators/eq.cc \
operators/fuzzy_hash.cc \
Expand Down
3 changes: 2 additions & 1 deletion src/actions/init_col.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "modsecurity/actions/action.h"
#include "modsecurity/transaction.h"
#include "modsecurity/rule.h"
#include "src/utils/string.h"


namespace modsecurity {
Expand Down Expand Up @@ -68,7 +69,7 @@
}

ms_dbg_a(t, 5, "Collection `" + m_collection_key + "' initialized with " \
"value: " + collectionName);
"value: " + utils::string::safeLogValue(collectionName));

Check warning on line 72 in src/actions/init_col.cc

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Modify the macro definition so that it needs to be followed by a semicolon, or remove this empty statement.

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AZ1Xq_Yb8MsCUjGKAdFV&open=AZ1Xq_Yb8MsCUjGKAdFV&pullRequest=3528

return true;
}
Expand Down
3 changes: 2 additions & 1 deletion src/actions/msg.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "modsecurity/transaction.h"
#include "modsecurity/rule.h"
#include "modsecurity/rule_message.h"
#include "src/utils/string.h"

/*
* Description: Assigns a custom message to the rule or chain in which it
Expand All @@ -49,7 +50,7 @@
bool Msg::evaluate(RuleWithActions *rule, Transaction *transaction, RuleMessage &ruleMessage) {
const auto msg = data(transaction);
ruleMessage.m_message = msg;
ms_dbg_a(transaction, 9, "Saving msg: " + msg);
ms_dbg_a(transaction, 9, "Saving msg: " + utils::string::safeLogValue(msg));

Check warning on line 53 in src/actions/msg.cc

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Modify the macro definition so that it needs to be followed by a semicolon, or remove this empty statement.

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AZ1Xq_VX8MsCUjGKAdFS&open=AZ1Xq_VX8MsCUjGKAdFS&pullRequest=3528

return true;
}
Expand Down
2 changes: 1 addition & 1 deletion src/actions/set_env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ bool SetENV::evaluate(RuleWithActions *rule, Transaction *t) {

auto pair = utils::string::ssplit_pair(colNameExpanded, '=');
ms_dbg_a(t, 8, "Setting environment variable: "
+ pair.first + " to " + pair.second);
+ pair.first + " to " + utils::string::safeLogValue(pair.second));
#ifndef WIN32
setenv(pair.first.c_str(), pair.second.c_str(), /*overwrite*/ 1);
#else
Expand Down
3 changes: 2 additions & 1 deletion src/actions/set_sid.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include "modsecurity/transaction.h"
#include "modsecurity/rule.h"
#include "src/utils/string.h"


namespace modsecurity {
Expand All @@ -29,7 +30,7 @@
bool SetSID::evaluate(RuleWithActions *rule, Transaction *t) {
std::string colNameExpanded(m_string->evaluate(t));
ms_dbg_a(t, 8, "Session ID initiated with value: \'"
+ colNameExpanded + "\'.");
+ utils::string::safeLogValue(colNameExpanded) + "\'.");

Check warning on line 33 in src/actions/set_sid.cc

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Modify the macro definition so that it needs to be followed by a semicolon, or remove this empty statement.

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AZ1Xq_YM8MsCUjGKAdFU&open=AZ1Xq_YM8MsCUjGKAdFU&pullRequest=3528

t->m_collections.m_session_collection_key = colNameExpanded;
t->m_variableSessionID.set(colNameExpanded, t->m_variableOffset);
Expand Down
3 changes: 2 additions & 1 deletion src/actions/set_uid.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include "modsecurity/transaction.h"
#include "modsecurity/rule.h"
#include "src/utils/string.h"


namespace modsecurity {
Expand All @@ -29,7 +30,7 @@
bool SetUID::evaluate(RuleWithActions *rule, Transaction *t) {
std::string colNameExpanded(m_string->evaluate(t));
ms_dbg_a(t, 8, "User collection initiated with value: \'"
+ colNameExpanded + "\'.");
+ utils::string::safeLogValue(colNameExpanded) + "\'.");

Check warning on line 33 in src/actions/set_uid.cc

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Modify the macro definition so that it needs to be followed by a semicolon, or remove this empty statement.

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AZ1Xq_Xx8MsCUjGKAdFT&open=AZ1Xq_Xx8MsCUjGKAdFT&pullRequest=3528

t->m_collections.m_user_collection_key = colNameExpanded;
t->m_variableUserID.set(colNameExpanded, t->m_variableOffset);
Expand Down
3 changes: 2 additions & 1 deletion src/actions/set_var.cc
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@
}

ms_dbg_a(t, 8, "Saving variable: " + m_variable->m_collectionName \
+ ":" + m_variableNameExpanded + " with value: " + targetValue);
+ ":" + m_variableNameExpanded + " with value: " \
+ utils::string::safeLogValue(targetValue));

Check warning on line 127 in src/actions/set_var.cc

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Modify the macro definition so that it needs to be followed by a semicolon, or remove this empty statement.

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AZ1Xq_Yu8MsCUjGKAdFW&open=AZ1Xq_Yu8MsCUjGKAdFW&pullRequest=3528

if (tx) {
tx->storeOrUpdateFirst(t, m_variableNameExpanded, targetValue);
Expand Down
6 changes: 3 additions & 3 deletions src/engine/lua.cc
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ int Lua::run(Transaction *t, const std::string &str) { // cppcheck-suppress cons

lua_getglobal(L, "main");

ms_dbg_a(t, 9, str);
ms_dbg_a(t, 9, utils::string::safeLogMetadata("Lua argument", str));

/* Put the parameter on the stack. */
if (!str.empty() ) {
Expand All @@ -211,7 +211,8 @@ int Lua::run(Transaction *t, const std::string &str) { // cppcheck-suppress cons
luaRet.assign(a);
}

ms_dbg_a(t, 9, "Returning from lua script: " + luaRet);
ms_dbg_a(t, 9, "Returning from lua script: "
+ utils::string::safeLogValue(luaRet));

if (luaRet.size() == 0) {
ret = false;
Expand Down Expand Up @@ -474,4 +475,3 @@ void Lua::applyTransformations(lua_State *L, const Transaction *t,

} // namespace engine
} // namespace modsecurity

112 changes: 84 additions & 28 deletions src/operators/detect_sqli.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,45 +17,101 @@

#include <string>
#include <list>
#include <array>

#include "src/operators/operator.h"
#include "libinjection/src/libinjection.h"

namespace modsecurity {
namespace operators {
#include "src/operators/libinjection_utils.h"
#include "src/operators/libinjection_adapter.h"
#include "src/utils/string.h"
#include "libinjection/src/libinjection_error.h"

namespace modsecurity::operators {

bool DetectSQLi::evaluate(Transaction *t, RuleWithActions *rule,
const std::string& input, RuleMessage &ruleMessage) {
char fingerprint[8];
int issqli;
#ifndef NO_LOGS
const std::string loggable_input = utils::string::safeLogValue(input);
#endif

std::array<char, 8> fingerprint{};

issqli = libinjection_sqli(input.c_str(), input.length(), fingerprint);
const injection_result_t sqli_result =
runLibinjectionSQLi(input.c_str(), input.length(), fingerprint.data());

if (!t) {
goto tisempty;
if (t == nullptr) {
return isMaliciousLibinjectionResult(sqli_result);
}

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:
t->m_matched.emplace_back(fingerprint.data());

#ifndef NO_LOGS
ms_dbg_a(t, 4,
std::string("detected SQLi using libinjection with fingerprint '")
+ fingerprint.data() + "' at: '" + loggable_input + "'");
#endif

if (rule != nullptr && rule->hasCaptureAction()) {
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;

case LIBINJECTION_RESULT_ERROR:
#ifndef NO_LOGS
ms_dbg_a(t, 4,
std::string("libinjection parser error during SQLi analysis (")
+ libinjectionResultToString(sqli_result)
+ "); treating as match (fail-safe). Input: '"
+ loggable_input + "'");
#endif

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: ")
+ loggable_input);

Check warning on line 80 in src/operators/detect_sqli.cc

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Modify the macro definition so that it needs to be followed by a semicolon, or remove this empty statement.

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AZ1Xq_cB8MsCUjGKAdFj&open=AZ1Xq_cB8MsCUjGKAdFj&pullRequest=3528
}

// Keep m_matched untouched for parser-error paths to avoid
// introducing synthetic fingerprints for non-TRUE results.
break;

case LIBINJECTION_RESULT_FALSE:
#ifndef NO_LOGS
ms_dbg_a(t, 9,
std::string("libinjection was not able to find any SQLi in: ")
+ loggable_input);
#endif
break;

default:
#ifndef NO_LOGS
ms_dbg_a(t, 4,
std::string("libinjection returned unexpected SQLi result (")
+ libinjectionResultToString(sqli_result)
+ "); treating as match (fail-safe). Input: '"
+ loggable_input + "'");

Check warning on line 101 in src/operators/detect_sqli.cc

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Modify the macro definition so that it needs to be followed by a semicolon, or remove this empty statement.

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AZ1UWGBqBSQh-ACkadKW&open=AZ1UWGBqBSQh-ACkadKW&pullRequest=3528
#endif
if (rule != nullptr && rule->hasCaptureAction()) {
t->m_collections.m_tx_collection->storeOrUpdateFirst(
"0", input);

ms_dbg_a(t, 7,
std::string("Added DetectSQLi unexpected input TX.0: ")
+ loggable_input);

Check warning on line 109 in src/operators/detect_sqli.cc

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Modify the macro definition so that it needs to be followed by a semicolon, or remove this empty statement.

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AZ1Xq_cB8MsCUjGKAdFk&open=AZ1Xq_cB8MsCUjGKAdFk&pullRequest=3528
}
break;
}

tisempty:
return issqli != 0;
return isMaliciousLibinjectionResult(sqli_result);
}


} // namespace operators
} // namespace modsecurity
} // namespace modsecurity::operators
86 changes: 62 additions & 24 deletions src/operators/detect_xss.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,36 +18,74 @@
#include <string>

#include "src/operators/operator.h"
#include "libinjection/src/libinjection.h"


namespace modsecurity {
namespace operators {
#include "src/operators/libinjection_utils.h"
#include "src/operators/libinjection_adapter.h"
#include "src/utils/string.h"
#include "libinjection/src/libinjection_error.h"

namespace modsecurity::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());

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));
#ifndef NO_LOGS
const std::string loggable_input = utils::string::safeLogValue(input);
#endif

const injection_result_t xss_result =
runLibinjectionXSS(input.c_str(), input.length());

if (t == nullptr) {
return isMaliciousLibinjectionResult(xss_result);
}

switch (xss_result) {
case LIBINJECTION_RESULT_TRUE:
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: ") + loggable_input);

Check warning on line 46 in src/operators/detect_xss.cc

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Modify the macro definition so that it needs to be followed by a semicolon, or remove this empty statement.

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AZ1Xq_aZ8MsCUjGKAdFd&open=AZ1Xq_aZ8MsCUjGKAdFd&pullRequest=3528
}
} else {
ms_dbg_a(t, 9, "libinjection was not able to " \
"find any XSS in: " + input);
break;

case LIBINJECTION_RESULT_ERROR:
#ifndef NO_LOGS
ms_dbg_a(t, 4,
std::string("libinjection parser error during XSS analysis (")
+ libinjectionResultToString(xss_result)
+ "); treating as match (fail-safe). Input: "
+ loggable_input);
#endif
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: ") + loggable_input);

Check warning on line 60 in src/operators/detect_xss.cc

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Modify the macro definition so that it needs to be followed by a semicolon, or remove this empty statement.

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AZ1Xq_aZ8MsCUjGKAdFe&open=AZ1Xq_aZ8MsCUjGKAdFe&pullRequest=3528
}
break;

case LIBINJECTION_RESULT_FALSE:
#ifndef NO_LOGS
ms_dbg_a(t, 9,
std::string("libinjection was not able to find any XSS in: ")
+ loggable_input);
#endif
break;

default:
#ifndef NO_LOGS
ms_dbg_a(t, 4,
std::string("libinjection returned unexpected XSS result (")
+ libinjectionResultToString(xss_result)
+ "); treating as match (fail-safe). Input: "
+ loggable_input);

Check warning on line 78 in src/operators/detect_xss.cc

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Modify the macro definition so that it needs to be followed by a semicolon, or remove this empty statement.

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AZ1UWF-6BSQh-ACkadKU&open=AZ1UWF-6BSQh-ACkadKU&pullRequest=3528
#endif
if (rule != nullptr && rule->hasCaptureAction()) {
t->m_collections.m_tx_collection->storeOrUpdateFirst("0", input);
ms_dbg_a(t, 7,
std::string("Added DetectXSS unexpected input TX.0: ") + loggable_input);

Check warning on line 83 in src/operators/detect_xss.cc

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Modify the macro definition so that it needs to be followed by a semicolon, or remove this empty statement.

See more on https://sonarcloud.io/project/issues?id=owasp-modsecurity_ModSecurity&issues=AZ1Xq_aZ8MsCUjGKAdFf&open=AZ1Xq_aZ8MsCUjGKAdFf&pullRequest=3528
}
break;
}
return is_xss != 0;
}

return isMaliciousLibinjectionResult(xss_result);
}

} // namespace operators
} // namespace modsecurity
} // namespace modsecurity::operators
Loading
Loading