thrift: fix CVE-2026-48145

Improper Validation of Certificate with Host Mismatch vulnerability in
Apache Thrift C++ bindings. This issue affects Apache Thrift: before
0.24.0.

Backport patch to fix CVE-2026-48145.

Reference:
[https://nvd.nist.gov/vuln/detail/cve-2026-48145]

Upstream Patch:
[https://github.com/apache/thrift/commit/c1457c69fbd49c6d554dafe91f1004049537322b]

Signed-off-by: Abhishek Bachiphale <Abhishek.Bachiphale@windriver.com>
Signed-off-by: Anuj Mittal <anuj.mittal@oss.qualcomm.com>
This commit is contained in:
Abhishek Bachiphale
2026-09-15 10:13:28 +05:30
committed by Anuj Mittal
parent 2c673e4a4f
commit f015b96ad0
2 changed files with 138 additions and 0 deletions
@@ -0,0 +1,137 @@
From c1457c69fbd49c6d554dafe91f1004049537322b Mon Sep 17 00:00:00 2001
From: Jens Geyer <jensg@apache.org>
Date: Thu, 21 May 2026 00:16:49 +0200
Subject: [PATCH] Enforce RFC 6125 wildcard placement in TSSLSocket hostname
matching Client: cpp
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Wildcards in certificate names must appear only in the leftmost
label per RFC 6125 §6.4.3. Add the check to matchName() and
cover it with a dedicated Boost.Test suite.
CVE: CVE-2026-48145
Upstream-Status: Backport [https://github.com/apache/thrift/commit/c1457c69fbd49c6d554dafe91f1004049537322b]
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Abhishek Bachiphale <Abhishek.Bachiphale@windriver.com>
---
lib/cpp/src/thrift/transport/TSSLSocket.cpp | 6 ++
lib/cpp/test/Makefile.am | 10 ++++
lib/cpp/test/TSSLSocketMatchNameTest.cpp | 61 +++++++++++++++++++++
3 files changed, 77 insertions(+)
create mode 100644 lib/cpp/test/TSSLSocketMatchNameTest.cpp
diff --git a/lib/cpp/src/thrift/transport/TSSLSocket.cpp b/lib/cpp/src/thrift/transport/TSSLSocket.cpp
index db426c85ebe..f97962ea5b7 100644
--- a/lib/cpp/src/thrift/transport/TSSLSocket.cpp
+++ b/lib/cpp/src/thrift/transport/TSSLSocket.cpp
@@ -1215,6 +1215,12 @@ Decision DefaultClientAccessManager::verify(const sockaddr_storage& sa,
* @return True, if "host" matches "pattern". False otherwise.
*/
bool matchName(const char* host, const char* pattern, int size) {
+ // RFC 6125 §6.4.3: wildcard must not appear outside the leftmost label.
+ bool past_first_dot = false;
+ for (int k = 0; k < size; k++) {
+ if (pattern[k] == '.') { past_first_dot = true; continue; }
+ if (pattern[k] == '*' && past_first_dot) return false;
+ }
bool match = false;
int i = 0, j = 0;
while (i < size && host[j] != '\0') {
diff --git a/lib/cpp/test/Makefile.am b/lib/cpp/test/Makefile.am
index 7c4153b49e4..234dd0b9964 100644
--- a/lib/cpp/test/Makefile.am
+++ b/lib/cpp/test/Makefile.am
@@ -108,6 +108,7 @@ check_PROGRAMS = \
TFileTransportTest \
link_test \
OpenSSLManualInitTest \
+ TSSLSocketMatchNameTest \
EnumTest \
RenderedDoubleConstantsTest \
AnnotationTest
@@ -413,6 +414,15 @@ OpenSSLManualInitTest_LDADD = \
$(OPENSSL_LDFLAGS) \
$(OPENSSL_LIBS)
+TSSLSocketMatchNameTest_SOURCES = \
+ TSSLSocketMatchNameTest.cpp
+
+TSSLSocketMatchNameTest_LDADD = \
+ $(top_builddir)/lib/cpp/libthrift.la \
+ $(BOOST_TEST_LDADD) \
+ $(OPENSSL_LDFLAGS) \
+ $(OPENSSL_LIBS)
+
#
# Common thrift code generation rules
#
diff --git a/lib/cpp/test/TSSLSocketMatchNameTest.cpp b/lib/cpp/test/TSSLSocketMatchNameTest.cpp
new file mode 100644
index 00000000000..dabfa59b9f8
--- /dev/null
+++ b/lib/cpp/test/TSSLSocketMatchNameTest.cpp
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); 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
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#define BOOST_TEST_MODULE TSSLSocketMatchNameTest
+#include <boost/test/unit_test.hpp>
+#include <thrift/transport/TSSLSocket.h>
+
+using apache::thrift::transport::AccessManager;
+using apache::thrift::transport::DefaultClientAccessManager;
+
+BOOST_AUTO_TEST_SUITE(TSSLSocketMatchNameTest)
+
+// Helper: ALLOW means match, SKIP means no match.
+static bool allows(const std::string& host, const std::string& pattern) {
+ DefaultClientAccessManager mgr;
+ return mgr.verify(host, pattern.c_str(), static_cast<int>(pattern.size()))
+ == AccessManager::ALLOW;
+}
+
+BOOST_AUTO_TEST_CASE(standard_wildcard_matches) {
+ BOOST_CHECK(allows("foo.example.com", "*.example.com"));
+ BOOST_CHECK(allows("FOO.EXAMPLE.COM", "*.example.com")); // case-insensitive
+ BOOST_CHECK(allows("a.b.c.example.com", "*.b.c.example.com")); // leftmost wildcard
+}
+
+BOOST_AUTO_TEST_CASE(exact_match) {
+ BOOST_CHECK(allows("example.com", "example.com"));
+ BOOST_CHECK(allows("foo.example.com", "foo.example.com"));
+}
+
+BOOST_AUTO_TEST_CASE(wildcard_must_not_span_labels) {
+ BOOST_CHECK(!allows("foo.bar.example.com", "*.example.com"));
+}
+
+BOOST_AUTO_TEST_CASE(wildcard_must_be_in_leftmost_label) {
+ // RFC 6125 §6.4.3: wildcard must not appear outside the leftmost label.
+ BOOST_CHECK(!allows("example.foo.com", "example.*.com"));
+ BOOST_CHECK(!allows("a.evil.com", "a.ev*.com"));
+}
+
+BOOST_AUTO_TEST_CASE(no_suffix_bypass) {
+ BOOST_CHECK(!allows("evil.com.attacker.com", "evil.com"));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
@@ -24,6 +24,7 @@ SRC_URI = "https://downloads.apache.org/${BPN}/${PV}/${BP}.tar.gz \
file://CVE-2026-55970.patch \
file://CVE-2026-48586-01.patch \
file://CVE-2026-48586-02.patch \
file://CVE-2026-48145.patch \
"
SRC_URI[sha256sum] = "794a0e455787960d9f27ab92c38e34da27e8deeda7a5db0e59dc64a00df8a1e5"