Back to Blog
high SEVERITY9 min read

How Denial of Service via Resource Leaks Happens in Go SSH Libraries and How to Fix It

A Denial of Service vulnerability in `golang.org/x/crypto/ssh` (CVE-2026-39830) allowed attackers to exhaust server resources by sending unsolicited SSH responses that were never properly cleaned up. The fix upgrades `golang.org/x/crypto` from `v0.50.0` to `v0.52.0` in `go.mod`, patching the resource leak in the SSH package's response handling logic. Any Go application that uses the `golang.org/x/crypto/ssh` package for SSH client or server functionality was potentially exposed.

O
By Orbis AppSec
Published August 6, 2026Reviewed August 6, 2026

Answer Summary

CVE-2026-39830 is a high-severity Denial of Service vulnerability in the `golang.org/x/crypto/ssh` package (Go), caused by a resource leak when the SSH implementation fails to properly discard or clean up unsolicited SSH responses. This maps to CWE-400 (Uncontrolled Resource Consumption). The fix is to upgrade `golang.org/x/crypto` from `v0.50.0` to `v0.52.0` in your `go.mod` file, which patches the SSH response handling logic to prevent goroutine or memory leaks triggered by malicious or unexpected server/client messages.

Vulnerability at a Glance

cweCWE-400
fixUpgrade golang.org/x/crypto from v0.50.0 to v0.52.0 in go.mod, which patches the SSH response handler to release resources for unsolicited messages
riskAttacker can exhaust server memory or goroutines by sending unsolicited SSH protocol responses, causing service unavailability
languageGo
root causeThe golang.org/x/crypto/ssh package did not properly discard or clean up resources allocated for unexpected/unsolicited SSH response messages
vulnerabilityDenial of Service via resource leak from unsolicited SSH responses

How Denial of Service via Resource Leaks Happens in Go SSH Libraries and How to Fix It

The Incident

In a Go project's go.mod, a dependency pinned to golang.org/x/crypto v0.50.0 quietly harbored a high-severity vulnerability: CVE-2026-39830. The golang.org/x/crypto/ssh package — widely used across Go applications for SSH client and server functionality — contained a resource leak triggered by unsolicited SSH responses. An attacker who could send unexpected SSH messages to an affected application could force it to accumulate unreleased resources until the process became unresponsive or crashed.

The fix was a targeted dependency upgrade: bumping golang.org/x/crypto from v0.50.0 to v0.52.0 in go.mod. But understanding why this matters requires a closer look at how SSH protocol handling and resource management interact in Go.


The Vulnerability Explained

What Are "Unsolicited SSH Responses"?

The SSH protocol is a request-response protocol, but it also supports server-initiated messages — things like channel data pushes, keepalive requests, and global requests. A well-behaved SSH peer only sends responses to requests that were actually made. A malicious or buggy peer, however, can send responses that were never requested.

In golang.org/x/crypto/ssh prior to v0.52.0, when the SSH implementation received one of these unsolicited responses, it allocated internal resources — goroutines waiting on channels, buffered data structures, or pending reply channels — to handle the incoming message. The critical flaw: these resources were never released when the message turned out to be unsolicited or unexpected.

The Vulnerable Dependency in go.mod

The vulnerable state of the project's go.mod looked like this:

// go.mod (vulnerable)
require (
    golang.org/x/crypto v0.50.0
    golang.org/x/net v0.53.0
    golang.org/x/sys v0.43.0 // indirect
    golang.org/x/text v0.36.0
)

The golang.org/x/crypto v0.50.0 line is the entry point for the vulnerability. Any code path in the application that imports golang.org/x/crypto/ssh — whether to dial SSH servers, accept SSH connections, or tunnel traffic — inherited this flawed response-handling behavior.

How an Attacker Exploits This

Consider a Go application that uses golang.org/x/crypto/ssh to accept inbound SSH connections — for example, a bastion host, an SFTP server, or a Git hosting backend. An attacker connects and, instead of completing a normal SSH handshake or session, begins flooding the server with unsolicited global request responses or channel open confirmations that the server never requested.

