On Wed, Jun 24, 2026 at 06:13:02PM +0200, Salvatore Bonaccorso wrote:
> Hi Nicolas,
> 
> On Wed, Jun 24, 2026 at 10:27:49AM -0400, Nicolas Mora wrote:
> > Hello Salvatore,
> > 
> > thanks for the bug report.
> > 
> > I prepared a new package in salsa [1], I also opened a bug upstream [2]
> > since I had to make some changes to the patch for CVE-2026-15661: [3], [4].
> > 
> > Hopefully the package will be uploaded soon.
> 
> Thank you. Note for trixie-security Moritz did prepared a security
> updae which should go out soon.

I was unaware of the existing trixie pu update since it hasn't been
proposed to the stable release managers yet.

Nicolas, I prepared the following backport yesterday and have uploaded
to security-master, please also have a look over it. I'll release the
DSA tomorrow.

Cheers,
        Moritz
diff -Nru libssh2-1.11.1/debian/changelog libssh2-1.11.1/debian/changelog
--- libssh2-1.11.1/debian/changelog     2024-10-16 13:36:53.000000000 +0200
+++ libssh2-1.11.1/debian/changelog     2026-06-23 23:01:56.000000000 +0200
@@ -1,3 +1,10 @@
+libssh2 (1.11.1-1+deb13u1) trixie-security; urgency=medium
+
+  * CVE-2026-7598 (Closes: #1135647)
+  * CVE-2025-15661 / CVE-2026-55199 / CVE-2026-55200 (Closes: #1140401)
+
+ -- Moritz Mühlenhoff <[email protected]>  Tue, 23 Jun 2026 23:01:56 +0200
+
 libssh2 (1.11.1-1) unstable; urgency=medium
 
   [ Nicolas Mora ]
diff -Nru libssh2-1.11.1/debian/patches/CVE-2025-15661.patch 
libssh2-1.11.1/debian/patches/CVE-2025-15661.patch
--- libssh2-1.11.1/debian/patches/CVE-2025-15661.patch  1970-01-01 
01:00:00.000000000 +0100
+++ libssh2-1.11.1/debian/patches/CVE-2025-15661.patch  2026-06-23 
22:58:24.000000000 +0200
@@ -0,0 +1,111 @@
+From 2dae3024897e1898d389835151f4e9606227721d Mon Sep 17 00:00:00 2001
+From: Will Cosgrove <[email protected]>
+Date: Fri, 10 Oct 2025 08:26:20 -0700
+Subject: [PATCH] Update sftp_symlink to avoid out of bounds read on malformed
+ packet #1705 (#1717)
+
+--- libssh2-1.11.1.orig/src/sftp.c
++++ libssh2-1.11.1/src/sftp.c
+@@ -3795,15 +3795,19 @@ static int sftp_symlink(LIBSSH2_SFTP *sf
+ {
+     LIBSSH2_CHANNEL *channel = sftp->channel;
+     LIBSSH2_SESSION *session = channel->session;
+-    size_t data_len = 0, link_len;
++    size_t data_len = 0, lk_len;
+     /* 13 = packet_len(4) + packet_type(1) + request_id(4) + path_len(4) */
+     ssize_t packet_len =
+         path_len + 13 +
+         ((link_type == LIBSSH2_SFTP_SYMLINK) ? (4 + target_len) : 0);
+     unsigned char *s, *data = NULL;
++    struct string_buf buf;
+     static const unsigned char link_responses[2] =
+         { SSH_FXP_NAME, SSH_FXP_STATUS };
+     int retcode;
++    unsigned char packet_type;
++    uint32_t tmp_u32;
++    unsigned char *lk_target;
+ 
+     if(sftp->symlink_state == libssh2_NB_state_idle) {
+         sftp->last_errno = LIBSSH2_FX_OK;
+@@ -3891,8 +3895,25 @@ static int sftp_symlink(LIBSSH2_SFTP *sf
+ 
+     sftp->symlink_state = libssh2_NB_state_idle;
+ 
+-    if(data[0] == SSH_FXP_STATUS) {
+-        retcode = _libssh2_ntohu32(data + 5);
++    buf.data = (unsigned char *)LIBSSH2_UNCONST(data);
++    buf.dataptr = buf.data;
++    buf.len = data_len;
++
++    if(_libssh2_get_byte(&buf, &packet_type)) {
++        LIBSSH2_FREE(session, data);
++        return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
++                              "SFTP Protocol Error (type)");
++    }
++
++    if(packet_type == SSH_FXP_STATUS) {
++        if(_libssh2_get_u32(&buf, &tmp_u32)) {
++            LIBSSH2_FREE(session, data);
++            return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
++                                  "SFTP Protocol Error (code)");
++        }
++
++        retcode = (int)tmp_u32;
++
+         LIBSSH2_FREE(session, data);
+         if(retcode == LIBSSH2_FX_OK)
+             return LIBSSH2_ERROR_NONE;
+@@ -3903,30 +3924,37 @@ static int sftp_symlink(LIBSSH2_SFTP *sf
+         }
+     }
+ 
+-    if(_libssh2_ntohu32(data + 5) < 1) {
++    /* advance past id */
++    if(_libssh2_get_u32(&buf, &tmp_u32)) {
+         LIBSSH2_FREE(session, data);
+         return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+-                              "Invalid READLINK/REALPATH response, "
+-                              "no name entries");
++                              "SFTP Protocol Error (id)");
+     }
+ 
+-    if(data_len < 13) {
+-        if(data_len > 0) {
+-            LIBSSH2_FREE(session, data);
+-        }
++    /* look for at least one link */
++    if(_libssh2_get_u32(&buf, &tmp_u32) || tmp_u32 < 1) {
++        LIBSSH2_FREE(session, data);
+         return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
+-                              "SFTP stat packet too short");
++                                     "Invalid READLINK/REALPATH response, "
++                                     "no name entries");
+     }
+ 
+-    /* this reads a u32 and stores it into a signed 32bit value */
+-    link_len = _libssh2_ntohu32(data + 9);
+-    if(link_len < target_len) {
+-        memcpy(target, data + 13, link_len);
+-        target[link_len] = 0;
+-        retcode = (int)link_len;
++    if(_libssh2_get_string(&buf, &lk_target, &lk_len) == LIBSSH2_ERROR_NONE) {
++        if(lk_len < target_len) {
++            memcpy(target, lk_target, lk_len);
++            target[lk_len] = '\0';
++            retcode = (int)lk_len;
++        }
++        else {
++            retcode = LIBSSH2_ERROR_BUFFER_TOO_SMALL;
++        }
+     }
+-    else
+-        retcode = LIBSSH2_ERROR_BUFFER_TOO_SMALL;
++    else {
++        LIBSSH2_FREE(session, data);
++        return _libssh2_error(session, LIBSSH2_ERROR_SFTP_PROTOCOL,
++                              "SFTP Protocol Error (filename)");
++    }
++
+     LIBSSH2_FREE(session, data);
+ 
+     return retcode;
diff -Nru libssh2-1.11.1/debian/patches/CVE-2026-55199.patch 
libssh2-1.11.1/debian/patches/CVE-2026-55199.patch
--- libssh2-1.11.1/debian/patches/CVE-2026-55199.patch  1970-01-01 
01:00:00.000000000 +0100
+++ libssh2-1.11.1/debian/patches/CVE-2026-55199.patch  2026-06-23 
22:59:46.000000000 +0200
@@ -0,0 +1,21 @@
+From 17626857d20b3c9a1addfa45979dadcee1cd84a4 Mon Sep 17 00:00:00 2001
+From: TristanInSec <[email protected]>
+Date: Wed, 15 Apr 2026 14:51:08 -0400
+Subject: [PATCH] packet: check `_libssh2_get_string()` return in `EXT_INFO`
+ handler
+
+--- libssh2-1.11.1.orig/src/packet.c
++++ libssh2-1.11.1/src/packet.c
+@@ -868,8 +868,10 @@ _libssh2_packet_add(LIBSSH2_SESSION * se
+ 
+                     nr_extensions -= 1;
+ 
+-                    _libssh2_get_string(&buf, &name, &name_len);
+-                    _libssh2_get_string(&buf, &value, &value_len);
++                    if(_libssh2_get_string(&buf, &name, &name_len))
++                        break;
++                    if(_libssh2_get_string(&buf, &value, &value_len))
++                        break;
+ 
+                     if(name && value) {
+                         _libssh2_debug((session,
diff -Nru libssh2-1.11.1/debian/patches/CVE-2026-55200.patch 
libssh2-1.11.1/debian/patches/CVE-2026-55200.patch
--- libssh2-1.11.1/debian/patches/CVE-2026-55200.patch  1970-01-01 
01:00:00.000000000 +0100
+++ libssh2-1.11.1/debian/patches/CVE-2026-55200.patch  2026-06-23 
23:01:52.000000000 +0200
@@ -0,0 +1,22 @@
+From 97acf3dfda80c91c3a8c9f2372546301d4a1a7a8 Mon Sep 17 00:00:00 2001
+From: Will Cosgrove <[email protected]>
+Date: Fri, 12 Jun 2026 15:57:44 -0700
+Subject: [PATCH] transport.c: Additional boundary checks for packet length
+ (#2052)
+
+--- libssh2-1.11.1.orig/src/transport.c
++++ libssh2-1.11.1/src/transport.c
+@@ -639,8 +639,12 @@ int _libssh2_transport_read(LIBSSH2_SESS
+                 total_num = 4;
+ 
+                 p->packet_length = _libssh2_ntohu32(block);
+-                if(p->packet_length < 1)
++                if(p->packet_length < 1) {
+                     return LIBSSH2_ERROR_DECRYPT;
++                }
++                else if(p->packet_length > LIBSSH2_PACKET_MAXPAYLOAD) {
++                    return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
++                }
+ 
+                 /* total_num may include size field, however due to existing
+                  * logic it needs to be removed after the entire packet is 
read
diff -Nru libssh2-1.11.1/debian/patches/CVE-2026-7598.patch 
libssh2-1.11.1/debian/patches/CVE-2026-7598.patch
--- libssh2-1.11.1/debian/patches/CVE-2026-7598.patch   1970-01-01 
01:00:00.000000000 +0100
+++ libssh2-1.11.1/debian/patches/CVE-2026-7598.patch   2026-06-23 
22:59:03.000000000 +0200
@@ -0,0 +1,41 @@
+From 256d04b60d80bf1190e96b0ad1e91b2174d744b1 Mon Sep 17 00:00:00 2001
+From: Will Cosgrove <[email protected]>
+Date: Mon, 13 Apr 2026 11:18:25 -0700
+Subject: [PATCH] userauth.c: username_len bounds checking (#1858)
+
+--- libssh2-1.11.1.orig/src/userauth.c
++++ libssh2-1.11.1/src/userauth.c
+@@ -80,6 +80,12 @@ static char *userauth_list(LIBSSH2_SESSI
+         memset(&session->userauth_list_packet_requirev_state, 0,
+                sizeof(session->userauth_list_packet_requirev_state));
+ 
++        if(username_len > UINT32_MAX - 27) {
++            _libssh2_error(session, LIBSSH2_ERROR_PROTO,
++                           "username_len out of bounds");
++            return NULL;
++        }
++
+         session->userauth_list_data_len = username_len + 27;
+ 
+         s = session->userauth_list_data =
+@@ -307,6 +313,11 @@ userauth_password(LIBSSH2_SESSION *sessi
+          * 40 = packet_type(1) + username_len(4) + service_len(4) +
+          * service(14)"ssh-connection" + method_len(4) + method(8)"password" +
+          * chgpwdbool(1) + password_len(4) */
++        if(username_len > UINT32_MAX - 40) {
++            return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
++                                  "username_len out of bounds");
++        }
++
+         session->userauth_pswd_data_len = username_len + 40;
+ 
+         session->userauth_pswd_data0 =
+@@ -447,7 +458,7 @@ password_response:
+                         }
+ 
+                         /* basic data_len + newpw_len(4) */
+-                        if(username_len + password_len + 44 <= UINT_MAX) {
++                        if(username_len <= UINT32_MAX - password_len - 44) {
+                             session->userauth_pswd_data_len =
+                                 username_len + password_len + 44;
+                             s = session->userauth_pswd_data =
diff -Nru libssh2-1.11.1/debian/patches/libssh-unconst-backport.patch 
libssh2-1.11.1/debian/patches/libssh-unconst-backport.patch
--- libssh2-1.11.1/debian/patches/libssh-unconst-backport.patch 1970-01-01 
01:00:00.000000000 +0100
+++ libssh2-1.11.1/debian/patches/libssh-unconst-backport.patch 2026-06-23 
23:01:56.000000000 +0200
@@ -0,0 +1,24 @@
+Needed by the fix for CVE-2025-15661
+
+Cherrypicked from 
+commit 606c102e52f8447de2b745dd6c5ddf418defc519
+Author: Viktor Szakats <[email protected]>
+Date:   Thu Jan 30 21:18:23 2025 +0100
+
+--- libssh2-1.11.1.orig/src/libssh2_priv.h
++++ libssh2-1.11.1/src/libssh2_priv.h
+@@ -117,6 +117,14 @@
+ #define UINT32_MAX 0xffffffffU
+ #endif
+ 
++#ifdef _WIN64
++#define LIBSSH2_UNCONST(p)  ((void *)(libssh2_uint64_t)(const void *)(p))
++#elif defined(_MSC_VER)
++#define LIBSSH2_UNCONST(p)  ((void *)(unsigned int)(const void *)(p))
++#else
++#define LIBSSH2_UNCONST(p)  ((void *)(uintptr_t)(const void *)(p))
++#endif
++
+ #if (defined(__GNUC__) || defined(__clang__)) && \
+     defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
+     !defined(LIBSSH2_NO_FMT_CHECKS)
diff -Nru libssh2-1.11.1/debian/patches/series 
libssh2-1.11.1/debian/patches/series
--- libssh2-1.11.1/debian/patches/series        2024-10-16 13:36:53.000000000 
+0200
+++ libssh2-1.11.1/debian/patches/series        2026-06-23 23:01:56.000000000 
+0200
@@ -6,3 +6,8 @@
 #CVE-2023-48795.patch
 #maxpathlen.patch
 #openssh-9.8.patch
+CVE-2025-15661.patch
+CVE-2026-7598.patch
+CVE-2026-55199.patch
+CVE-2026-55200.patch
+libssh-unconst-backport.patch

Reply via email to