diff -pruN 2.9.10-1/CHANGES 2.9.11-1/CHANGES
--- 2.9.10-1/CHANGES	2025-06-02 19:43:30.000000000 +0000
+++ 2.9.11-1/CHANGES	2025-07-02 09:23:15.000000000 +0000
@@ -1,3 +1,15 @@
+01 Jul 2025 - 2.9.11
+--------------------
+
+ * fix: prevent segmentation fault if the XML node is empty
+   [PR from private repo - @theseion, @fzipi, @RedXanadu, @airween; fixed CVE-2025-52891]
+ * Plug memory leak when msre_op_validateSchema_execute() exits normally (validateSchema)
+   [Issue #3401 - @nic-prgs]
+ * chore: bump version in MSI installer.wxs
+   [Issue #3400 - @airween]
+ * Fix resource leaks in `msc_status_engine_mac_address`
+   [Issue #3391 - @amezin]
+
 02 Jun 2025 - 2.9.10
 --------------------
 
diff -pruN 2.9.10-1/apache2/msc_release.h 2.9.11-1/apache2/msc_release.h
--- 2.9.10-1/apache2/msc_release.h	2025-06-02 19:43:30.000000000 +0000
+++ 2.9.11-1/apache2/msc_release.h	2025-07-02 09:23:15.000000000 +0000
@@ -38,7 +38,7 @@
 
 #define MODSEC_VERSION_MAJOR       "2"
 #define MODSEC_VERSION_MINOR       "9"
-#define MODSEC_VERSION_MAINT       "10"
+#define MODSEC_VERSION_MAINT       "11"
 #define MODSEC_VERSION_TYPE        ""
 #define MODSEC_VERSION_RELEASE     ""
 
diff -pruN 2.9.10-1/apache2/msc_status_engine.c 2.9.11-1/apache2/msc_status_engine.c
--- 2.9.10-1/apache2/msc_status_engine.c	2025-06-02 19:43:30.000000000 +0000
+++ 2.9.11-1/apache2/msc_status_engine.c	2025-07-02 09:23:15.000000000 +0000
@@ -182,7 +182,7 @@ int DSOLOCAL msc_status_engine_mac_addre
                 (unsigned char)LLADDR(sdl)[3],
                 (unsigned char)LLADDR(sdl)[4],
                 (unsigned char)LLADDR(sdl)[5]);
-            goto end;
+            break;
         }
     }
 
@@ -225,7 +225,7 @@ int DSOLOCAL msc_status_engine_mac_addre
                 (unsigned char)ifr->ifr_addr.sa_data[4],
                 (unsigned char)ifr->ifr_addr.sa_data[5]);
 
-            goto end;
+            break;
         }
     }
     close( sock );
@@ -268,7 +268,7 @@ int DSOLOCAL msc_status_engine_mac_addre
                 (unsigned char)pAdapter->Address[3],
                 (unsigned char)pAdapter->Address[4],
                 (unsigned char)pAdapter->Address[5]);
-            goto end;
+            break;
         }
         pAdapter = pAdapter->Next;
     }
@@ -276,7 +276,6 @@ int DSOLOCAL msc_status_engine_mac_addre
     free(pAdapterInfo);
 #endif
 
-end:
     return 0;
 failed:
     return -1;
