Package: release.debian.org
Severity: normal
Tags: security
X-Debbugs-Cc: [email protected], [email protected], Debian 
Security Team <[email protected]>
Control: affects -1 + src:modsecurity
User: [email protected]
Usertags: pu


[ Reason ]
Fixes for CVE-2026-52747 and CVE-2026-52761

[ Impact ]
Security rules bypass.

[ Tests ]
Fixed and tested by upstream.

[ Risks ]
Low risk, simple patch.

[ Checklist ]
  [x] *all* changes are documented in the d/changelog
  [x] I reviewed all changes and I approve them
  [x] attach debdiff against the package in (old)stable
  [x] the issue is verified as fixed in unstable

[ Changes ]
Preserve line breaks from non-file form-field values.
Fix returned length of "unicode" variable.
diff -Nru modsecurity-3.0.14/debian/changelog 
modsecurity-3.0.14/debian/changelog
--- modsecurity-3.0.14/debian/changelog 2026-04-30 17:23:57.000000000 +0200
+++ modsecurity-3.0.14/debian/changelog 2026-06-30 21:01:17.000000000 +0200
@@ -1,3 +1,13 @@
+modsecurity (3.0.14-1+deb13u2) trixie; urgency=medium
+
+  [ Alberto Gonzalez Iniesta ]
+  * Fix CVE number
+
+  [ Ervin Hegedus ]
+  * Add fixes for CVE-2026-52747 and CVE-2026-52761
+
+ -- Ervin Hegedüs <[email protected]>  Tue, 30 Jun 2026 21:01:17 +0200
+
 modsecurity (3.0.14-1+deb13u1) trixie; urgency=medium
 
   [ Ervin Hegedus ]
