When the SSH Server Attacks the Client: libssh2 CVE-2026-55200

Almost everything you know about securing SSH is about the server. Disable password auth, rotate host keys, put sshd behind a bastion, rate-limit with fail2ban. The threat model is always the same: an attacker out on the internet trying to get in to a box you run.
CVE-2026-55200 turns that around. It is a critical, pre-authentication memory-corruption bug in libssh2, and the victim is the SSH client. The attacker is the server. If a piece of software using a vulnerable libssh2 connects out to a host an attacker controls, that host can corrupt the client's memory and run code inside it before any credentials are exchanged. None of your sshd hardening applies, because sshd was never in the picture. This post is what the bug actually is, why it is a DevOps problem rather than a sysadmin footnote, the one distinction that decides whether you are exposed, and how to find libssh2 in your stack.
TL;DR
- CVE-2026-55200 is a pre-auth heap overflow in libssh2's
ssh2_transport_read(). It does not bound-check thepacket_lengthfield, so a malicious server can trigger an out-of-bounds write and, plausibly, remote code execution. Critical (CVSS 9.2), no credentials or interaction required. - It affects the SSH client, not the server. The attacker is whatever host your client connects to.
- Vulnerable: libssh2 through 1.11.1. Fixed upstream in commit
97acf3d(released as 1.11.2); at disclosure distros were shipping patched 1.11.1 builds ahead of a formal tag. - OpenSSH is not libssh2. Your
ssh,sshd, and the plaingitCLI use OpenSSH's own code and are not affected by this CVE. The exposure is libssh2-linked clients:curldoingscp/sftp, libgit2-based git tooling, PHP/Python SSH bindings, backup agents, embedded devices. - libssh2 is frequently statically linked or embedded, so
apt upgradedoes not always reach it. You have to go looking.
Prerequisites
- A working idea of the SSH client/server split (who initiates, who listens)
- Comfort auditing packages and shared-library dependencies on Linux
- A container or two whose contents you are responsible for
The bug, precisely
Every SSH connection is a stream of binary packets. Each packet is framed by a length field, packet_length, that tells the receiver how many bytes to read next. In libssh2, the function ssh2_transport_read() reads that field and uses it to size a buffer.
The flaw (CWE-680, an integer overflow leading to a buffer overflow) is that it does not enforce an upper bound on packet_length. A malicious server sends a crafted packet with an enormous length value, the size calculation overflows, libssh2 allocates less memory than it goes on to write, and the result is a heap out-of-bounds write. This happens during the transport-layer read, which runs before authentication, so the attacker never needs a valid key or password. A controlled heap overflow of this kind is the classic path to remote code execution, and a public proof-of-concept already exists. No in-the-wild exploitation had been confirmed at the time of writing, but that gap tends to close fast once a PoC is public.
your client ──TCP connect──▶ attacker's SSH server
◀─ crafted packet with a huge packet_length ─
ssh2_transport_read() under-allocates, then overwrites the heap
▶ memory corruption → potential RCE, pre-auth
The mental flip worth internalizing: the dangerous direction here is outbound. A connection your own automation initiates is the attack surface.
Why this is a pipeline problem
"An SSH client bug" sounds like it belongs to humans typing ssh in a terminal. It does not, because those humans are almost all running OpenSSH, which is a separate codebase (more on that in a second). The software that actually links libssh2 is the automation:
curlbuilt with libssh2 handlesscp://andsftp://URLs. Plenty of CI jobs, health checks, and download steps shell out tocurl.- libgit2-based git tooling. libgit2 can provide SSH transport through libssh2. That covers language bindings like
pygit2andnodegit, and some desktop and CI git integrations that do not shell out to the systemgit. - Language SSH libraries. PHP's
ssh2extension and Python'sssh2-pythonwrap libssh2 directly. Anything that does programmatic SFTP through them is in scope. - Backup and file-transfer agents, and a long tail of embedded and IoT firmware, which often bundle libssh2 statically.
Put together, that is a lot of outbound SSH originating from inside your infrastructure, from processes nobody thinks of as "an SSH client." And the realistic trigger is not exotic: a job that pulls an artifact over sftp, clones from a mirror, or connects to a host resolved from configuration an attacker can influence (a compromised mirror, a typosquatted hostname, or a man-in-the-middle on a flat build network). Pre-auth means the connection does not have to succeed for the payload to land.
The one distinction that decides everything: OpenSSH is not libssh2
This is where most of the panic should drain away, and where the real audit begins. There are two completely separate SSH implementations in play, and only one of them is affected:
| You are using... | SSH comes from | Affected by CVE-2026-55200? |
|---|---|---|
ssh, scp (OpenSSH), sshd |
OpenSSH's own code | No |
The plain git CLI over SSH |
Shells out to the OpenSSH ssh binary |
No |
curl scp:// / sftp:// |
libssh2 (if built with it) | Yes, if libssh2 ≤ 1.11.1 |
pygit2 / nodegit / libgit2 tools |
libgit2's SSH backend | Yes, if built against libssh2 ≤ 1.11.1 |
PHP ssh2, ssh2-python |
libssh2 | Yes, if libssh2 ≤ 1.11.1 |
The libgit2 row has a wrinkle worth knowing: libgit2's SSH support is a build-time choice. Its USE_SSH option can be set to libssh2 (which links the vulnerable library) or to exec (which shells out to the system OpenSSH binary instead). Two builds of the same tool can land on opposite sides of this table. So "am I affected" is not a question about which tool you use; it is a question about what that tool was linked against.
The everyday git clone [email protected]:... you run in a terminal uses the OpenSSH ssh binary and is not affected through that path. The risk is the tooling that embeds a git implementation rather than calling out to git, and the non-git clients above.
Am I affected? Go and look
Because libssh2 hides inside other binaries, the check is a small hunt rather than one command. Start with the usual suspects:
Then widen the net, because the dynamic-library check misses the worst case:
- Static linking is the trap. A Go, Rust, or C binary can compile libssh2 straight in, so it will not show up in
lddor your package list, andapt upgradewill never touch it. For suspect binaries,strings ./binary | grep -i 'libssh2'sometimes surfaces an embedded version banner. Container image scanners like Trivy or Grype are better at this than a shell loop. - Language bindings pin their own copy. Check
pygit2,nodegit,ssh2-python, and the PHPssh2extension against the libssh2 they were built with, not the system package. - Base images and firmware may ship an old libssh2 you inherited. Rebuild from a patched base rather than assuming the registry did it for you.
Anything you find at 1.11.1 or earlier is in scope.
Fixing it
The fix is upstream commit 97acf3d, which adds the missing bound on packet_length (a LIBSSH2_PACKET_MAXPAYLOAD check), released as libssh2 1.11.2. Practically:
- Update the package to a build that includes the fix. Distributions began shipping patched 1.11.1 packages before a new upstream tag existed, so trust your distro's advisory version over the raw upstream tag.
- Rebuild anything that static-links or vendors libssh2. The library upgrade only helps binaries that actually pick it up. Your own images and Go/Rust artifacts need a rebuild against the patched library.
- Rebuild containers from a patched base, and re-scan, rather than patching a running layer.
- Constrain egress as defense in depth. This bug needs your client to reach a hostile server. Build and CI networks that can only open SSH to a known allowlist of hosts remove the easy version of the attack, and that control is worth having regardless of this CVE.
- Prefer OpenSSH-backed transports where you have the choice. If a tool can shell out to the system
sshinstead of linking libssh2, that path is not affected here.
Do not let "we patched libssh2" become a false all-clear. The dangerous copies are the ones your inventory did not know about: a vendored library inside a language binding, a statically linked CLI, an appliance or IoT image you do not rebuild. Patch the package, then go hunting for the copies that a package manager cannot see.
Wrapping up
CVE-2026-55200 is a good reminder that "securing SSH" is two problems, not one. The server side is the one everybody drills, and it is not what this bug touches. The client side, the outbound connections your automation makes through libraries you did not realize were speaking SSH, is the quieter surface, and it is exactly where a pre-auth heap overflow like this one bites. The work is not glamorous: figure out where libssh2 actually lives in your stack, including the static and vendored copies your package manager cannot see, update to 1.11.2 or a patched build, and rebuild what embeds it. The tooling that connects out on your behalf deserves the same scrutiny as the box that accepts connections.
We earn commissions when you shop through the links below.
DigitalOcean
Cloud infrastructure for developers
Simple, reliable cloud computing designed for developers
DevDojo
Developer community & tools
Join a community of developers sharing knowledge and tools
SMTPfast
Developer-first email API
Send transactional and marketing email through a clean REST API. Detailed logs, webhooks, and embeddable signup forms in one dashboard.
QuizAPI
Developer-first quiz platform
Build, generate, and embed quizzes with a powerful REST API. AI-powered question generation and live multiplayer.
Want to support DevOps Daily and reach thousands of developers?
Become a SponsorFound an issue?
Related Posts
Also worth your time on this topic
CVE-2026-3854: A Single git push Owned GitHub
A semicolon in a git push option let any authenticated user run code on GitHub.com's backend and on 88% of self-hosted GitHub Enterprise installs. Here is how the bug worked and what to do.
SSH Basics and Key Authentication
How does SSH key authentication work? How do you set it up?
junior
Securing Your Linux Server: Essential First Steps
Harden a fresh Ubuntu 24.04 server by creating a non-root user, locking down SSH, configuring a firewall with UFW, and setting up fail2ban to block brute-force attacks.
45 minutes