diff -pruN 2.9.10-1/apache2/msc_xml.c 2.9.11-1/apache2/msc_xml.c
--- 2.9.10-1/apache2/msc_xml.c	2025-06-02 19:43:30.000000000 +0000
+++ 2.9.11-1/apache2/msc_xml.c	2025-07-02 09:23:15.000000000 +0000
@@ -36,6 +36,7 @@ static void msc_xml_on_start_elementns(
     xml_parser_state->pathlen += (taglen + 1);
     char *newpath = apr_pstrcat(msr->mp, xml_parser_state->currpath, ".", (char *)localname, NULL);
     xml_parser_state->currpath = newpath;
+    xml_parser_state->currpathbufflen += taglen + 1; // +1 for the '.' character here too
 
     int *new_stack_item = (int *)apr_array_push(xml_parser_state->has_child_stack);
     *new_stack_item = 0;
@@ -44,6 +45,7 @@ static void msc_xml_on_start_elementns(
     // this is necessary because if there is any text between the tags (new line, etc)
     // it will be added to the current value
     xml_parser_state->currval = NULL;
+    xml_parser_state->currvalbufflen = 0;
 
     // if there is an item before the current one we set that has a child
     if (xml_parser_state->depth > 1) {
@@ -72,8 +74,12 @@ static void msc_xml_on_end_elementns(
         if (apr_table_elts(msr->arguments)->nelts >= msr->txcfg->arguments_limit) {
             if (msr->txcfg->debuglog_level >= 4) {
                 msr_log(msr, 4, "Skipping request argument, over limit (XML): name \"%s\", value \"%s\"",
-                        log_escape_ex(msr->mp, xml_parser_state->currpath, strlen(xml_parser_state->currpath)),
-                        log_escape_ex(msr->mp, xml_parser_state->currval, strlen(xml_parser_state->currval)));
+                        log_escape_ex(msr->mp, xml_parser_state->currpath, xml_parser_state->currpathbufflen),
+                        log_escape_ex(msr->mp,
+                                      (xml_parser_state->currval == NULL ? apr_pstrndup(msr->mp, "", 1) : xml_parser_state->currval),
+                                      (xml_parser_state->currvalbufflen == 0 ? 1 : xml_parser_state->currvalbufflen)
+                                     )
+                        );
             }
             msr->msc_reqbody_error = 1;
             msr->xml->xml_error = apr_psprintf(msr->mp, "More than %ld ARGS (GET + XML)", msr->txcfg->arguments_limit);
@@ -84,15 +90,15 @@ static void msc_xml_on_end_elementns(
             msc_arg * arg = (msc_arg *) apr_pcalloc(msr->mp, sizeof(msc_arg));
 
             arg->name = xml_parser_state->currpath;
-            arg->name_len = strlen(arg->name);
-            arg->value = xml_parser_state->currval;
-            arg->value_len = strlen(xml_parser_state->currval);
+            arg->name_len = xml_parser_state->currpathbufflen;
+            arg->value = (xml_parser_state->currval == NULL) ? apr_pstrndup(msr->mp, "", 1) : xml_parser_state->currval;
+            arg->value_len = (xml_parser_state->currvalbufflen == 0) ? 1 : xml_parser_state->currvalbufflen;
             arg->value_origin_len = arg->value_len;
             arg->origin = "XML";
 
             if (msr->txcfg->debuglog_level >= 9) {
                 msr_log(msr, 9, "Adding XML argument '%s' with value '%s'",
-                    xml_parser_state->currpath, xml_parser_state->currval);
+                    arg->name, arg->value);
             }
 
             apr_table_addn(msr->arguments,
@@ -106,9 +112,11 @@ static void msc_xml_on_end_elementns(
     // -1 is needed because we don't need the last '.'
     char * newpath = apr_pstrndup(msr->mp, xml_parser_state->currpath, xml_parser_state->pathlen - 1);
     xml_parser_state->currpath = newpath;
+    xml_parser_state->currpathbufflen = xml_parser_state->pathlen - 1;
 
     xml_parser_state->depth--;
     xml_parser_state->currval = NULL;
+    xml_parser_state->currvalbufflen = 0;
 }
 
 static void msc_xml_on_characters(void *ctx, const xmlChar *ch, int len) {
@@ -123,6 +131,7 @@ static void msc_xml_on_characters(void *
                                             ((xml_parser_state->currval != NULL) ? xml_parser_state->currval : ""),
                                             apr_pstrndup(msr->mp, (const char *)ch, len),
                                             NULL);
+    xml_parser_state->currvalbufflen += len;
     // check if the memory allocation was successful
     if (xml_parser_state->currval == NULL) {
         msr->xml->xml_error = apr_psprintf(msr->mp, "Failed to allocate memory for XML value.");
@@ -174,8 +183,9 @@ int xml_init(modsec_rec *msr, char **err
         msr->xml->xml_parser_state->depth           = 0;
         msr->xml->xml_parser_state->pathlen         = 4; // "xml\0"
         msr->xml->xml_parser_state->currpath        = apr_pstrdup(msr->mp, "xml");
+        msr->xml->xml_parser_state->currpathbufflen = 3; // "xml"
         msr->xml->xml_parser_state->currval         = NULL;
-        msr->xml->xml_parser_state->currpathbufflen = 4;
+        msr->xml->xml_parser_state->currvalbufflen  = 0;
         // initialize the stack with item of 10
         // this will store the information about nodes
         // 10 is just an initial value, it can be automatically incremented
diff -pruN 2.9.10-1/apache2/msc_xml.h 2.9.11-1/apache2/msc_xml.h
--- 2.9.10-1/apache2/msc_xml.h	2025-06-02 19:43:30.000000000 +0000
+++ 2.9.11-1/apache2/msc_xml.h	2025-07-02 09:23:15.000000000 +0000
@@ -31,6 +31,7 @@ struct msc_xml_parser_state {
     char               * currpath;
     char               * currval;
     size_t               currpathbufflen;
+    size_t               currvalbufflen;
     apr_pool_t         * mp;
 };
 
diff -pruN 2.9.10-1/apache2/re_operators.c 2.9.11-1/apache2/re_operators.c
--- 2.9.10-1/apache2/re_operators.c	2025-06-02 19:43:30.000000000 +0000
+++ 2.9.11-1/apache2/re_operators.c	2025-07-02 09:23:15.000000000 +0000
@@ -2898,6 +2898,7 @@ static int msre_op_validateSchema_execut
 
     xmlSchemaFree(schema);
     xmlSchemaFreeValidCtxt(validCtx);
+    xmlSchemaFreeParserCtxt(parserCtx);
 
     return 0;
 }
diff -pruN 2.9.10-1/debian/changelog 2.9.11-1/debian/changelog
--- 2.9.10-1/debian/changelog	2025-06-02 19:43:53.000000000 +0000
+++ 2.9.11-1/debian/changelog	2025-07-02 09:23:42.000000000 +0000
@@ -1,3 +1,11 @@
+modsecurity-apache (2.9.11-1) unstable; urgency=medium
+
+  [ Ervin Hegedüs ]
+  * New upstream version 2.9.11
+  * Fixes CVE-2025-52891
+
+ -- Ervin Hegedüs <airween@gmail.com>  Wed, 02 Jul 2025 11:23:42 +0200
+
 modsecurity-apache (2.9.10-1) unstable; urgency=medium
 
   [ Ervin Hegedüs ]
diff -pruN 2.9.10-1/iis/installer.wxs 2.9.11-1/iis/installer.wxs
--- 2.9.10-1/iis/installer.wxs	2025-06-02 19:43:30.000000000 +0000
+++ 2.9.11-1/iis/installer.wxs	2025-07-02 09:23:15.000000000 +0000
@@ -7,9 +7,9 @@
     lightArgs: 
 -->
 <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
-    <Product Id="22B04FDB-9BAB-46B0-87B8-A39544ECECD3" Name="ModSecurity IIS" Language="1033" Version="2.9.7" Manufacturer="ModSecurity" UpgradeCode="82F09489-1678-4C38-ADCB-08C3757653DB">
+    <Product Id="22B04FDB-9BAB-46B0-87B8-A39544ECECD3" Name="ModSecurity IIS" Language="1033" Version="2.9.11" Manufacturer="ModSecurity" UpgradeCode="82F09489-1678-4C38-ADCB-08C3757653DB">
         <Package Description="ModSecurityISS" Comments="none" InstallerVersion="405" Compressed="yes" InstallPrivileges="elevated" InstallScope="perMachine" />
-        <?define ProductName = "ModSecuirty IIS" ?>
+        <?define ProductName = "ModSecurity IIS" ?>
         <?if $(sys.BUILDARCH) = x64 ?>
         <?define Win64 = "yes" ?>
         <?define PlatformProgramFilesFolder = "ProgramFiles64Folder" ?>