diff -Nru modsecurity-3.0.14/debian/patches/fix-CVE-2026-52747.patch 
modsecurity-3.0.14/debian/patches/fix-CVE-2026-52747.patch
--- modsecurity-3.0.14/debian/patches/fix-CVE-2026-52747.patch  1970-01-01 
01:00:00.000000000 +0100
+++ modsecurity-3.0.14/debian/patches/fix-CVE-2026-52747.patch  2026-06-30 
21:01:17.000000000 +0200
@@ -0,0 +1,97 @@
+From: Ervin Hegedus <[email protected]>
+Date: Tue, 30 Jun 2026 20:54:08 +0200
+Subject: fix-CVE-2026-52747
+
+---
+ src/request_body_processor/multipart.cc            |  2 +-
+ .../request-body-parser-multipart-crlf.json        | 58 +++++++++++++++++++++-
+ 2 files changed, 58 insertions(+), 2 deletions(-)
+
+diff --git a/src/request_body_processor/multipart.cc 
b/src/request_body_processor/multipart.cc
+index fd14032..5f6d802 100644
+--- a/src/request_body_processor/multipart.cc
++++ b/src/request_body_processor/multipart.cc
+@@ -669,7 +669,7 @@ int Multipart::process_part_data(std::string *error, 
size_t offset) {
+ 
+         if (m_reserve[0] != 0) {
+             d.assign(&(m_reserve[1]), m_reserve[0]);
+-            d.assign(m_buf, MULTIPART_BUF_SIZE - m_bufleft);
++            d.append(m_buf, MULTIPART_BUF_SIZE - m_bufleft);
+ 
+             m_mpp->m_length += d.size();
+         } else {
+diff --git 
a/test/test-cases/regression/request-body-parser-multipart-crlf.json 
b/test/test-cases/regression/request-body-parser-multipart-crlf.json
+index 8d49c79..6d06d20 100644
+--- a/test/test-cases/regression/request-body-parser-multipart-crlf.json
++++ b/test/test-cases/regression/request-body-parser-multipart-crlf.json
+@@ -52,7 +52,7 @@
+       ]
+     },
+     "expected":{
+-      "debug_log":"Adding request argument \\(BODY\\): name \"b\", value 
\"22.12.22.3\"",
++      "debug_log":"Adding request argument \\(BODY\\): name \"b\", value 
\"2\r\n2.1\r\n2.2\r\n2.3\"",
+       "http_code":403
+     },
+     "rules":[
+@@ -63,5 +63,61 @@
+         "SecRule REQBODY_PROCESSOR_ERROR \"@eq 1\" 
\"phase:2,deny,id:500057\"",
+         "SecRule ARGS_POST \"@eq 1231\" \"phase:2,deny,id:500067\""
+     ]
++  },
++  {
++    "enabled": 1,
++    "version_min": 300000,
++    "title": "multipart parser - check \\r and \\n in multipart part",
++    "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": "144",
++        "Content-Type": "multipart/form-data; boundary=00000000; 
charset=UTF-8",
++        "Expect": "100-continue"
++      },
++      "uri": "/",
++      "method": "POST",
++      "body": [
++        "--00000000\r",
++        "Content-Disposition: form-data; name=\"namea\"\r",
++        "\r",
++        "111\r",
++        "--00000000\r",
++        "Content-Disposition: form-data; name=\"nameb\"\r",
++        "\r",
++        "22\r\n2\r",
++        "--00000000--"
++      ]
++    },
++    "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": "Multipart: Invalid parameter after boundary in C-T 
\\(tolerated\\).*Added data",
++      "http_code": 403
++    },
++    "rules": [
++      "SecRuleEngine On",
++      "SecRequestBodyAccess On",
++      "SecRule ARGS:nameb \"@streq 22\r\n2\" \"phase:2,deny,id:500096\""
++    ]
+   }
+ ]
diff -Nru modsecurity-3.0.14/debian/patches/fix-CVE-2026-52761.patch 
modsecurity-3.0.14/debian/patches/fix-CVE-2026-52761.patch
--- modsecurity-3.0.14/debian/patches/fix-CVE-2026-52761.patch  1970-01-01 
01:00:00.000000000 +0100
+++ modsecurity-3.0.14/debian/patches/fix-CVE-2026-52761.patch  2026-06-30 
21:01:17.000000000 +0200
@@ -0,0 +1,165 @@
+From: Ervin Hegedus <[email protected]>
+Date: Tue, 30 Jun 2026 20:59:36 +0200
+Subject: fix-CVE-2026-52761
+
+---
+ src/actions/transformations/utf8_to_unicode.cc     | 25 ++++-------
+ test/test-cases/regression/transformations.json    | 50 ++++++++++++++++++++++
+ .../transformations/utf8toUnicode.json             |  7 +++
+ 3 files changed, 66 insertions(+), 16 deletions(-)
+
+diff --git a/src/actions/transformations/utf8_to_unicode.cc 
b/src/actions/transformations/utf8_to_unicode.cc
+index 4b01583..8d75bdd 100644
+--- a/src/actions/transformations/utf8_to_unicode.cc
++++ b/src/actions/transformations/utf8_to_unicode.cc
+@@ -34,7 +34,9 @@ static inline bool encode(std::string &value) {
+     bool changed = false;
+     std::string::size_type count = 0;
+     auto bytes_left = input_len;
+-    unsigned char unicode[8];
++    char unicode[8] = {0}; /* 5 or 6 bytes for OLD standard unicode character 
and 1 byte for null terminator */
++                           /* 4 bytes are enough for standard UTF8 + '\0' */
++                           /* result can be only signed char array, so no 
need to cast later */
+ 
+     /* RFC3629 states that UTF-8 are encoded using sequences of 1 to 4 
octets. */
+     /* Max size per character should fit in 4 bytes */
+@@ -81,10 +83,7 @@ static inline bool encode(std::string &value) {
+                     d = ((c & 0x1F) << 6) | (*(utf + 1) & 0x3F);
+                     *data++ = '%';
+                     *data++ = 'u';
+-                    snprintf(reinterpret_cast<char *>(unicode),
+-                             sizeof(reinterpret_cast<char *>(unicode)),
+-                             "%x", d);
+-                    length = strlen(reinterpret_cast<char *>(unicode));
++                    length = snprintf(unicode, sizeof(unicode), "%x", d);
+ 
+                     switch (length) {
+                         case 1:
+@@ -104,7 +103,7 @@ static inline bool encode(std::string &value) {
+                             break;
+                     }
+ 
+-                    for (std::string::size_type j = 0; j < length; j++) {
++                    for (int j = 0; j < length; j++) {
+                         *data++ = unicode[j];
+                     }
+ 
+@@ -133,10 +132,7 @@ static inline bool encode(std::string &value) {
+                         | (*(utf + 2) & 0x3F);
+                     *data++ = '%';
+                     *data++ = 'u';
+-                    snprintf(reinterpret_cast<char *>(unicode),
+-                             sizeof(reinterpret_cast<char *>(unicode)),
+-                             "%x", d);
+-                    length = strlen(reinterpret_cast<char *>(unicode));
++                    length = snprintf(unicode, sizeof(unicode), "%x", d);
+ 
+                     switch (length)  {
+                         case 1:
+@@ -156,7 +152,7 @@ static inline bool encode(std::string &value) {
+                             break;
+                     }
+ 
+-                    for (std::string::size_type j = 0; j < length; j++) {
++                    for (int j = 0; j < length; j++) {
+                         *data++ = unicode[j];
+                     }
+ 
+@@ -195,10 +191,7 @@ static inline bool encode(std::string &value) {
+                         | (*(utf + 3) & 0x3F);
+                     *data++ = '%';
+                     *data++ = 'u';
+-                    snprintf(reinterpret_cast<char *>(unicode),
+-                             sizeof(reinterpret_cast<char *>(unicode)),
+-                             "%x", d);
+-                    length = strlen(reinterpret_cast<char *>(unicode));
++                    length = snprintf(unicode, sizeof(unicode), "%x", d);
+ 
+                     switch (length)  {
+                         case 1:
+@@ -218,7 +211,7 @@ static inline bool encode(std::string &value) {
+                             break;
+                     }
+ 
+-                    for (std::string::size_type j = 0; j < length; j++) {
++                    for (int j = 0; j < length; j++) {
+                         *data++ = unicode[j];
+                     }
+ 
+diff --git a/test/test-cases/regression/transformations.json 
b/test/test-cases/regression/transformations.json
+index dcb328f..a58df52 100644
+--- a/test/test-cases/regression/transformations.json
++++ b/test/test-cases/regression/transformations.json
+@@ -114,5 +114,55 @@
+       "SecRuleEngine On",
+       "SecRule ARGS \"@contains test \" \"id:1,pass,t:trim,t:lowercase\""
+     ]
++  },
++  {
++    "enabled": 1,
++    "version_min": 300000,
++    "version_max": 0,
++    "title": "Testing transformations :: 
none,utf8toUnicode,urlDecodeUni,htmlEntityDecode,jsDecode,cssDecode,removeNulls",
++    "client": {
++      "ip": "200.249.12.31",
++      "port": 2313
++    },
++    "server": {
++      "ip": "200.249.12.31",
++      "port": 80
++    },
++    "request": {
++      "headers": {
++        "Host": "www.modsecurity.org",
++        "User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; 
rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)",
++        "Accept": 
"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
++        "Accept-Language": "en-us,en;q=0.5",
++        "Accept-Encoding": "gzip,deflate",
++        "Accept-Charset": "ISO-8859-1,utf-8;q=0.7,*;q=0.7",
++        "Keep-Alive": "300",
++        "Connection": "keep-alive",
++        "Pragma": "no-cache",
++        "Cache-Control": "no-cache",
++        "Content-Length": "0"
++      },
++      "uri": 
"/?var=%ef%bc%9cscript%20%ef%bc%9ealert%281%29%ef%bc%9c/script%ef%bc%9e",
++      "method": "GET",
++      "http_version": 1.1,
++      "body": [
++        ""
++      ]
++    },
++    "response": {
++      "headers": {
++        "Content-Length": "0"
++      },
++      "body": [
++        ""
++      ]
++    },
++    "expected": {
++      "http_code": 403
++    },
++    "rules": [
++      "SecRuleEngine On",
++      "SecRule ARGS \"@rx (?i)<script[^>]*>[\\s\\S]*?\" 
\"id:941110,phase:2,deny,capture,t:none,t:utf8toUnicode,t:urlDecodeUni,t:htmlEntityDecode,t:jsDecode,t:cssDecode,t:removeNulls\""
++    ]
+   }
+ ]
+diff --git 
a/test/test-cases/secrules-language-tests/transformations/utf8toUnicode.json 
b/test/test-cases/secrules-language-tests/transformations/utf8toUnicode.json
+index 52192c0..23792d1 100644
+--- 
a/test/test-cases/secrules-language-tests/transformations/utf8toUnicode.json
++++ 
b/test/test-cases/secrules-language-tests/transformations/utf8toUnicode.json
+@@ -48,5 +48,12 @@
+       "type" : "tfn",
+       "ret" : 1,
+       "output" : "%u0100%u0080 %u00c4%u0081 %u00c4%u0082 %u00c4%u0083 
%u00c4%u0084 %u00c4%u0085 %u00c4%u0086 %u00c4%u0087 %u00c4%u0088 %u00c4%u0089 
%u00c4%u008a %u00c4%u008b %u00c4%u008c %u00c4%u008d %u00c4%u008e %u00c4%u008f 
%u00c4%u0090 %u00c4%u0091 %u00c4%u0092 %u00c4%u0093 %u00c4%u0094 %u00c4%u0095 
%u00c4%u0096 %u00c4%u0097 %u00c4%u0098 %u00c4%u0099 %u00c4%u009a %u00c4%u009b 
%u00c4%u009c %u00c4%u009d %u00c4%u009e %u00c4%u009f %u00c4%u00a0 %u00c4%u00a1 
%u00c4%u00a2 %u00c4%u00a3 %u00c4%u00a4 %u00c4%u00a5 %u00c4%u00a6 %u00c4%u00a7 
%u00c4%u00a8 %u00c4%u00a9 %u00c4%u00aa %u00c4%u00ab %u00c4%u00ac %u00c4%u00ad 
%u00c4%u00ae %u00c4%u00af %u00c4%u00b0 %u00c4%u00b1 %u00c4%u00b2 %u00c4%u00b3 
%u00c4%u00b4 %u00c4%u00b5 %u00c4%u00b6 %u00c4%u00b7 %u00c4%u00b8 %u00c4%u00b9 
%u00c4%u00ba %u00c4%u00bb %u00c4%u00bc %u00c4%u00bd %u00c4%u00be %u00c4%u00bf 
%u00c5%u0080 %u00c5%u0081 %u00c5%u0082 %u00c5%u0083 %u00c5%u0084 %u00c5%u0085 
%u00c5%u0086 %u00c5%u0087 %u00c5%u0088 %u00c5%u0089 %u00c5%u008a %u00c5%u008b 
%u00c5%u008c %u00c5%u008d %u00c5%u008e %u00c5%u008f %u00c5%u0090 %u00c5%u0091 
%u00c5%u0092 %u00c5%u0093 %u00c5%u0094 %u00c5%u0095 %u00c5%u0096 %u00c5%u0097 
%u00c5%u0098 %u00c5%u0099 %u00c5%u009a %u00c5%u009b %u00c5%u009c %u00c5%u009d 
%u00c5%u009e %u00c5%u009f %u00c5%u00a0 %u00c5%u00a1 %u00c5%u00a2 %u00c5%u00a3 
%u00c5%u00a4 %u00c5%u00a5 %u00c5%u00a6 %u00c5%u00a7 %u00c5%u00a8 %u00c5%u00a9 
%u00c5%u00aa %u00c5%u00ab %u00c5%u00ac %u00c5%u00ad %u00c5%u00ae %u00c5%u00af 
%u00c5%u00b0 %u00c5%u00b1 %u00c5%u00b2 %u00c5%u00b3 %u00c5%u00b4 %u00c5%u00b5 
%u00c5%u00b6 %u00c5%u00b7 %u00c5%u00b8 %u00c5%u00b9 %u00c5%u00ba %u00c5%u00bb 
%u00c5%u00bc %u00c5%u00bd %u00c5%u00be %u00c5%u00bf"
++   },
++   {
++      "input" : "<script >",
++      "name" : "utf8toUnicode",
++      "type" : "tfn",
++      "ret" : 1,
++      "output" : "%uff1cscript %uff1e"
+    }
+ ]
diff -Nru modsecurity-3.0.14/debian/patches/series 
modsecurity-3.0.14/debian/patches/series
--- modsecurity-3.0.14/debian/patches/series    2026-04-30 17:23:57.000000000 
+0200
+++ modsecurity-3.0.14/debian/patches/series    2026-06-30 21:01:17.000000000 
+0200
@@ -2,3 +2,5 @@
 ftbfs_1034760.patch
 fix-CVE-2026-30923.patch
 fix-CVE-2026-42268.patch
+fix-CVE-2026-52747.patch
+fix-CVE-2026-52761.patch

Reply via email to