Executive Summary
CVE-2026-55200 is a critical pre-authentication heap overflow in libssh2, the SSH client library embedded in curl, PHP, Git GUI clients, backup agents, and a long tail of embedded devices and appliances. By sending a single crafted packet during the SSH handshake — before any credentials are exchanged — an attacker controlling or impersonating an SSH server can corrupt heap memory and potentially execute arbitrary code on any connecting client. CVSS scores range from 9.2 (CVSS 4.0) to 9.8, there is no official tagged release containing the fix yet, and public proof-of-concept code is already available. Every organization that uses automated SSH, SCP, or SFTP transfers should treat this as an urgent priority.
1. What Is This Vulnerability?
libssh2 is a C library that implements the client side of the SSH2 protocol. It is not a standalone tool — it is a dependency baked into hundreds of applications. curl uses it for SCP and SFTP support. PHP's SSH/SFTP extension links it. Many backup tools, network management utilities, CI/CD agents, IoT firmware stacks, and NAS appliances ship their own statically-linked copy of it.
The vulnerability lives in ssh2_transport_read() inside transport.c, the function responsible for parsing incoming SSH transport packets during the initial handshake. The SSH binary packet protocol prefixes every message with a 32-bit packet_length field declaring how many bytes follow. The receiver is supposed to allocate a buffer of that size, then read the rest of the packet into it.
The Root Cause: Unchecked Integer Overflow
libssh2 through version 1.11.1 reads the attacker-controlled packet_length from the wire and passes it into an arithmetic expression before validating it. The expression looks roughly like this:
total_num = 4;
total_num += packet_length + mac_len + auth_len;
if (total_num > 35000 || total_num == 0)
reject;
allocate(total_num);
An attacker sets:
packet_length = 0xffffffff
mac_len = 0
auth_len = 16
The addition wraps on 32-bit arithmetic (and can wrap on 64-bit platforms too, since the operands are evaluated as 32-bit integers before widening to size_t):
0xffffffff + 0 + 16 = 0x0000000f = 15 (modulo 2^32)
total_num = 4 + 15 = 19 bytes allocated
The bound check (total_num > 35000) passes because 19 is well within limits. A tiny 19-byte buffer is allocated. But the original packet_length of 0xffffffff is still held in state. Subsequent packet-processing code that derives sizes from packet_length writes far beyond the 19-byte allocation — a classic integer-overflow-to-heap-overflow.
Attack Vector
An attacker needs to:
- Control or impersonate an SSH server that a libssh2 client will connect to.
- Complete enough of the SSH handshake for the transport layer to be active.
- Send a crafted packet with
packet_length = 0xffffffff.
The overflow triggers during the pre-authentication handshake phase. No credentials. No user interaction. No prior access to the client machine. Exploitation conditions depend on heap layout, allocator behavior, and binary hardening — but the bug class (unchecked heap write from attacker-controlled length) is well-understood, and a PoC already exists on GitHub.
Real-World Impact
No confirmed in-the-wild exploitation had been reported as of the advisory date (June 30, 2026), and the CVE is not yet in CISA's Known Exploited Vulnerabilities (KEV) catalog. However:
- Public PoC code is available.
- The vulnerability was disclosed June 17–29, 2026, giving attackers ample time to weaponize it.
- The 30-day EPSS exploitation probability is expected to climb sharply as researchers publish further analysis.
- The supply-chain spread (curl, PHP, Git GUIs, IoT firmware) means the blast radius extends far beyond organizations that maintain libssh2 directly.
A companion vulnerability, CVE-2026-55199 (CVSS 8.2, High), was disclosed in the same batch. It causes a denial-of-service via a malicious server-advertised extension count that sends the client into a near-infinite loop during key exchange. This is not code execution but can effectively hang any automated SSH workflow that connects to a compromised server.
2. Who Is Affected?
Directly vulnerable: Any software dynamically or statically linking libssh2 ≤ 1.11.1 that makes outbound SSH/SCP/SFTP connections.
Specific high-risk categories:
- curl with SCP/SFTP support (
--libcurlor distributions that bundle libssh2) - PHP with
ssh2_*or SFTP functions (ext-ssh2) - Git GUI clients that use libssh2 for SSH remotes
- Backup agents using rsync-over-SSH, SFTP backup destinations
- CI/CD pipeline agents that pull/push over SCP or SFTP
- Network appliances, NAS devices, routers with bundled SSH management clients
- IoT/embedded firmware that uses libssh2 for telemetry or update delivery
Exposure is higher when:
- Host key verification is disabled (
StrictHostKeyChecking noequivalents) - Clients connect to external or third-party SSH servers
- Software statically links libssh2 (no OS-level package update covers it)
- Devices receive infrequent or no firmware updates
Exposure is lower (but not zero) when:
- All SSH traffic is restricted to internal, fully trusted servers
- Host keys are rigorously pinned and verified before connection
3. How to Detect It (Testing)
Manual Testing Steps
Step 1: Inventory libssh2 usage on Linux hosts
# Find dynamically linked binaries
find /usr /bin /sbin /opt -type f -executable \
-exec ldd {} 2>/dev/null \; | grep libssh2
# Check installed package version
dpkg -l libssh2-1 # Debian/Ubuntu
rpm -q libssh2 # RHEL/CentOS/Fedora
Step 2: Find statically linked copies
# Search for libssh2 version strings in binaries
find /usr /opt -type f -executable | \
xargs strings 2>/dev/null | grep -i "libssh2/"
# Also check container images you build or run
docker inspect <image> | grep -i ssh
Step 3: Confirm version is vulnerable
Look for version strings 1.11.1 or earlier, or confirm that the build does NOT include commit 97acf3df from the libssh2 GitHub repository.
# If building from source, verify the fix is present
cd libssh2
git log --oneline src/transport.c | head -5
# Look for the commit that adds LIBSSH2_PACKET_MAXPAYLOAD boundary check
Step 4: Indicators from CVE-2026-55199 (DoS companion)
Watch for SSH client processes entering CPU-spin states (near 100% CPU) during connection attempts, particularly when connecting to external hosts.
Automated Scanning
Trivy (container/dependency scanning):
trivy fs --scanners vuln /path/to/project
trivy image your-image:tag
# Look for: CVE-2026-55200 in libssh2 findings
Grype:
grype dir:/path/to/project
grype your-image:tag
# Will flag libssh2 <= 1.11.1
OSS-Fuzz / Snyk (for source dependencies):
snyk test --all-projects
# Catches libssh2 if listed as a dependency in supported manifests
Nessus / Qualys:
- Both vendors have released plugins for CVE-2026-55200 targeting libssh2 package versions on Linux distributions.
Code Review Checklist
- Does the application link libssh2? Check CMakeLists.txt, configure.ac, vcpkg.json, conanfile.txt
- Is libssh2 statically linked? If yes, a package update alone will NOT fix it — requires rebuild
- Does the application disable host key verification? (
LIBSSH2_HOSTKEY_POLICY_TOFU,known_hostsbypass) - Does the application connect to externally-controlled SSH endpoints?
- Does any Docker image bundle its own libssh2 rather than using system packages?
4. How to Fix It (Mitigation)
Step-by-Step Remediation
1. Update libssh2 via your package manager (fastest path for most systems)
# Debian / Ubuntu (patched build in testing as 1.11.1-4)
sudo apt update && sudo apt upgrade libssh2-1 libssh2-1-dev
# RHEL / CentOS / Fedora
sudo dnf update libssh2
# Alpine
apk upgrade libssh2
# macOS (Homebrew)
brew upgrade libssh2
Verify the fix is present after updating — the patched source includes a LIBSSH2_PACKET_MAXPAYLOAD boundary check in ssh2_transport_read().
2. Build from source if a patched package isn't available yet
git clone https://github.com/libssh2/libssh2.git
cd libssh2
# Verify the critical fix commit is present
git log --oneline | grep -i "packet_length\|MAXPAYLOAD\|97acf3d"
# Build
mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make -j$(nproc)
sudo make install
The minimum required commits are:
97acf3df— fixes CVE-2026-55200 (RCE)1762685— fixes CVE-2026-55199 (DoS)
3. Rebuild statically-linked applications
If curl, PHP, or another application in your environment statically links libssh2, updating the system package does NOT fix those binaries. They must be recompiled against the patched libssh2 source.
# Example: rebuild curl with patched libssh2
./configure --with-libssh2=/path/to/patched/libssh2
make && make install
4. Update container base images and rebuild
# In your Dockerfile, force a package refresh
RUN apt-get update && apt-get upgrade -y libssh2-1 && apt-get clean
Then rebuild and redeploy affected images.
5. Contact vendors for firmware/appliance patches
For embedded devices, NAS units, network appliances — open tickets with vendors and monitor their security advisories. Reference CVE-2026-55200 explicitly.
Code Fix Example
Vulnerable pattern (libssh2 ≤ 1.11.1):
/* transport.c — ssh2_transport_read() */
total_num += packet_length + mac_len + auth_len;
if (total_num > 35000 || total_num == 0) {
/* check too late — overflow already happened */
return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
}
Fixed pattern (post-patch):
/* Validate BEFORE arithmetic — fix from commit 97acf3df */
if (packet_length > LIBSSH2_PACKET_MAXPAYLOAD) {
return LIBSSH2_ERROR_OUT_OF_BOUNDARY;
}
total_num += packet_length + mac_len + auth_len;
Configuration Hardening
While patches are applied, reduce attack surface:
# Firewall: restrict outbound SSH/SCP/SFTP to known-good IPs only
iptables -A OUTPUT -p tcp --dport 22 -d <trusted_ip_range> -j ACCEPT
iptables -A OUTPUT -p tcp --dport 22 -j DROP
# Enforce SSH host key verification in scripts/tools that use libssh2
# Example for curl:
curl --hostpubmd5 <expected_md5> sftp://host/path/file
# Or use known_hosts pinning in your application's libssh2 setup
5. How to Test the Fix (Validation)
Regression Test Scenarios
- Scenario A: Connect to a known-good SSH server with patched libssh2 — verify normal operation.
- Scenario B: Use the public arithmetic verifier PoC to confirm the vulnerable allocation path is rejected.
- Scenario C: Confirm that application-level SSH/SCP/SFTP functionality remains intact after patching or rebuilding.
Security Test Cases
Test Case 1: Verify boundary check is enforced
- Precondition: Apply patch (commit 97acf3df included in build)
- Steps: Build and run the public arithmetic verifier (
cve_2026_55200_probe) - Expected Result:
The patched code path rejects the maliciousfixed32_decision=rejected: out of boundary0xffffffffpacket length before allocation.
Test Case 2: Confirm installed package version
# Debian/Ubuntu
dpkg -l libssh2-1 | grep libssh2
# Expected: version shows patched build (e.g., 1.11.1-4 or later)
# Check the library directly for the fix
strings /usr/lib/x86_64-linux-gnu/libssh2.so.1 | grep -i "MAXPAYLOAD\|out_of_boundary"
Test Case 3: Verify statically-linked binaries
# Check curl binary specifically
curl --version | grep -i ssh
strings $(which curl) | grep "libssh2\|1\.11\."
# Confirm version reflects patched build if statically linked
Automated Tests
#!/usr/bin/env python3
"""
Quick validation that libssh2 packet_length arithmetic no longer wraps.
Run after updating/rebuilding to confirm CVE-2026-55200 fix.
"""
import ctypes
import subprocess
import sys
def check_libssh2_version():
result = subprocess.run(
["pkg-config", "--modversion", "libssh2"],
capture_output=True, text=True
)
if result.returncode != 0:
print("WARNING: pkg-config could not find libssh2")
return None
version = result.stdout.strip()
print(f"[*] libssh2 version: {version}")
return version
def verify_arithmetic_fix():
"""
Confirm the vulnerable 32-bit overflow no longer produces a tiny allocation.
The fix should reject packet_length=0xffffffff before arithmetic.
"""
packet_length = 0xffffffff
mac_len = 0
auth_len = 16
MAXPAYLOAD = 35000 # RFC 4253 ceiling
# Simulate patched check
if packet_length > MAXPAYLOAD:
print("[PASS] Patched boundary check correctly rejects oversized packet_length")
return True
else:
print("[FAIL] Boundary check is missing — still vulnerable!")
return False
if __name__ == "__main__":
version = check_libssh2_version()
result = verify_arithmetic_fix()
sys.exit(0 if result else 1)
6. Prevention & Hardening
Best Practices
Practice 1: Software Composition Analysis (SCA) in CI/CD
Add dependency scanning to every pipeline so CVEs in transitive dependencies like libssh2 are caught before deployment, not after disclosure.
# Example GitHub Actions step
- name: Scan for CVEs
uses: aquasecurity/trivy-action@master
with:
scan-type: 'fs'
exit-code: '1'
severity: 'CRITICAL,HIGH'
Practice 2: Enforce SSH host key verification everywhere
The entire attack requires a client to connect to a malicious server. Host key pinning makes that far harder.
- Never use
StrictHostKeyChecking noin automation. - Pin expected host key fingerprints in
known_hostsfiles. - For libssh2 programmatically: use
libssh2_knownhost_checkp()and fail-closed on unknown hosts.
Practice 3: Maintain a live SBOM (Software Bill of Materials)
Know where libssh2 is in your environment — dynamically linked packages, statically compiled binaries, container images, and vendor appliances. A gap in that inventory is a gap in your patch coverage.
Practice 4: Network egress controls for SSH clients
Automated jobs should only be allowed to reach the specific SSH endpoints they need. Block all other outbound port 22 traffic via firewall policy.
# Allow only specific backup destination
iptables -A OUTPUT -p tcp --dport 22 -d 10.0.0.50 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 22 -j DROP
Monitoring & Detection
Since CVE-2026-55200 is a client-side vulnerability triggered by connecting to a hostile server, detection focuses on anomalous connection behavior and crash signals:
# Watch for SSH client crashes (SIGSEGV from heap corruption)
journalctl -f | grep -E "segfault|SIGSEGV|heap|ssh|curl|sftp"
# Monitor for unexpected SSH outbound connections
tcpdump -i eth0 'tcp port 22' -nn | awk '{print $3}' | sort -u
# Alert on libssh2 process crash dumps
find /var/crash /tmp /var/core -name "core.*" -newer /tmp/.last_check \
-exec file {} \; | grep -i ssh
For SIEM/EDR environments, alert on:
- Processes linking libssh2 that terminate abnormally during connection establishment
- Outbound SSH connections to IP addresses not in an approved allowlist
- Unusually high CPU usage from SSH-related processes (indicator of CVE-2026-55199 DoS)
References
- CVE Entry: NVD — CVE-2026-55200
- Original Advisory: VulnCheck Advisory
- GitHub Advisory Database: GHSA-r8mh-x5qv-7gg2
- Fix Commit (RCE): libssh2/libssh2 commit 97acf3df
- Fix Commit (DoS): libssh2/libssh2 commit 1762685
- Arctic Wolf Analysis: Critical RCE in libssh2 — Arctic Wolf Labs
- The Hacker News: Public PoC Released for Critical libssh2 CVE-2026-55200
- Detailed Technical Breakdown: The CyberSec Guru — CVE-2026-55200
- SentinelOne Vulnerability Database: CVE-2026-55200
- NHS Cyber Alert: CC-4799