* [Buildroot] [PATCH 1/1] package/drogon: fix CVE-2023-26137 and CVE-2023-26138
@ 2026-10-27 15:18 Dario Binacchi
2026-10-27 17:22 ` Thomas Petazzoni via buildroot
0 siblings, 1 reply; 2+ messages in thread
From: Dario Binacchi @ 2026-10-27 15:18 UTC (permalink / raw)
To: buildroot; +Cc: Dario Binacchi
All drogon releases, including 1.9.14, are affected by two CRLF
injection vulnerabilities, which upstream has fixed but not released
yet.
- CVE-2023-26137: HTTP response splitting when untrusted input is used
to build header values in addHeader() and addCookie().
https://www.cve.org/CVERecord?id=CVE-2023-26137
- CVE-2023-26138: CRLF injection when untrusted input is used to set
request headers in addHeader().
https://www.cve.org/CVERecord?id=CVE-2023-26138
Backport the upstream fix, which rejects CR and LF characters in header
and cookie values, both in responses and in requests sent by
HttpClient.
Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
---
...01-Fix-CVE-2023-26137-CVE-2023-26138.patch | 357 ++++++++++++++++++
package/drogon/drogon.mk | 3 +
2 files changed, 360 insertions(+)
create mode 100644 package/drogon/0001-Fix-CVE-2023-26137-CVE-2023-26138.patch
diff --git a/package/drogon/0001-Fix-CVE-2023-26137-CVE-2023-26138.patch b/package/drogon/0001-Fix-CVE-2023-26137-CVE-2023-26138.patch
new file mode 100644
index 000000000000..0b8e93df8731
--- /dev/null
+++ b/package/drogon/0001-Fix-CVE-2023-26137-CVE-2023-26138.patch
@@ -0,0 +1,357 @@
+From 3c068bd888c332b9a155ba45a102d5faba643211 Mon Sep 17 00:00:00 2001
+From: Dario Binacchi <45538935+passgat@users.noreply.github.com>
+Date: Tue, 27 Oct 2026 07:49:45 +0100
+Subject: [PATCH] Fix CVE 2023 26137 CVE 2023 26138 (#2630)
+
+CVE: CVE-2023-26137
+CVE: CVE-2023-26138
+Upstream: https://github.com/drogonframework/drogon/commit/3c068bd888c332b9a155ba45a102d5faba643211
+Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
+---
+ lib/inc/drogon/HttpRequest.h | 5 +++-
+ lib/inc/drogon/HttpResponse.h | 8 +++--
+ lib/src/HttpRequestImpl.h | 6 ++++
+ lib/src/HttpResponseImpl.h | 10 +++++++
+ lib/src/HttpUtils.cc | 41 +++++++++++++++++++++++++
+ lib/src/HttpUtils.h | 15 ++++++++++
+ lib/tests/CMakeLists.txt | 1 +
+ lib/tests/unittests/HttpHeaderTest.cc | 43 +++++++++++++++++++++++++++
+ lib/tests/unittests/HttpUtilsTest.cc | 41 +++++++++++++++++++++++++
+ 9 files changed, 167 insertions(+), 3 deletions(-)
+ create mode 100644 lib/tests/unittests/HttpUtilsTest.cc
+
+diff --git a/lib/inc/drogon/HttpRequest.h b/lib/inc/drogon/HttpRequest.h
+index 2ffd4fc4b9b1..e27a0023a22f 100644
+--- a/lib/inc/drogon/HttpRequest.h
++++ b/lib/inc/drogon/HttpRequest.h
+@@ -148,6 +148,8 @@ class DROGON_EXPORT HttpRequest
+ * @param field The field parameter is transformed to lower case before
+ * storing.
+ * @param value The value of the header.
++ * @note The header is ignored if the field or the value contains CR or LF
++ * characters, to prevent CRLF injection.
+ */
+ virtual void addHeader(std::string field, const std::string &value) = 0;
+ virtual void addHeader(std::string field, std::string &&value) = 0;
+@@ -468,7 +470,8 @@ class DROGON_EXPORT HttpRequest
+ /// For example, "content-type: text/plain\r\n"
+ virtual void setCustomContentTypeString(const std::string &type) = 0;
+
+- /// Add a cookie
++ /// Add a cookie. The cookie is ignored if its key or value contains CR or
++ /// LF characters.
+ virtual void addCookie(std::string key, std::string value) = 0;
+
+ /**
+diff --git a/lib/inc/drogon/HttpResponse.h b/lib/inc/drogon/HttpResponse.h
+index f949bd0b033f..e0b1c1678b52 100644
+--- a/lib/inc/drogon/HttpResponse.h
++++ b/lib/inc/drogon/HttpResponse.h
+@@ -264,15 +264,19 @@ class DROGON_EXPORT HttpResponse
+ * @param field The field parameter is transformed to lower case before
+ * storing.
+ * @param value The value of the header.
++ * @note The header is ignored if the field or the value contains CR or LF
++ * characters, to prevent HTTP response splitting.
+ */
+ virtual void addHeader(std::string field, const std::string &value) = 0;
+ virtual void addHeader(std::string field, std::string &&value) = 0;
+
+- /// Add a cookie
++ /// Add a cookie. The cookie is ignored if its key or value contains CR or
++ /// LF characters.
+ virtual void addCookie(const std::string &key,
+ const std::string &value) = 0;
+
+- /// Add a cookie
++ /// Add a cookie. The cookie is ignored if its key, value, domain or path
++ /// contains CR or LF characters.
+ virtual void addCookie(const Cookie &cookie) = 0;
+ virtual void addCookie(Cookie &&cookie) = 0;
+
+diff --git a/lib/src/HttpRequestImpl.h b/lib/src/HttpRequestImpl.h
+index 1b397b7f12fc..39fb868739d4 100644
+--- a/lib/src/HttpRequestImpl.h
++++ b/lib/src/HttpRequestImpl.h
+@@ -462,6 +462,8 @@ class HttpRequestImpl : public HttpRequest
+
+ void addHeader(std::string field, const std::string &value) override
+ {
++ if (!isValidHeader(field, value))
++ return;
+ transform(field.begin(),
+ field.end(),
+ field.begin(),
+@@ -471,6 +473,8 @@ class HttpRequestImpl : public HttpRequest
+
+ void addHeader(std::string field, std::string &&value) override
+ {
++ if (!isValidHeader(field, value))
++ return;
+ transform(field.begin(),
+ field.end(),
+ field.begin(),
+@@ -480,6 +484,8 @@ class HttpRequestImpl : public HttpRequest
+
+ void addCookie(std::string key, std::string value) override
+ {
++ if (!isValidCookie(key, value))
++ return;
+ cookies_[std::move(key)] = std::move(value);
+ }
+
+diff --git a/lib/src/HttpResponseImpl.h b/lib/src/HttpResponseImpl.h
+index beebe7fa8db2..f28d43b338b9 100644
+--- a/lib/src/HttpResponseImpl.h
++++ b/lib/src/HttpResponseImpl.h
+@@ -193,6 +193,8 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse
+
+ void addHeader(std::string field, const std::string &value) override
+ {
++ if (!isValidHeader(field, value))
++ return;
+ fullHeaderString_.reset();
+ transform(field.begin(),
+ field.end(),
+@@ -203,6 +205,8 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse
+
+ void addHeader(std::string field, std::string &&value) override
+ {
++ if (!isValidHeader(field, value))
++ return;
+ fullHeaderString_.reset();
+ transform(field.begin(),
+ field.end(),
+@@ -215,16 +219,22 @@ class DROGON_EXPORT HttpResponseImpl : public HttpResponse
+
+ void addCookie(const std::string &key, const std::string &value) override
+ {
++ if (!isValidCookie(key, value))
++ return;
+ cookies_[key] = Cookie(key, value);
+ }
+
+ void addCookie(const Cookie &cookie) override
+ {
++ if (!isValidCookie(cookie))
++ return;
+ cookies_[cookie.key()] = cookie;
+ }
+
+ void addCookie(Cookie &&cookie) override
+ {
++ if (!isValidCookie(cookie))
++ return;
+ cookies_[cookie.key()] = std::move(cookie);
+ }
+
+diff --git a/lib/src/HttpUtils.cc b/lib/src/HttpUtils.cc
+index 5cfcbb7d2566..cd33975c1df1 100644
+--- a/lib/src/HttpUtils.cc
++++ b/lib/src/HttpUtils.cc
+@@ -14,6 +14,7 @@
+
+ #include "HttpUtils.h"
+ #include <drogon/utils/Utilities.h>
++#include <drogon/Cookie.h>
+ #include <trantor/utils/Logger.h>
+ #include <map>
+ #include <unordered_map>
+@@ -740,4 +741,44 @@ const std::vector<std::string_view> &getFileExtensions(ContentType contentType)
+ return it->second;
+ }
+
++static bool containsCRLF(std::string_view str)
++{
++ return str.find_first_of("\r\n") != std::string_view::npos;
++}
++
++bool isValidHeader(std::string_view field, std::string_view value)
++{
++ if (containsCRLF(field) || containsCRLF(value))
++ {
++ LOG_ERROR << "Header '" << field
++ << "' contains CR or LF characters, ignored";
++ return false;
++ }
++ return true;
++}
++
++bool isValidCookie(std::string_view key, std::string_view value)
++{
++ if (containsCRLF(key) || containsCRLF(value))
++ {
++ LOG_ERROR << "Cookie '" << key
++ << "' contains CR or LF characters, ignored";
++ return false;
++ }
++ return true;
++}
++
++bool isValidCookie(const Cookie &cookie)
++{
++ if (!isValidCookie(cookie.key(), cookie.value()))
++ return false;
++ if (containsCRLF(cookie.domain()) || containsCRLF(cookie.path()))
++ {
++ LOG_ERROR << "Cookie '" << cookie.key()
++ << "' contains CR or LF characters, ignored";
++ return false;
++ }
++ return true;
++}
++
+ } // namespace drogon
+diff --git a/lib/src/HttpUtils.h b/lib/src/HttpUtils.h
+index 16a6c21732d2..53f2c13cff53 100644
+--- a/lib/src/HttpUtils.h
++++ b/lib/src/HttpUtils.h
+@@ -21,6 +21,8 @@
+
+ namespace drogon
+ {
++class Cookie;
++
+ const std::string_view &contentTypeToMime(ContentType contentType);
+ const std::string_view &statusCodeToString(int code);
+ ContentType getContentType(const std::string &fileName);
+@@ -43,6 +45,19 @@ inline std::string_view getFileExtension(const std::string &fileName)
+
+ const std::vector<std::string_view> &getFileExtensions(ContentType contentType);
+
++/// Return false (and log an error) if the header field or value contains a CR
++/// or LF character, which are not allowed in HTTP field names and values
++/// (RFC 9110, section 5.5).
++bool isValidHeader(std::string_view field, std::string_view value);
++
++/// Return false (and log an error) if the cookie key or value contains a CR or
++/// LF character.
++bool isValidCookie(std::string_view key, std::string_view value);
++
++/// Return false (and log an error) if the cookie key, value, domain or path
++/// contains a CR or LF character.
++bool isValidCookie(const Cookie &cookie);
++
+ inline const std::vector<std::string_view> &getFileExtensions(
+ const std::string_view &contentType)
+ {
+diff --git a/lib/tests/CMakeLists.txt b/lib/tests/CMakeLists.txt
+index 10f42ede1693..514e8692e74e 100644
+--- a/lib/tests/CMakeLists.txt
++++ b/lib/tests/CMakeLists.txt
+@@ -13,6 +13,7 @@ set(UNITTEST_SOURCES
+ unittests/ClassNameTest.cc
+ unittests/HttpDateTest.cc
+ unittests/HttpHeaderTest.cc
++ unittests/HttpUtilsTest.cc
+ unittests/HttpResponseSwapTest.cc
+ unittests/HttpClientTimeoutTest.cc
+ unittests/MD5Test.cc
+diff --git a/lib/tests/unittests/HttpHeaderTest.cc b/lib/tests/unittests/HttpHeaderTest.cc
+index d10c8887e5f1..940622989b07 100644
+--- a/lib/tests/unittests/HttpHeaderTest.cc
++++ b/lib/tests/unittests/HttpHeaderTest.cc
+@@ -16,6 +16,21 @@ DROGON_TEST(HttpHeaderRequest)
+ CHECK(req->getHeader("abc") == "");
+ }
+
++DROGON_TEST(HttpHeaderRequestCRLFInjection)
++{
++ auto req = HttpRequest::newHttpRequest();
++ req->addHeader("X-Test", "abc\r\nX-Injected: 1");
++ req->addHeader("X-Test\r\nX-Injected", "abc");
++ req->addHeader("X-Lf", std::string("abc\nX-Injected: 1"));
++ CHECK(req->getHeader("X-Test") == "");
++ CHECK(req->getHeader("X-Lf") == "");
++ CHECK(req->headers().empty());
++
++ req->addCookie("key", "value\r\nX-Injected: 1");
++ req->addCookie("key\nX-Injected: 1", "value");
++ CHECK(req->cookies().empty());
++}
++
+ DROGON_TEST(HttpHeaderResponse)
+ {
+ auto resp = std::dynamic_pointer_cast<HttpResponseImpl>(
+@@ -37,6 +52,34 @@ DROGON_TEST(HttpHeaderResponse)
+ CHECK(resp->getHeader("abc") == "");
+ }
+
++DROGON_TEST(HttpHeaderResponseCRLFInjection)
++{
++ auto resp = std::dynamic_pointer_cast<HttpResponseImpl>(
++ HttpResponse::newHttpResponse());
++ REQUIRE(resp != nullptr);
++ resp->addHeader("X-Test", "abc\r\nSet-Cookie: injected=1");
++ resp->addHeader("X-Test\r\nX-Injected", "abc");
++ resp->addHeader("X-Lf", std::string("abc\nX-Injected: 1"));
++ CHECK(resp->getHeader("X-Test") == "");
++ CHECK(resp->getHeader("X-Lf") == "");
++ CHECK(resp->headers().empty());
++
++ resp->addCookie("key", "value\r\nX-Injected: 1");
++ Cookie cookie("key", "value");
++ cookie.setPath("/\r\nX-Injected: 1");
++ resp->addCookie(cookie);
++ cookie.setPath("/");
++ cookie.setDomain("example.com\nX-Injected: 1");
++ resp->addCookie(std::move(cookie));
++ CHECK(resp->cookies().empty());
++
++ resp->makeHeaderString();
++ auto buffer = resp->renderToBuffer();
++ auto str = std::string{buffer->peek(), buffer->readableBytes()};
++ CHECK(str.find("injected") == std::string::npos);
++ CHECK(str.find("X-Injected") == std::string::npos);
++}
++
+ DROGON_TEST(ResponseSetCustomContentTypeString)
+ {
+ auto resp = HttpResponse::newHttpResponse();
+diff --git a/lib/tests/unittests/HttpUtilsTest.cc b/lib/tests/unittests/HttpUtilsTest.cc
+new file mode 100644
+index 000000000000..182b10000d61
+--- /dev/null
++++ b/lib/tests/unittests/HttpUtilsTest.cc
+@@ -0,0 +1,41 @@
++#include "../lib/src/HttpUtils.h"
++#include <drogon/Cookie.h>
++#include <drogon/drogon_test.h>
++using namespace drogon;
++
++DROGON_TEST(IsValidHeader)
++{
++ CHECK(isValidHeader("X-Test", "abc"));
++ CHECK(isValidHeader("X-Test", ""));
++ CHECK(isValidHeader("X-Test", "a: b; c=d"));
++ CHECK(!isValidHeader("X-Test", "abc\r\nX-Injected: 1"));
++ CHECK(!isValidHeader("X-Test", "abc\r"));
++ CHECK(!isValidHeader("X-Test", "abc\nX-Injected: 1"));
++ CHECK(!isValidHeader("X-Test\r\nX-Injected", "abc"));
++ CHECK(!isValidHeader("X-Test\n", "abc"));
++}
++
++DROGON_TEST(IsValidCookie)
++{
++ CHECK(isValidCookie("key", "value"));
++ CHECK(isValidCookie("key", ""));
++ CHECK(!isValidCookie("key", "value\r\nX-Injected: 1"));
++ CHECK(!isValidCookie("key", "value\n"));
++ CHECK(!isValidCookie("key\r", "value"));
++
++ Cookie cookie("key", "value");
++ cookie.setDomain("example.com");
++ cookie.setPath("/");
++ CHECK(isValidCookie(cookie));
++
++ cookie.setValue("value\r\nX-Injected: 1");
++ CHECK(!isValidCookie(cookie));
++
++ cookie.setValue("value");
++ cookie.setDomain("example.com\r\nX-Injected: 1");
++ CHECK(!isValidCookie(cookie));
++
++ cookie.setDomain("example.com");
++ cookie.setPath("/\nX-Injected: 1");
++ CHECK(!isValidCookie(cookie));
++}
diff --git a/package/drogon/drogon.mk b/package/drogon/drogon.mk
index 03cba45ceb34..7850d754dc6e 100644
--- a/package/drogon/drogon.mk
+++ b/package/drogon/drogon.mk
@@ -12,6 +12,9 @@ DROGON_LICENSE = MIT
DROGON_LICENSE_FILES = LICENSE
DROGON_INSTALL_STAGING = YES
+# 0001-Fix-CVE-2023-26137-CVE-2023-26138.patch
+DROGON_IGNORE_CVES += CVE-2023-26137 CVE-2023-26138
+
DROGON_DEPENDENCIES = jsoncpp util-linux zlib
HOST_DROGON_DEPENDENCIES = host-jsoncpp host-util-linux host-zlib
--
2.43.0
_______________________________________________
buildroot mailing list
buildroot@buildroot.org
https://lists.buildroot.org/mailman/listinfo/buildroot
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [Buildroot] [PATCH 1/1] package/drogon: fix CVE-2023-26137 and CVE-2023-26138
2026-10-27 15:18 [Buildroot] [PATCH 1/1] package/drogon: fix CVE-2023-26137 and CVE-2023-26138 Dario Binacchi
@ 2026-10-27 17:22 ` Thomas Petazzoni via buildroot
0 siblings, 0 replies; 2+ messages in thread
From: Thomas Petazzoni via buildroot @ 2026-10-27 17:22 UTC (permalink / raw)
To: Dario Binacchi; +Cc: buildroot
On Tue, Oct 27, 2026 at 04:18:09PM +0100, Dario Binacchi wrote:
> All drogon releases, including 1.9.14, are affected by two CRLF
> injection vulnerabilities, which upstream has fixed but not released
> yet.
>
> - CVE-2023-26137: HTTP response splitting when untrusted input is used
> to build header values in addHeader() and addCookie().
> https://www.cve.org/CVERecord?id=CVE-2023-26137
> - CVE-2023-26138: CRLF injection when untrusted input is used to set
> request headers in addHeader().
> https://www.cve.org/CVERecord?id=CVE-2023-26138
>
> Backport the upstream fix, which rejects CR and LF characters in header
> and cookie values, both in responses and in requests sent by
> HttpClient.
>
> Signed-off-by: Dario Binacchi <dario.binacchi@amarulasolutions.com>
Applied to master, thanks!
Best regards,
Thomas Petazzoni
--
Thomas Petazzoni, co-owner and CEO, Bootlin
Embedded Linux and Kernel engineering and training
https://bootlin.com
_______________________________________________
buildroot mailing list
buildroot@buildroot.org
https://lists.buildroot.org/mailman/listinfo/buildroot
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-10-27 17:22 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-27 15:18 [Buildroot] [PATCH 1/1] package/drogon: fix CVE-2023-26137 and CVE-2023-26138 Dario Binacchi
2026-10-27 17:22 ` Thomas Petazzoni via buildroot
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.