Each unsolicited message causes the SSH package to:
1. Allocate a pending reply structure or goroutine to "wait" for the response to be processed.
2. Never clean it up, because there's no corresponding request to match it against.

Over time — or very quickly with a high-volume flood — the server accumulates thousands of leaked goroutines and unreleased channel buffers. Go's runtime does not garbage-collect goroutines that are blocked waiting on a channel; they persist indefinitely. The result is memory exhaustion, goroutine exhaustion, or both, leading to a complete Denial of Service for all users of the application.

This attack requires no authentication if the leak occurs during the pre-authentication phase of the SSH handshake, making it particularly dangerous. Even if authentication is required, a single valid credential (or a compromised account) is sufficient to trigger the DoS.

Real-World Impact

For this specific application — which uses testcontainers-go (also present in go.mod) and likely communicates with container infrastructure over SSH or uses crypto primitives — a DoS attack could:

  • Take down container orchestration or CI/CD pipelines.
  • Exhaust memory on shared infrastructure, affecting other services on the same host.
  • Trigger cascading failures if the SSH component is on a critical path (e.g., secret retrieval, remote execution).

The Fix

What Changed in go.mod and go.sum

The fix is a precise, minimal dependency upgrade. Here is the before-and-after from the actual PR diff:

Before (vulnerable):

// go.mod
golang.org/x/crypto v0.50.0
golang.org/x/net v0.53.0
golang.org/x/sys v0.43.0 // indirect
golang.org/x/text v0.36.0

After (patched):

// go.mod
golang.org/x/crypto v0.52.0
golang.org/x/net v0.54.0
golang.org/x/sys v0.45.0 // indirect
golang.org/x/text v0.37.0

And the corresponding go.sum hash entries were updated to reflect the new verified module versions:

// go.sum (before)
golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=
golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q=

// go.sum (after)
golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988=
golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc=

Why Each Change Was Necessary

golang.org/x/crypto v0.50.0v0.52.0: This is the primary security fix. Version v0.52.0 patches the SSH package's internal message dispatch loop to properly discard and release resources associated with unsolicited responses. Instead of leaving goroutines blocked on unreachable channels, the patched code detects that no pending request corresponds to the incoming response and immediately frees the associated resources.

golang.org/x/net v0.53.0v0.54.0: The golang.org/x/net package is a transitive dependency of golang.org/x/crypto. Bumping x/crypto to v0.52.0 required a compatible x/net version to satisfy Go module dependency resolution, ensuring no version conflicts in the module graph.

golang.org/x/sys v0.43.0v0.45.0 and golang.org/x/text v0.36.0v0.37.0: These indirect dependencies follow the same pattern — they are pulled in transitively and needed version bumps to maintain a consistent, compatible module graph after the primary upgrade.

How the Fix Solves the Problem

The patched golang.org/x/crypto/ssh package adds proper cleanup logic in the SSH mux/demux layer. When an incoming message arrives and no pending request is found to match it, the response handler now explicitly:

  1. Reads and discards the message payload (preventing buffer accumulation).
  2. Does not allocate a waiting goroutine or reply channel.
  3. Logs or silently drops the unsolicited message, depending on configuration.

This means an attacker sending thousands of unsolicited responses gets no resource allocation on the server side — the messages are consumed and discarded without leaving any lasting footprint.


Prevention & Best Practices

1. Use govulncheck as Part of Your CI Pipeline

Go's official vulnerability checker, govulncheck, scans your module graph against the Go vulnerability database and reports only vulnerabilities that affect code paths actually called by your application:

go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./...

This would have flagged golang.org/x/crypto v0.50.0 as vulnerable before it reached production.

2. Keep golang.org/x/ Packages Updated Regularly

The golang.org/x/ packages (crypto, net, sys, text) are maintained by the Go team and receive security patches frequently. Unlike the Go standard library, they are not bundled with the Go toolchain — they must be explicitly upgraded. Add a recurring task to your dependency maintenance workflow:

go get golang.org/x/crypto@latest
go get golang.org/x/net@latest
go mod tidy

3. Audit SSH Handler Code for Resource Cleanup

