diff --git a/meta/recipes-support/curl/curl/CVE-2026-107929.patch b/meta/recipes-support/curl/curl/CVE-2026-107929.patch
new file mode 100644
index 0000000000..873b03fd5b
--- /dev/null
+++ b/meta/recipes-support/curl/curl/CVE-2026-107929.patch
@@ -0,0 +1,470 @@
+From d37d79df1e01066417aff0a9e6bc675edad3edba Mon Sep 17 00:00:00 2001
+From: Stefan Eissing <stefan@eissing.org>
+Date: Fri, 9 Oct 2026 09:51:12 +0200
+Subject: [PATCH] url: CURLOPT_INTERFACE fix connection reuse match
+
+Remember the full option string at the connection for use in reuse
+matching and cf-socket binding.
+
+Parse the string when set for syntax check, but remember the unparsed
+version and use that in connection matching.
+
+Parse that string again when the socket is set up.
+
+Closes #23326
+
+CVE: CVE-2026-107929
+Upstream-Status: Backport [https://github.com/curl/curl/commit/d37d79df1e01066417aff0a9e6bc675edad3edba]
+
+Backport Changes:
+- Use curl 8.19.0's data->set.str[], Curl_setstropt() and
+  Curl_safefree() instead of the newer string and free helpers.
+- Change the older setstropt_interface() parameters and its caller
+  to pass the easy handle; remove the obsolete output assertions.
+- Keep bindlocal()'s older nested SO_BINDTODEVICE test. Route its
+  success path through cleanup and keep two blank separators around
+  the new option parsing and binding checks.
+- Replace the older braced local-bind comparison and its split
+  comment ending with upstream's new matching expression.
+
+Signed-off-by: Darsh Kelaiya <dkelaiya@cisco.com>
+---
+ lib/cf-socket.c | 135 +++++++++++++++++++++++++++++++-----------------
+ lib/setopt.c    |  34 +++---------
+ lib/url.c       |  48 +++++++++--------
+ lib/urldata.h   |   6 +--
+ 4 files changed, 126 insertions(+), 97 deletions(-)
+
+diff --git a/lib/cf-socket.c b/lib/cf-socket.c
+index 2ebbe4d..f3978e2 100644
+--- a/lib/cf-socket.c
++++ b/lib/cf-socket.c
+@@ -464,11 +464,13 @@ int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
+  * len    [in]     - length of the input string.
+  * dev    [in/out] - address where a pointer to newly allocated memory
+  *                   holding the interface-or-host will be stored upon
+- *                   completion.
++ *                   completion or NULL if the caller is not interested.
+  * iface  [in/out] - address where a pointer to newly allocated memory
+- *                   holding the interface will be stored upon completion.
++ *                   holding the interface will be stored upon completion
++ *                   or NULL if the caller is not interested.
+  * host   [in/out] - address where a pointer to newly allocated memory
+- *                   holding the host will be stored upon completion.
++ *                   holding the host will be stored upon completion
++ *                   or NULL if the caller is not interested.
+  *
+  * Returns CURLE_OK on success.
+  */
+@@ -480,27 +482,36 @@ CURLcode Curl_parse_interface(const char *input,
+   static const char if_host_prefix[] = "ifhost!";
+   size_t len;
+ 
+-  DEBUGASSERT(dev);
+-  DEBUGASSERT(iface);
+-  DEBUGASSERT(host);
+-
+   len = strlen(input);
+   if(len > 512)
+     return CURLE_BAD_FUNCTION_ARGUMENT;
+ 
++  if(dev)
++    *dev = NULL;
++  if(iface)
++    *iface = NULL;
++  if(host)
++    *host = NULL;
++
+   if(!strncmp(if_prefix, input, strlen(if_prefix))) {
+     input += strlen(if_prefix);
+     if(!*input)
+       return CURLE_BAD_FUNCTION_ARGUMENT;
+-    *iface = curlx_memdup0(input, len - strlen(if_prefix));
+-    return *iface ? CURLE_OK : CURLE_OUT_OF_MEMORY;
++    if(iface) {
++      *iface = curlx_memdup0(input, len - strlen(if_prefix));
++      return *iface ? CURLE_OK : CURLE_OUT_OF_MEMORY;
++    }
++    return CURLE_OK;
+   }
+   else if(!strncmp(host_prefix, input, strlen(host_prefix))) {
+     input += strlen(host_prefix);
+     if(!*input)
+       return CURLE_BAD_FUNCTION_ARGUMENT;
+-    *host = curlx_memdup0(input, len - strlen(host_prefix));
+-    return *host ? CURLE_OK : CURLE_OUT_OF_MEMORY;
++    if(host) {
++      *host = curlx_memdup0(input, len - strlen(host_prefix));
++      return *host ? CURLE_OK : CURLE_OUT_OF_MEMORY;
++    }
++    return CURLE_OK;
+   }
+   else if(!strncmp(if_host_prefix, input, strlen(if_host_prefix))) {
+     const char *host_part;
+@@ -509,23 +520,30 @@ CURLcode Curl_parse_interface(const char *input,
+     host_part = memchr(input, '!', len);
+     if(!host_part || !*(host_part + 1))
+       return CURLE_BAD_FUNCTION_ARGUMENT;
+-    *iface = curlx_memdup0(input, host_part - input);
+-    if(!*iface)
+-      return CURLE_OUT_OF_MEMORY;
++    if(iface) {
++      *iface = curlx_memdup0(input, host_part - input);
++      if(!*iface)
++        return CURLE_OUT_OF_MEMORY;
++    }
+     ++host_part;
+-    *host = curlx_memdup0(host_part, len - (host_part - input));
+-    if(!*host) {
+-      curlx_free(*iface);
+-      *iface = NULL;
+-      return CURLE_OUT_OF_MEMORY;
++    if(host) {
++      *host = curlx_memdup0(host_part, len - (host_part - input));
++      if(!*host) {
++        if(iface)
++          Curl_safefree(*iface);
++        return CURLE_OUT_OF_MEMORY;
++      }
+     }
+     return CURLE_OK;
+   }
+ 
+   if(!*input)
+     return CURLE_BAD_FUNCTION_ARGUMENT;
+-  *dev = curlx_memdup0(input, len);
+-  return *dev ? CURLE_OK : CURLE_OUT_OF_MEMORY;
++  if(dev) {
++    *dev = curlx_memdup0(input, len);
++    return *dev ? CURLE_OK : CURLE_OUT_OF_MEMORY;
++  }
++  return CURLE_OK;
+ }
+ 
+ #ifndef CURL_DISABLE_BINDLOCAL
+@@ -545,27 +563,38 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
+                                                 "random" */
+   /* how many port numbers to try to bind to, increasing one at a time */
+   int portnum = data->set.localportrange;
+-  const char *dev = data->set.str[STRING_DEVICE];
+-  const char *iface_input = data->set.str[STRING_INTERFACE];
+-  const char *host_input = data->set.str[STRING_BINDHOST];
+-  const char *iface = iface_input ? iface_input : dev;
+-  const char *host = host_input ? host_input : dev;
++  char *dev_in = NULL, *iface_in = NULL, *host_in = NULL;
++  const char *iface = NULL, *host = NULL;
+   int error;
+ #ifdef IP_BIND_ADDRESS_NO_PORT
+   int on = 1;
+ #endif
++  CURLcode result = CURLE_OK;
++
+ #ifndef USE_IPV6
+   (void)scope;
+ #endif
+ 
+-  /*************************************************************
+-   * Select device to bind socket to
+-   *************************************************************/
++  if(conn->interface_opts) {
++    /*************************************************************
++     * Select device to bind socket to
++     *************************************************************/
++    result = Curl_parse_interface(conn->interface_opts,
++                                  &dev_in, &iface_in, &host_in);
++    if(result)
++      goto out;
++    /* This is how we use the values */
++    iface = iface_in ? iface_in : dev_in;
++    host = host_in ? host_in : dev_in;
++  }
++
+   if(!iface && !host && !port)
+-    /* no local kind of binding was requested */
+-    return CURLE_OK;
+-  else if(iface && (strlen(iface) >= 255))
+-    return CURLE_BAD_FUNCTION_ARGUMENT;
++    goto out;
++
++  if(iface && (strlen(iface) >= 255)) {
++    result = CURLE_BAD_FUNCTION_ARGUMENT;
++    goto out;
++  }
+ 
+   memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
+ 
+@@ -593,14 +622,15 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
+          * succeeds it means the parameter was a valid interface and not an IP
+          * address. Return immediately.
+          */
+-        if(!host_input) {
++        if(!host_in) {
+           infof(data, "socket successfully bound to interface '%s'", iface);
+-          return CURLE_OK;
++          result = CURLE_OK;
++          goto out;
+         }
+       }
+     }
+ #endif
+-    if(!host_input) {
++    if(!host_in) {
+       /* Discover IP from input device, then bind to it */
+       if2ip_result = Curl_if2ip(af,
+ #ifdef USE_IPV6
+@@ -610,18 +640,20 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
+     }
+     switch(if2ip_result) {
+     case IF2IP_NOT_FOUND:
+-      if(iface_input && !host_input) {
++      if(iface_in && !host_in) {
+         /* Do not fall back to treating it as a hostname */
+         char buffer[STRERROR_LEN];
+         data->state.os_errno = error = SOCKERRNO;
+         failf(data, "Could not bind to interface '%s' with errno %d: %s",
+               iface, error, curlx_strerror(error, buffer, sizeof(buffer)));
+-        return CURLE_INTERFACE_FAILED;
++        result = CURLE_INTERFACE_FAILED;
++        goto out;
+       }
+       break;
+     case IF2IP_AF_NOT_SUPPORTED:
+       /* Signal the caller to try another address family if available */
+-      return CURLE_UNSUPPORTED_PROTOCOL;
++      result = CURLE_UNSUPPORTED_PROTOCOL;
++      goto out;
+     case IF2IP_FOUND:
+       /*
+        * We now have the numerical IP address in the 'myhost' buffer
+@@ -632,7 +664,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
+       done = 1;
+       break;
+     }
+-    if(!iface_input || host_input) {
++    if(!iface_in || host_in) {
+       /*
+        * This was not an interface, resolve the name as a hostname
+        * or IP number
+@@ -659,7 +691,8 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
+         if(af != h_af) {
+           /* bad IP version combo, signal the caller to try another address
+              family if available */
+-          return CURLE_UNSUPPORTED_PROTOCOL;
++          result = CURLE_UNSUPPORTED_PROTOCOL;
++          goto out;
+         }
+         done = 1;
+       }
+@@ -692,8 +725,10 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
+                present, is known to be numeric */
+             curl_off_t scope_id;
+             if(curlx_str_number((const char **)CURL_UNCONST(&scope_ptr),
+-                                &scope_id, UINT_MAX))
+-              return CURLE_UNSUPPORTED_PROTOCOL;
++                                &scope_id, UINT_MAX)) {
++              result = CURLE_UNSUPPORTED_PROTOCOL;
++              goto out;
++            }
+             si6->sin6_scope_id = (unsigned int)scope_id;
+           }
+ #endif
+@@ -720,7 +755,8 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
+       data->state.os_errno = error = SOCKERRNO;
+       failf(data, "Could not bind to '%s' with errno %d: %s", host,
+             error, curlx_strerror(error, buffer, sizeof(buffer)));
+-      return CURLE_INTERFACE_FAILED;
++      result = CURLE_INTERFACE_FAILED;
++      goto out;
+     }
+   }
+   else {
+@@ -747,7 +783,8 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
+       /* we succeeded to bind */
+       infof(data, "Local port: %hu", port);
+       conn->bits.bound = TRUE;
+-      return CURLE_OK;
++      result = CURLE_OK;
++      goto out;
+     }
+ 
+     if(--portnum > 0) {
+@@ -773,7 +810,13 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
+           error, curlx_strerror(error, buffer, sizeof(buffer)));
+   }
+ 
+-  return CURLE_INTERFACE_FAILED;
++  result = CURLE_INTERFACE_FAILED;
++
++out:
++  curlx_free(dev_in);
++  curlx_free(iface_in);
++  curlx_free(host_in);
++  return result;
+ }
+ #endif
+ 
+diff --git a/lib/setopt.c b/lib/setopt.c
+index ae77ae8..4c634a8 100644
+--- a/lib/setopt.c
++++ b/lib/setopt.c
+@@ -160,33 +160,18 @@ static CURLcode setstropt_userpwd(const char *option, char **userp,
+   return CURLE_OK;
+ }
+ 
+-static CURLcode setstropt_interface(char *option, char **devp,
+-                                    char **ifacep, char **hostp)
++static CURLcode setstropt_interface(struct Curl_easy *data, char *option)
+ {
+-  char *dev = NULL;
+-  char *iface = NULL;
+-  char *host = NULL;
+-  CURLcode result;
+-
+-  DEBUGASSERT(devp);
+-  DEBUGASSERT(ifacep);
+-  DEBUGASSERT(hostp);
+-
++  if(option && !option[0])
++    option = NULL;
+   if(option) {
+-    /* Parse the interface details if set, otherwise clear them all */
+-    result = Curl_parse_interface(option, &dev, &iface, &host);
++    /* Parse for checking syntax */
++    CURLcode result = Curl_parse_interface(option, NULL, NULL, NULL);
+     if(result)
+       return result;
++    return Curl_setstropt(&data->set.str[STRING_INTERFACE_OPT], option);
+   }
+-  curlx_free(*devp);
+-  *devp = dev;
+-
+-  curlx_free(*ifacep);
+-  *ifacep = iface;
+-
+-  curlx_free(*hostp);
+-  *hostp = host;
+-
++  Curl_safefree(data->set.str[STRING_INTERFACE_OPT]);
+   return CURLE_OK;
+ }
+ 
+@@ -2267,10 +2252,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option,
+      * Set what interface or address/hostname to bind the socket to when
+      * performing an operation and thus what from-IP your connection will use.
+      */
+-    return setstropt_interface(ptr,
+-                               &s->str[STRING_DEVICE],
+-                               &s->str[STRING_INTERFACE],
+-                               &s->str[STRING_BINDHOST]);
++    return setstropt_interface(data, ptr);
+   case CURLOPT_ISSUERCERT:
+     /*
+      * Set Issuer certificate file
+diff --git a/lib/url.c b/lib/url.c
+index 4a01baf..1b6e9e3 100644
+--- a/lib/url.c
++++ b/lib/url.c
+@@ -550,7 +550,7 @@ void Curl_conn_free(struct Curl_easy *data, struct connectdata *conn)
+   Curl_safefree(conn->host.rawalloc); /* hostname buffer */
+   Curl_safefree(conn->conn_to_host.rawalloc); /* hostname buffer */
+   Curl_safefree(conn->secondaryhostname);
+-  Curl_safefree(conn->localdev);
++  Curl_safefree(conn->interface_opts);
+   Curl_ssl_conn_config_cleanup(conn);
+ 
+ #ifdef USE_UNIX_SOCKETS
+@@ -773,24 +773,29 @@ static bool url_match_connect_config(struct connectdata *conn,
+      m->data->set.ipver != conn->ip_version)
+     return FALSE;
+ 
+-  if(m->needle->localdev || m->needle->localport) {
++  /* When needle has specific local bind settings, those have to match.
++   * If it does not, any other connection might do when it comes to ports. */
++  if(m->needle->localport &&
++     ((conn->localport != m->needle->localport) ||
++      (conn->localportrange != m->needle->localportrange)))
++    return FALSE;
++  /* For interface related bind options, we require a full match
++   * as connection might go totally different ways (VPNs, for example). */
++  if((m->needle->interface_opts != conn->interface_opts) &&
++     (!m->needle->interface_opts || !conn->interface_opts ||
++      strcmp(conn->interface_opts, m->needle->interface_opts)))
++    return FALSE;
++
++  if((m->needle->interface_opts || m->needle->localport) &&
+     /* If we are bound to a specific local end (IP+port), we must not reuse a
+        random other one, although if we did not ask for a particular one we
+-       can reuse one that was bound.
+-
+-       This comparison is a bit rough and too strict. Since the input
+-       parameters can be specified in numerous ways and still end up the same
+-       it would take a lot of processing to make it really accurate. Instead,
+-       this matching will assume that reuses of bound connections will most
+-       likely also reuse the exact same binding parameters and missing out a
+-       few edge cases should not hurt anyone much.
+-    */
+-    if((conn->localport != m->needle->localport) ||
+-       (conn->localportrange != m->needle->localportrange) ||
+-       (m->needle->localdev &&
+-        (!conn->localdev || strcmp(conn->localdev, m->needle->localdev))))
+-      return FALSE;
+-  }
++       can reuse one that was bound. */
++    ((conn->localport != m->needle->localport) ||
++     (conn->localportrange != m->needle->localportrange) ||
++     (m->needle->interface_opts &&
++      (!conn->interface_opts ||
++       strcmp(conn->interface_opts, m->needle->interface_opts)))))
++    return FALSE;
+ 
+   if(m->needle->bits.conn_to_host != conn->bits.conn_to_host)
+     /* do not mix connections that use the "connect to host" feature and
+@@ -1443,9 +1448,10 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
+   conn->transport_wanted = TRNSPRT_TCP; /* most of them are TCP streams */
+ 
+   /* Store the local bind parameters that will be used for this connection */
+-  if(data->set.str[STRING_DEVICE]) {
+-    conn->localdev = curlx_strdup(data->set.str[STRING_DEVICE]);
+-    if(!conn->localdev)
++  if(data->set.str[STRING_INTERFACE_OPT]) {
++    conn->interface_opts =
++      curlx_strdup(data->set.str[STRING_INTERFACE_OPT]);
++    if(!conn->interface_opts)
+       goto error;
+   }
+ #ifndef CURL_DISABLE_BINDLOCAL
+@@ -1465,7 +1471,7 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
+   return conn;
+ error:
+ 
+-  curlx_free(conn->localdev);
++  curlx_free(conn->interface_opts);
+   curlx_free(conn);
+   return NULL;
+ }
+diff --git a/lib/urldata.h b/lib/urldata.h
+index 0bc9ade..327c9f4 100644
+--- a/lib/urldata.h
++++ b/lib/urldata.h
+@@ -694,7 +694,7 @@ struct connectdata {
+      made and will serve the purpose of being used for comparison reasons so
+      that subsequent bound-requested connections are not accidentally reusing
+      wrong connections. */
+-  char *localdev;
++  char *interface_opts;
+   uint16_t localportrange;
+ #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+   int socks5_gssapi_enctype;
+@@ -1167,9 +1167,7 @@ enum dupstring {
+ #endif
+   STRING_CUSTOMREQUEST,   /* HTTP/FTP/RTSP request/method to use */
+   STRING_DEFAULT_PROTOCOL, /* Protocol to use when the URL does not specify */
+-  STRING_DEVICE,          /* local network interface/address to use */
+-  STRING_INTERFACE,       /* local network interface to use */
+-  STRING_BINDHOST,        /* local address to use */
++  STRING_INTERFACE_OPT,   /* CURLOPT_INTERFACE config */
+   STRING_ENCODING,        /* Accept-Encoding string */
+ #ifndef CURL_DISABLE_FTP
+   STRING_FTP_ACCOUNT,     /* ftp account data */
+-- 
+2.35.6
diff --git a/meta/recipes-support/curl/curl_8.19.0.bb b/meta/recipes-support/curl/curl_8.19.0.bb
index a4f7b466c3..026b5a3638 100644
--- a/meta/recipes-support/curl/curl_8.19.0.bb
+++ b/meta/recipes-support/curl/curl_8.19.0.bb
@@ -70,6 +70,7 @@ SRC_URI = "https://curl.se/download/${BP}.tar.xz \
            file://CVE-2026-92392.patch \
            file://CVE-2026-94266_p1.patch \
            file://CVE-2026-94266_p2.patch \
+           file://CVE-2026-107929.patch \
            "
 
 SRC_URI:append:class-nativesdk = " \
