diff --git a/meta/recipes-support/curl/curl/CVE-2026-8932.patch b/meta/recipes-support/curl/curl/CVE-2026-8932.patch
new file mode 100644
index 0000000000..0b539c54ab
--- /dev/null
+++ b/meta/recipes-support/curl/curl/CVE-2026-8932.patch
@@ -0,0 +1,427 @@
+From c25faf128bba57a64da636f126773b858b35bc27 Mon Sep 17 00:00:00 2001
+From: Joshua Rogers <MegaManSec@users.noreply.github.com>
+Date: Tue, 19 May 2026 11:47:50 +0200
+Subject: [PATCH] tls: fix incomplete mTLS config in conn reuse and session
+ cache
+
+cert_type, key, key_type, key_passwd and key_blob lived in
+ssl_config_data but not in ssl_primary_config, so they were invisible to
+match_ssl_primary_config() and to the TLS session cache peer key.
+
+Two easy handles sharing a connection pool could reuse each other's
+authenticated connections when they differed only on SSLKEY, SSLKEYTYPE,
+KEYPASSWD, SSLCERTTYPE or SSLKEYBLOB. The second handle would silently
+inherit the first handle's authenticated identity.
+
+Promote all five fields into ssl_primary_config so the conn-reuse
+predicate and session cache key cover the complete client credential
+set. Also replace the fixed ":CCERT" session cache marker with the
+actual clientcert path so sessions are not shared across different
+client certificates.
+
+Verified by test 3303 and 3304
+
+Reported-By: Joshua Rogers (AISLE Research)
+Closes #21667
+
+CVE: CVE-2026-8932
+Upstream-Status: Backport [https://github.com/curl/curl/commit/7541ae569d82fb308a5e2d94916027da4fa3ba3e]
+
+Backport Changes:
+- curl 8.7.1 keeps the session cache in vtls.c and stores backend key
+  properties outside ssl_primary_config. Duplicate those pointers into
+  the primary configuration so matching and cloning cover reuse.
+- Keep the old backend members as aliases, so omit backend-only access
+  moves in ldap.c, vssh, and the TLS backend files.
+- Adapt unit3303 to the curl 8.7.1 harness and allocation helpers.
+  Include memdebug.h last so cleanup uses the debug allocator's free()
+  hook. Fold unit3304's case-insensitive cert_type and key_type checks
+  into it.
+- Extend unit3303 with key_blob deep-copy, connection reuse, and TLS
+  session cache matching checks.
+- Omit vtls_scache.c, vtls_scache.h, and unit3304 because their peer
+  key API does not exist in curl 8.7.1. The vtls.c cache uses the
+  updated clone and match functions exercised by unit3303.
+
+(cherry picked from commit 7541ae569d82fb308a5e2d94916027da4fa3ba3e)
+Signed-off-by: Devansh Patel <devanshp@cisco.com>
+---
+ lib/urldata.h           |   5 +
+ lib/vtls/vtls.c         |  25 +++++
+ tests/data/Makefile.inc |   3 +-
+ tests/data/test3303     |  23 +++++
+ tests/unit/Makefile.inc |   4 +-
+ tests/unit/unit3303.c   | 210 ++++++++++++++++++++++++++++++++++++++++
+ 6 files changed, 268 insertions(+), 2 deletions(-)
+ create mode 100644 tests/data/test3303
+ create mode 100644 tests/unit/unit3303.c
+
+diff --git a/lib/urldata.h b/lib/urldata.h
+index d2d9424197..9015515e17 100644
+--- a/lib/urldata.h
++++ b/lib/urldata.h
+@@ -286,6 +286,11 @@ struct ssl_primary_config {
+   char *CAfile;          /* certificate to verify peer against */
+   char *issuercert;      /* optional issuer certificate filename */
+   char *clientcert;
++  char *cert_type;       /* format for certificate (default: PEM) */
++  char *key;             /* private key file name */
++  struct curl_blob *key_blob;
++  char *key_type;        /* format for private key (default: PEM) */
++  char *key_passwd;      /* plain text private key password */
+   char *cipher_list;     /* list of ciphers to use */
+   char *cipher_list13;   /* list of TLS 1.3 cipher suites to use */
+   char *pinned_key;
+diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c
+index d13a3cb1b7..c89e8abcc6 100644
+--- a/lib/vtls/vtls.c
++++ b/lib/vtls/vtls.c
+@@ -187,10 +187,15 @@ match_ssl_primary_config(struct Curl_easy *data,
+      blobcmp(c1->cert_blob, c2->cert_blob) &&
+      blobcmp(c1->ca_info_blob, c2->ca_info_blob) &&
+      blobcmp(c1->issuercert_blob, c2->issuercert_blob) &&
++     blobcmp(c1->key_blob, c2->key_blob) &&
+      Curl_safecmp(c1->CApath, c2->CApath) &&
+      Curl_safecmp(c1->CAfile, c2->CAfile) &&
+      Curl_safecmp(c1->issuercert, c2->issuercert) &&
+      Curl_safecmp(c1->clientcert, c2->clientcert) &&
++     curl_strequal(c1->cert_type, c2->cert_type) &&
++     Curl_safecmp(c1->key, c2->key) &&
++     curl_strequal(c1->key_type, c2->key_type) &&
++     !Curl_timestrcmp(c1->key_passwd, c2->key_passwd) &&
+ #ifdef USE_TLS_SRP
+      !Curl_timestrcmp(c1->username, c2->username) &&
+      !Curl_timestrcmp(c1->password, c2->password) &&
+@@ -234,10 +239,15 @@ static bool clone_ssl_primary_config(struct ssl_primary_config *source,
+   CLONE_BLOB(cert_blob);
+   CLONE_BLOB(ca_info_blob);
+   CLONE_BLOB(issuercert_blob);
++  CLONE_BLOB(key_blob);
+   CLONE_STRING(CApath);
+   CLONE_STRING(CAfile);
+   CLONE_STRING(issuercert);
+   CLONE_STRING(clientcert);
++  CLONE_STRING(cert_type);
++  CLONE_STRING(key);
++  CLONE_STRING(key_type);
++  CLONE_STRING(key_passwd);
+   CLONE_STRING(cipher_list);
+   CLONE_STRING(cipher_list13);
+   CLONE_STRING(pinned_key);
+@@ -257,12 +267,17 @@ static void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc)
+   Curl_safefree(sslc->CAfile);
+   Curl_safefree(sslc->issuercert);
+   Curl_safefree(sslc->clientcert);
++  Curl_safefree(sslc->cert_type);
++  Curl_safefree(sslc->key);
++  Curl_safefree(sslc->key_type);
++  Curl_safefree(sslc->key_passwd);
+   Curl_safefree(sslc->cipher_list);
+   Curl_safefree(sslc->cipher_list13);
+   Curl_safefree(sslc->pinned_key);
+   Curl_safefree(sslc->cert_blob);
+   Curl_safefree(sslc->ca_info_blob);
+   Curl_safefree(sslc->issuercert_blob);
++  Curl_safefree(sslc->key_blob);
+   Curl_safefree(sslc->curves);
+   Curl_safefree(sslc->CRLfile);
+ #ifdef USE_TLS_SRP
+@@ -297,6 +312,11 @@ CURLcode Curl_ssl_easy_config_complete(struct Curl_easy *data)
+   data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD];
+   data->set.ssl.primary.clientcert = data->set.str[STRING_CERT];
+   data->set.ssl.key_blob = data->set.blobs[BLOB_KEY];
++  data->set.ssl.primary.cert_type = data->set.ssl.cert_type;
++  data->set.ssl.primary.key = data->set.ssl.key;
++  data->set.ssl.primary.key_type = data->set.ssl.key_type;
++  data->set.ssl.primary.key_passwd = data->set.ssl.key_passwd;
++  data->set.ssl.primary.key_blob = data->set.ssl.key_blob;
+ 
+ #ifndef CURL_DISABLE_PROXY
+   data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY];
+@@ -322,6 +342,11 @@ CURLcode Curl_ssl_easy_config_complete(struct Curl_easy *data)
+   data->set.proxy_ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY];
+   data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY];
+   data->set.proxy_ssl.key_blob = data->set.blobs[BLOB_KEY_PROXY];
++  data->set.proxy_ssl.primary.cert_type = data->set.proxy_ssl.cert_type;
++  data->set.proxy_ssl.primary.key = data->set.proxy_ssl.key;
++  data->set.proxy_ssl.primary.key_type = data->set.proxy_ssl.key_type;
++  data->set.proxy_ssl.primary.key_passwd = data->set.proxy_ssl.key_passwd;
++  data->set.proxy_ssl.primary.key_blob = data->set.proxy_ssl.key_blob;
+ #ifdef USE_TLS_SRP
+   data->set.proxy_ssl.primary.username =
+     data->set.str[STRING_TLSAUTH_USERNAME_PROXY];
+diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
+index f420a8a4f5..27b1b52a10 100644
+--- a/tests/data/Makefile.inc
++++ b/tests/data/Makefile.inc
+@@ -264,4 +264,5 @@ test3024 test3025 test3026 test3027 test3028 test3029 test3030 \
+ \
+ test3100 test3101 test3102 test3103 \
+ test3200 \
+-test3201 test3202
++test3201 test3202 \
++test3303
+diff --git a/tests/data/test3303 b/tests/data/test3303
+new file mode 100644
+index 0000000000..9b52bcb817
+--- /dev/null
++++ b/tests/data/test3303
+@@ -0,0 +1,23 @@
++<?xml version="1.0" encoding="US-ASCII"?>
++<testcase>
++<info>
++<keywords>
++unittest
++TLS
++mTLS
++</keywords>
++</info>
++
++# Client-side
++<client>
++<server>
++none
++</server>
++<features>
++unittest
++</features>
++<name>
++conn-reuse match distinguishes mTLS key, cert_type, key_type and key_passwd fields
++</name>
++</client>
++</testcase>
+diff --git a/tests/unit/Makefile.inc b/tests/unit/Makefile.inc
+index 1926b49b3a..afbe29d2b7 100644
+--- a/tests/unit/Makefile.inc
++++ b/tests/unit/Makefile.inc
+@@ -39,7 +39,7 @@ UNITPROGS = unit1300          unit1302 unit1303 unit1304 unit1305 unit1307 \
+  unit1650 unit1651 unit1652 unit1653 unit1654 unit1655 unit1656 \
+  unit1660 unit1661 \
+  unit2600 unit2601 unit2602 unit2603 \
+- unit3200
++ unit3200 unit3303
+ 
+ unit1300_SOURCES = unit1300.c $(UNITFILES)
+ 
+@@ -134,3 +134,5 @@ unit2602_SOURCES = unit2602.c $(UNITFILES)
+ unit2603_SOURCES = unit2603.c $(UNITFILES)
+ 
+ unit3200_SOURCES = unit3200.c $(UNITFILES)
++
++unit3303_SOURCES = unit3303.c $(UNITFILES)
+diff --git a/tests/unit/unit3303.c b/tests/unit/unit3303.c
+new file mode 100644
+index 0000000000..f9928b638a
+--- /dev/null
++++ b/tests/unit/unit3303.c
+@@ -0,0 +1,210 @@
++/***************************************************************************
++ *                                  _   _ ____  _
++ *  Project                     ___| | | |  _ \| |
++ *                             / __| | | | |_) | |
++ *                            | (__| |_| |  _ <| |___
++ *                             \___|\___/|_| \_\_____|
++ *
++ * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
++ *
++ * This software is licensed as described in the file COPYING, which
++ * you should have received as part of this distribution. The terms
++ * are also available at https://curl.se/docs/copyright.html.
++ *
++ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
++ * copies of the Software, and permit persons to whom the Software is
++ * furnished to do so, under the terms of the COPYING file.
++ *
++ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
++ * KIND, either express or implied.
++ *
++ * SPDX-License-Identifier: curl
++ *
++ ***************************************************************************/
++#include "curlcheck.h"
++#include "cfilters.h"
++#include "http.h"
++#include "urldata.h"
++
++#ifdef USE_SSL
++#include "vtls/vtls.h"
++#include "vtls/vtls_int.h"
++#endif
++#include "memdebug.h" /* LAST include file */
++
++static CURLcode unit_setup(void)
++{
++  return curl_global_init(CURL_GLOBAL_ALL);
++}
++
++static void unit_stop(void)
++{
++  curl_global_cleanup();
++}
++
++UNITTEST_START
++#ifdef USE_SSL
++{
++  CURL *curl;
++  struct Curl_easy *data;
++  struct connectdata *conn;
++  struct Curl_cfilter cf;
++  struct ssl_connect_data sslctx;
++  struct ssl_primary_config *primary;
++  struct curl_blob key_blob;
++  struct curl_blob alt_key_blob;
++  struct curl_blob *saved_blob;
++  struct curl_blob *saved_conn_blob;
++  void *sessionid;
++  size_t idsize = 0;
++  bool added = FALSE;
++  char fake_session;
++  char *saved;
++  static char alt_passwd[] = "wrong";
++  static char alt_key[] = "other.key";
++  static char alt_ktype[] = "DER";
++  static char alt_ctype[] = "P12";
++  static char lc_ctype[] = "pem";
++  static char lc_ktype[] = "pem";
++
++  curl = curl_easy_init();
++  abort_unless(curl, "curl_easy_init failed");
++  data = (struct Curl_easy *)curl;
++
++  key_blob.data = (void *)"first private key";
++  key_blob.len = sizeof("first private key") - 1;
++  key_blob.flags = CURL_BLOB_COPY;
++  alt_key_blob.data = (void *)"second private key";
++  alt_key_blob.len = sizeof("second private key") - 1;
++  alt_key_blob.flags = CURL_BLOB_NOCOPY;
++
++  curl_easy_setopt(curl, CURLOPT_SSLCERT, "client.pem");
++  curl_easy_setopt(curl, CURLOPT_SSLKEY, "client.key");
++  curl_easy_setopt(curl, CURLOPT_SSLKEY_BLOB, &key_blob);
++  curl_easy_setopt(curl, CURLOPT_KEYPASSWD, "secret");
++  curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM");
++  curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM");
++
++  abort_unless(!Curl_ssl_easy_config_complete(data),
++               "Curl_ssl_easy_config_complete failed");
++
++  conn = calloc(1, sizeof(*conn));
++  abort_unless(conn, "connection allocation failed");
++  abort_unless(!Curl_ssl_conn_config_init(data, conn),
++               "Curl_ssl_conn_config_init failed");
++
++  fail_unless(Curl_ssl_conn_config_match(data, conn, FALSE),
++              "identical mTLS config should match");
++
++  primary = &data->set.ssl.primary;
++
++  fail_unless(conn->ssl_config.key_blob &&
++              conn->ssl_config.key_blob != primary->key_blob &&
++              conn->ssl_config.key_blob->len == primary->key_blob->len &&
++              !memcmp(conn->ssl_config.key_blob->data,
++                      primary->key_blob->data, primary->key_blob->len),
++              "key_blob must be cloned into the connection config");
++
++  saved_blob = primary->key_blob;
++  primary->key_blob = &alt_key_blob;
++  fail_unless(!Curl_ssl_conn_config_match(data, conn, FALSE),
++              "different key_blob must not reuse conn");
++  primary->key_blob = saved_blob;
++
++  saved = primary->key_passwd;
++  primary->key_passwd = alt_passwd;
++  fail_unless(!Curl_ssl_conn_config_match((struct Curl_easy *)curl, conn,
++                                          FALSE),
++              "different key_passwd must not reuse conn");
++  primary->key_passwd = saved;
++
++  saved = primary->key;
++  primary->key = alt_key;
++  fail_unless(!Curl_ssl_conn_config_match((struct Curl_easy *)curl, conn,
++                                          FALSE),
++              "different key must not reuse conn");
++  primary->key = saved;
++
++  saved = primary->key_type;
++  primary->key_type = alt_ktype;
++  fail_unless(!Curl_ssl_conn_config_match((struct Curl_easy *)curl, conn,
++                                          FALSE),
++              "different key_type must not reuse conn");
++  primary->key_type = saved;
++
++  saved = primary->cert_type;
++  primary->cert_type = alt_ctype;
++  fail_unless(!Curl_ssl_conn_config_match((struct Curl_easy *)curl, conn,
++                                          FALSE),
++              "different cert_type must not reuse conn");
++  primary->cert_type = saved;
++
++  primary->cert_type = lc_ctype;
++  fail_unless(Curl_ssl_conn_config_match((struct Curl_easy *)curl, conn,
++                                         FALSE),
++              "cert_type comparison must be case-insensitive");
++  primary->cert_type = saved;
++
++  primary->key_type = lc_ktype;
++  fail_unless(Curl_ssl_conn_config_match((struct Curl_easy *)curl, conn,
++                                         FALSE),
++              "key_type comparison must be case-insensitive");
++  primary->key_type = saved;
++
++  fail_unless(Curl_ssl_conn_config_match((struct Curl_easy *)curl, conn,
++                                         FALSE),
++              "restored mTLS config should match");
++
++  memset(&cf, 0, sizeof(cf));
++  memset(&sslctx, 0, sizeof(sslctx));
++  conn->handler = &Curl_handler_https;
++  sslctx.peer.hostname = "example.com";
++  sslctx.port = 443;
++  cf.cft = &Curl_cft_ssl;
++  cf.ctx = &sslctx;
++  cf.conn = conn;
++
++  abort_unless(!Curl_ssl_initsessions(data, 1),
++               "Curl_ssl_initsessions failed");
++  abort_unless(!Curl_ssl_addsessionid(&cf, data, &fake_session, 1,
++                                      &added),
++               "Curl_ssl_addsessionid failed");
++  fail_unless(added, "session was not added to the cache");
++  fail_unless(data->state.session[0].ssl_config.key_blob &&
++              data->state.session[0].ssl_config.key_blob !=
++                conn->ssl_config.key_blob,
++              "key_blob must be cloned into the session cache");
++
++  sessionid = NULL;
++  fail_unless(!Curl_ssl_getsessionid(&cf, data, &sessionid, &idsize) &&
++              sessionid == &fake_session,
++              "identical key_blob should reuse the TLS session");
++
++  saved_conn_blob = conn->ssl_config.key_blob;
++  conn->ssl_config.key_blob = &alt_key_blob;
++  sessionid = NULL;
++  fail_unless(Curl_ssl_getsessionid(&cf, data, &sessionid, &idsize) &&
++              !sessionid,
++              "different key_blob must not reuse the TLS session");
++  conn->ssl_config.key_blob = saved_conn_blob;
++
++  sessionid = NULL;
++  fail_unless(!Curl_ssl_getsessionid(&cf, data, &sessionid, &idsize) &&
++              sessionid == &fake_session,
++              "restored key_blob should reuse the TLS session");
++
++  Curl_ssl_conn_config_cleanup(conn);
++  conn->ssl_config = data->state.session[0].ssl_config;
++  memset(&data->state.session[0].ssl_config, 0,
++         sizeof(data->state.session[0].ssl_config));
++  free(data->state.session[0].name);
++  data->state.session[0].name = NULL;
++  free(data->state.session[0].conn_to_host);
++  data->state.session[0].conn_to_host = NULL;
++  data->state.session[0].sessionid = NULL;
++  Curl_ssl_conn_config_cleanup(conn);
++  free(conn);
++  curl_easy_cleanup(curl);
++}
++#endif /* USE_SSL */
++UNITTEST_STOP
diff --git a/meta/recipes-support/curl/curl_8.7.1.bb b/meta/recipes-support/curl/curl_8.7.1.bb
index 9f261955ff..6f9a814457 100644
--- a/meta/recipes-support/curl/curl_8.7.1.bb
+++ b/meta/recipes-support/curl/curl_8.7.1.bb
@@ -45,6 +45,7 @@ SRC_URI = " \
     file://CVE-2026-8286.patch \
     file://CVE-2026-8927-dependent.patch \
     file://CVE-2026-8927.patch \
+    file://CVE-2026-8932.patch \
 "
 
 SRC_URI:append:class-nativesdk = " \