If you write custom SSH protocol handlers using golang.org/x/crypto/ssh, ensure every code path that allocates a channel or goroutine for an incoming message has a corresponding cleanup:

// Risky pattern: goroutine allocated but may never be signaled
go func() {
    reply := <-pendingReplies // blocks forever if no reply arrives
    process(reply)
}()

// Safer pattern: use a context or timeout
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
select {
case reply := <-pendingReplies:
    process(reply)
case <-ctx.Done():
    // Clean up and return — don't leak the goroutine
    return
}

4. Pin and Verify go.sum Hashes

The go.sum file contains cryptographic hashes of every module version used. Always commit go.sum to version control and verify it in CI. The hash change from:

golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI=

to:

golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988=

provides a tamper-evident record that the correct patched version is in use.

5. Use Trivy or Similar SCA Scanners

The vulnerability was originally flagged by Trivy's Software Composition Analysis (SCA) scanner against go.mod. Integrate Trivy into your CI/CD pipeline:

trivy fs --scanners vuln .

This scans go.mod and go.sum for known CVEs in all direct and transitive dependencies.

Security Standards Reference

  • CWE-400: Uncontrolled Resource Consumption — the root cause of this DoS class.
  • OWASP A05:2021 – Security Misconfiguration: Outdated or unpatched dependencies fall under this category.
  • OWASP Dependency-Check: Recommended tooling for automated dependency vulnerability scanning.

Key Takeaways

  • Unsolicited SSH messages are an attack vector: Any SSH implementation must handle unexpected protocol messages defensively, including proper resource cleanup for messages that don't match any pending request.
  • golang.org/x/crypto is not part of the Go standard library and must be explicitly upgraded — it does not receive automatic security patches when you update your Go toolchain.
  • The go.sum hash change is security-critical: The new hash h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= for v0.52.0 verifies you are running the patched code, not a downgraded or tampered version.
  • Transitive dependency bumps (x/net, x/sys, x/text) were required to maintain a consistent module graph — a reminder that security upgrades can have ripple effects that must be managed with go mod tidy.
  • Trivy's SCA scan on go.mod caught this before exploitation — static dependency scanning is a first line of defense for supply chain vulnerabilities in Go projects.

How Orbis AppSec Detected This

  • Source: The go.mod file declaring golang.org/x/crypto v0.50.0 as a direct dependency, which is consumed by any code path importing golang.org/x/crypto/ssh — including SSH client/server initialization and session handling.
  • Sink: The SSH mux/demux response handler inside golang.org/x/crypto/ssh that allocates goroutines and reply channels for incoming SSH protocol messages without a corresponding cleanup path for unsolicited responses.
  • Missing control: No guard against resource allocation for SSH messages that have no matching pending request; the response handler lacked a discard-and-free code path for unexpected message types.
  • CWE: CWE-400 — Uncontrolled Resource Consumption.
  • Fix: Upgraded golang.org/x/crypto from v0.50.0 to v0.52.0 in go.mod and updated go.sum hashes, with coordinated bumps of golang.org/x/net, golang.org/x/sys, and golang.org/x/text to maintain module graph consistency.

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.


Conclusion

CVE-2026-39830 is a sharp reminder that Denial of Service vulnerabilities don't always require complex exploit chains — sometimes a resource leak in a well-trusted library is all it takes. The golang.org/x/crypto/ssh package's failure to clean up resources for unsolicited SSH responses turned routine network traffic into a potential availability attack. The fix is straightforward: upgrade to v0.52.0. But the broader lesson is about dependency hygiene — the golang.org/x/ ecosystem moves quickly, and staying current is a security obligation, not just a best-practice suggestion.

For Go developers building anything that touches SSH — whether it's infrastructure tooling, container management, or remote execution systems — treat golang.org/x/crypto version pinning as a first-class security concern and integrate automated scanning into your pipeline.


References

Frequently Asked Questions

What is a resource leak Denial of Service in an SSH library?

It occurs when an SSH implementation allocates memory or goroutines to handle incoming messages but fails to release those resources when the messages are unexpected or unsolicited, allowing an attacker to exhaust server resources by repeatedly sending such messages.

