Jun 26, 2026·7 min read·71 visits
Writing payloads larger than 4GB to a Go SSH channel causes integer truncation, leading to an infinite write loop and 100% CPU utilization on the executing thread.
A critical vulnerability exists in the Go SSH sub-repository (golang.org/x/crypto/ssh) before version 0.52.0. When an application writes payloads of 4GB or larger in a single write operation, integer truncation in the remote window calculation causes an infinite loop. This results in complete CPU core exhaustion and a denial-of-service condition.
The Go SSH sub-repository, distributed as part of golang.org/x/crypto/ssh, is widely used across the Go ecosystem to implement SSH clients, servers, and tunnels. A denial-of-service vulnerability, tracked as CVE-2026-39834 and GO-2026-5020, resides in the channel data transfer logic. The vulnerability occurs when transferring exceptionally large datasets over an established SSH channel.
The specific issue belongs to the class of integer overflow and truncation errors, cataloged as CWE-190. It manifests when an application calls write operations, such as Write or WriteExtended, with a payload slice size that exceeds the maximum bounds of a 32-bit unsigned integer (4 GiB, or 4,294,967,296 bytes). The vulnerability does not require authentication privileges if the application exposes a file upload or streaming endpoint that forwards user data into an SSH channel.
Upon encountering a 4 GiB write boundary, the internal packet-chunking logic truncates the calculated size of the next data packet to zero. Because the state machine receives a packet size of zero, it makes no progress through the data stream but continues to execute the write loop. The resulting execution loop runs indefinitely, pinning the affected CPU core to 100% capacity and degrading the performance or availability of the entire system.
The technical root cause of the vulnerability lies in the packet size calculation within ssh/channel.go. In the SSH protocol, large payloads are split into smaller chunks bounded by the remote party's maximum payload size and the available window space. This process is managed by an internal helper function called min in vulnerable versions.
The min function is defined with the signature func min(a uint32, b int) uint32. The first parameter a represents ch.maxRemotePayload, which is typically a uint32 variable. The second parameter b is the length of the remaining data slice (len(data)), which is of type int.
On 64-bit architectures, the Go native int type is a 64-bit signed integer. When a caller attempts to transmit a payload size of exactly $2^{32}$ bytes (4 GiB), b holds the value 4,294,967,296. The binary representation of this value is 0x100000000. When the code evaluates uint32(b), the cast drops the upper 32 bits of the 64-bit integer, resulting in a truncated value of 0.
Inside the comparison block, if a < uint32(b) compares the maximum payload size (for example, 32768) to the truncated value of 0. Because 32768 < 0 is false, the function executes the fallback branch and returns uint32(b), which is 0. Consequently, the allocation engine attempts to reserve zero bytes of window capacity and sends an empty packet. Since zero bytes are subtracted from the total remaining length of the payload, the write loop repeats indefinitely with the exact same variables, consuming 100% CPU.
To resolve the truncation defect, the Go security team implemented a fix in Change List 781663. The primary fix changes the comparison logic within ssh/channel.go to use 64-bit integer values, preventing truncation during the comparison phase. Additionally, the function was renamed to avoid namespace conflicts with Go's native built-in min function introduced in modern Go releases.
Below is the comparison of the vulnerable logic and the corrected implementation:
// VULNERABLE FUNCTION
func min(a uint32, b int) uint32 {
if a < uint32(b) {
return a
}
return uint32(b)
}
// PATCHED FUNCTION
// minPayloadSize returns min(limit, length) clamped to a uint32.
// The comparison is done in int64 because length is an int — on
// 64-bit systems len(data) can exceed 2^32, and a direct uint32(length)
// cast would silently truncate to 0 at every multiple of 2^32.
func minPayloadSize(limit uint32, length int) uint32 {
if int64(length) > int64(limit) {
return limit
}
return uint32(length)
}The corrected implementation casts both variables to int64 before conducting the comparison. Because int64 is capable of representing values up to $2^{63}-1$, the value of length (even when exceeding 4 GiB) is accurately preserved. If the remaining data size length is greater than the limit, the function safely returns the limit (which is already a uint32). If the remaining data size is smaller than the limit, it is guaranteed to fit within a uint32 variable, making the conversion safe from truncation.
Exploitation of CVE-2026-39834 requires the attacker to interact with an application that exposes an interface capable of sending data to an SSH channel. The host can be either an SSH client or an SSH server, meaning both outbound and inbound data flows are potentially vulnerable.
To trigger the denial-of-service condition, an attacker must cause the application to execute a single write call of size $n$, where $n$ is an exact multiple of 4 GiB, or slightly above 4 GiB such that the truncated value of b is smaller than the remote window payload threshold.
The vulnerability is triggered at the network boundaries. When the application receives the payload and passes it to the golang.org/x/crypto/ssh channel writer, the executing goroutine becomes stuck. No network errors or panics are thrown; the code simply spins, generating high CPU load. Since Go utilizes cooperative and pre-emptive scheduling, a single spinning goroutine will lock a complete OS thread, eventually degrading the availability of other application routines.
The impact of CVE-2026-39834 is classified as a high-severity Denial of Service (DoS). By utilizing relatively minor local resources to initiate a large file stream or data transfer, an attacker can consume all available CPU cycles on the target system. This causes complete resource exhaustion and halts other system operations.
The CVSS v3.1 score is evaluated at 9.1, reflecting the high availability impact and ease of execution over a network. Since the Go SSH package is the fundamental library for several high-profile infrastructure applications, the downstream impact is wide.
Affected downstream products include popular orchestrators, container engines, and cloud agents. Programs like Docker, containerd, HashiCorp Vault, Prometheus, and various cloud log-collection daemons are affected if they negotiate raw data channels via SSH with untrusted endpoints. In multi-tenant environments, a single user running an exploit against an SSH-based service could cause a complete service disruption for all other tenants sharing the same physical host.
The definitive remediation for this vulnerability is to upgrade the golang.org/x/crypto dependency to version v0.52.0 or higher. This update introduces the fixed minPayloadSize logic, which natively handles sizes larger than 4 GiB without truncation.
For systems where immediate upgrades are not possible, defensive mitigations can be applied at the application layer. Implementing application-level chunking ensures that no single call to channel.Write() exceeds a safe limit, such as 1 GiB.
// Application-level safety wrapper
func SafeChannelWrite(ch ssh.Channel, data []byte) (int, error) {
const maxChunkSize = 1024 * 1024 * 1024 // 1 GiB
total := 0
for len(data) > 0 {
chunk := len(data)
if chunk > maxChunkSize {
chunk = maxChunkSize
}
n, err := ch.Write(data[:chunk])
total += n
if err != nil {
return total, err
}
data = data[n:]
}
return total, nil
}Additionally, system administrators should monitor for anomalous Go processes running at 100% CPU capacity with minimal network output. Static code analysis pipelines should be configured to run dependency check tools to identify packages importing vulnerable versions of the SSH library.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
golang.org/x/crypto Go Cryptography | < 0.52.0 | 0.52.0 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-190 |
| Attack Vector | Network |
| CVSS v3.1 Score | 9.1 (Critical) |
| EPSS Score | 0.00466 |
| Impact | Denial of Service (DoS) via 100% CPU exhaustion |
| Exploit Status | none |
| KEV Status | Not listed |
The software performs a calculation that can produce an integer overflow or wraparound, causing the logic to evaluate incorrectly or behave unpredictably.
A symbolic link directory traversal vulnerability was identified in go-git, a pure Go implementation of the Git specification. This vulnerability allows an attacker to construct a repository that, when checked out or processed, bypasses directory boundaries to write or overwrite arbitrary files on the host filesystem.
CVE-2026-71557 is a path traversal vulnerability in go-git, a pure-Go implementation of Git. In vulnerable versions, the filesystem-backed storage engine fails to validate reference names before mapping them to on-disk paths. An attacker hosting a malicious Git server can advertise references containing directory traversal sequences, such as 'refs/heads/../../config', to write or overwrite files outside the intended reference storage directory.
An information disclosure vulnerability in the Nuxt development server allows adjacent network attackers to retrieve the absolute project root directory and a persistent workspace UUID by querying the unprotected Chrome DevTools workspace endpoint. This occurs when the development server is bound to a network-reachable interface, allowing requests that bypass the header-based security verification checks.
A Regular Expression Denial of Service (ReDoS) vulnerability exists in SvelteKit's content negotiation header parser prior to version 2.70.2. An unauthenticated remote attacker can exploit this vulnerability by sending a crafted Accept header with highly repetitive malformed values. This triggers catastrophic backtracking on the single-threaded Node.js/Bun event loop, leading to CPU exhaustion and full denial of service.
An OS command injection vulnerability exists in the npm package loading component of the jsii-diff CLI tool within the AWS jsii framework. Prior to version 1.131.0, when parsing package specifiers prefixed with `npm:`, the tool concatenated user-controlled inputs directly into a shell execution string via child_process.exec. This allows attackers to execute arbitrary shell commands under the context of the running Node.js process.
CodeIgniter4 versions prior to v4.7.4 contain a protocol-spoofing vulnerability due to improper verification of upstream reverse proxy forwarding headers. Remote, unauthenticated attackers can inject headers like X-Forwarded-Proto to deceive the framework into identifying an insecure HTTP request as a secure HTTPS connection.