How do you prevent resource leak DoS in Go SSH code?

Always ensure that every allocated channel, goroutine, or buffer associated with an incoming SSH message has a corresponding cleanup path, even for unexpected or unsolicited messages. Use the patched version of golang.org/x/crypto (v0.52.0+) and audit custom SSH handlers for similar patterns.

What CWE is a resource leak Denial of Service?

CWE-400: Uncontrolled Resource Consumption, which describes situations where a program does not properly control the amount of resources it allocates in response to an input, enabling exhaustion attacks.

Is rate limiting enough to prevent this type of DoS?

Rate limiting helps reduce the attack surface but is not sufficient on its own. The underlying resource leak must be patched; otherwise, even a slow trickle of unsolicited messages could eventually exhaust resources. The correct fix is to upgrade to golang.org/x/crypto v0.52.0.

Can static analysis detect resource leak DoS vulnerabilities in Go?

Yes, tools like Trivy (which flagged this exact CVE in go.mod), govulncheck, and Semgrep can detect known vulnerable dependency versions. For novel resource leaks, Go's race detector and profiling tools (pprof) can help identify goroutine or memory leaks during testing.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #6152

Related Articles

high

How SSH channel exhaustion happens in Go crypto and how to fix it

CVE-2026-39827 is a high-severity resource exhaustion vulnerability in `golang.org/x/crypto` where an authenticated SSH client can repeatedly open channels to consume server resources without bound. The vulnerability was present in the `cloud/gcp/functions/acmedns` module at version `v0.49.0` and was resolved by upgrading to `v0.52.0`. Left unpatched, this flaw could allow an attacker with valid SSH credentials to degrade or deny service to other users of the affected GCP Cloud Function.

high

How improper handling of case sensitivity happens in Go MCP SDK and how to fix it

A high-severity vulnerability (CVE-2026-27896) in the Model Context Protocol Go SDK v1.3.0 allowed attackers to bypass security controls through improper handling of case sensitivity. The fix upgrades the dependency from v1.3.0 to v1.3.1, which correctly normalizes case comparisons. This vulnerability was particularly concerning for CLI tools where attackers could manipulate input to evade validation logic.

high

How Denial of Service in SSH Key Exchange happens in Go golang.org/x/crypto and how to fix it

A high-severity denial of service vulnerability (CVE-2025-22869) was discovered in the SSH key exchange implementation of Go's `golang.org/x/crypto` library. The `cpdaemon` service depended on the vulnerable version v0.32.0, which could allow an attacker to exhaust server resources during the SSH handshake phase. The fix upgrades the dependency to v0.35.0, which includes the upstream patch for this vulnerability.

high

Authorization Bypass in gRPC-Go HTTP/2 Path Validation (CVE-2026-33186)

A critical authorization bypass vulnerability (CVE-2026-33186) in `google.golang.org/grpc` v1.79.1 allowed attackers to circumvent gRPC authorization policies through malformed HTTP/2 path values. The fix upgrades the dependency in `src/go/go.mod` from v1.79.1 to v1.79.3, closing a path validation gap in the `grpc-go/authz` middleware that could have exposed protected RPC endpoints to unauthorized callers.

critical

Go JOSE DoS Vulnerability: Fixing JWE Object Exploitation in Rclone

A high-severity Denial of Service vulnerability (CVE-2026-34986) was discovered in the `github.com/go-jose/go-jose/v4` library, which Rclone depends on for JSON Web Encryption operations. An attacker could craft a malicious JWE object to exhaust server resources and bring down services. The fix is a targeted dependency upgrade from v4.1.3 to v4.1.4 — a minimal change with significant security impact.

high

How Remote Code Execution via serialize-javascript happens in Node.js and how to fix it

A high-severity Remote Code Execution (RCE) vulnerability in the `serialize-javascript` package (version 6.0.2) allowed attackers to inject malicious code through prototype poisoning of `RegExp.flags` and `Date.prototype.toISOString()`. The fix upgrades the dependency to version 7.0.3, which eliminates the unsafe serialization patterns and removes the now-unnecessary `randombytes` dependency.