Back to Blog
high SEVERITY5 min read

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.

O
By Orbis AppSec
Published June 10, 2026Reviewed June 10, 2026

Answer Summary

CVE-2025-22869 is a high-severity Denial of Service vulnerability in Go's `golang.org/x/crypto/ssh` package (CWE-400) that allows attackers to consume excessive resources during the SSH key exchange handshake. The fix is to upgrade `golang.org/x/crypto` from v0.32.0 to v0.35.0 in your `go.mod` file, which includes the upstream patch that adds proper resource limits during the key exchange phase.

Vulnerability at a Glance

cweCWE-400 (Uncontrolled Resource Consumption)
fixUpgrade golang.org/x/crypto from v0.32.0 to v0.35.0
riskRemote attacker can crash or exhaust resources of any service using golang.org/x/crypto/ssh for SSH connections
languageGo
root causeInsufficient resource limits during the SSH key exchange phase in golang.org/x/crypto/ssh v0.32.0 and earlier
vulnerabilityDenial of Service in SSH Key Exchange

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

Introduction

In the cpdaemon service, we discovered a high-severity denial of service vulnerability stemming from its dependency on golang.org/x/crypto v0.32.0. This package provides the SSH implementation used by the daemon, and a flaw in the key exchange (kex) negotiation phase meant that a remote, unauthenticated attacker could exhaust server resources simply by initiating crafted SSH handshakes—no valid credentials required.

The vulnerable dependency was declared in cpdaemon/go.mod:

golang.org/x/crypto v0.32.0

This matters for any Go developer building services that accept SSH connections, tunnel traffic, or use SSH-based protocols for inter-service communication. The key exchange happens before authentication, meaning the attack surface is open to anyone who can reach the network port.

The Vulnerability Explained

What Happens During SSH Key Exchange?

When an SSH connection is established, the client and server perform a key exchange (kex) to agree on shared cryptographic secrets. This happens before any authentication. The process involves:

  1. Algorithm negotiation
  2. Diffie-Hellman (or similar) parameter exchange
  3. Key derivation

In golang.org/x/crypto/ssh v0.32.0 and earlier, the key exchange implementation did not properly limit the resources that could be consumed during this phase. An attacker could exploit this by:

  • Initiating multiple concurrent SSH connections that enter the kex phase
  • Sending specially crafted kex messages that force expensive computations
  • Holding connections in the kex phase without completing the handshake

Attack Scenario Specific to cpdaemon

The cpdaemon service uses golang.org/x/crypto/ssh as a direct dependency (not just transitive—it's listed in the require block). An attacker who can reach the daemon's SSH listener could:

  1. Open hundreds of connections to cpdaemon's SSH port
  2. Begin the key exchange on each connection but never complete it
  3. Force the daemon to allocate unbounded resources (goroutines, memory for kex state, CPU for cryptographic operations) for each pending handshake
  4. Eventually exhaust the daemon's resources, causing it to become unresponsive to legitimate connections

This is particularly dangerous because:
- No authentication is needed—the attack happens during the pre-auth handshake
- The attacker doesn't need to know any credentials or keys
- A single attacker machine can potentially take down the service

The Vulnerable go.mod

require (
    // ... other dependencies
    golang.org/x/crypto v0.32.0    // VULNERABLE - CVE-2025-22869
    golang.org/x/sync v0.12.0
    // ...
)

The Fix

The fix is straightforward but critical: upgrade golang.org/x/crypto from v0.32.0 to v0.35.0, which contains the upstream patch that adds proper resource bounds during the SSH key exchange phase.

Before (vulnerable):

golang.org/x/crypto v0.32.0
golang.org/x/sys v0.29.0 // indirect
golang.org/x/text v0.21.0 // indirect

After (fixed):

golang.org/x/crypto v0.35.0
golang.org/x/sys v0.30.0 // indirect
golang.org/x/text v0.22.0 // indirect

Why Multiple Files Changed

  1. cpdaemon/go.mod: Updated the declared dependency version from v0.32.0 to v0.35.0. Also updated golang.org/x/sys (v0.29.0 → v0.30.0) and golang.org/x/text (v0.21.0 → v0.22.0) because golang.org/x/crypto v0.35.0 requires these newer minimum versions of its sibling modules.

  2. cpdaemon/go.sum: Added the new checksums for v0.35.0 of golang.org/x/crypto and the updated transitive dependencies. The Go module system uses go.sum to verify download integrity, so these entries are essential.

What v0.35.0 Fixes Internally

The upstream fix in golang.org/x/crypto v0.35.0 adds proper resource controls during the SSH key exchange:
- Bounds on the number of concurrent key exchanges per connection
- Timeouts for incomplete kex negotiations
- Memory limits on kex message buffers

This ensures that an attacker cannot force unbounded resource allocation during the pre-authentication phase.

Prevention & Best Practices

  1. Pin and regularly update dependencies: Use go get -u golang.org/x/crypto@latest or tools like Dependabot/Renovate to stay current with security patches.

  2. Run vulnerability scanners in CI: Trivy, govulncheck, and Snyk can catch known CVEs in your dependency tree before they reach production.

  3. Implement defense in depth for SSH services:
    - Set ServerConfig.MaxStartups or equivalent connection limits
    - Use firewall rules to limit connection rates to SSH ports
    - Deploy SSH services behind a bastion or VPN when possible

  4. Monitor for resource exhaustion: Set alerts on goroutine counts, memory usage, and connection counts for services using golang.org/x/crypto/ssh.

  5. Use govulncheck for Go-specific analysis:
    bash go install golang.org/x/vuln/cmd/govulncheck@latest govulncheck ./...
    This tool checks not just whether you depend on a vulnerable module, but whether your code actually calls the vulnerable function paths.

Key Takeaways

  • Pre-auth attack surfaces are the most dangerous: CVE-2025-22869 requires zero credentials, making every exposed SSH port a potential target until patched.
  • cpdaemon/go.mod declared golang.org/x/crypto as a direct dependency, meaning the SSH functionality is core to the daemon—not an unused transitive dependency.
  • Transitive dependency bumps (x/sys, x/text) are often required when upgrading Go standard library extensions, since they maintain minimum version compatibility across the golang.org/x ecosystem.
  • Trivy correctly identified the vulnerable version in go.mod without needing to trace call paths—version-based detection caught this before any exploit attempt.
  • A three-version jump (v0.32.0 → v0.35.0) was necessary because the fix landed in v0.35.0, not in a patch to the v0.32.x line—Go's golang.org/x modules don't backport security fixes.

How Orbis AppSec Detected This

  • Source: Network connections reaching cpdaemon's SSH listener, initiating the key exchange protocol
  • Sink: The golang.org/x/crypto/ssh key exchange handler in the vulnerable v0.32.0 library, which processes unbounded kex messages without resource limits
  • Missing control: No resource bounds or timeouts on the SSH key exchange phase in golang.org/x/crypto v0.32.0
  • CWE: CWE-400 (Uncontrolled Resource Consumption)
  • Fix: Upgraded golang.org/x/crypto from v0.32.0 to v0.35.0 in cpdaemon/go.mod, which includes upstream resource limiting during SSH key exchange

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-2025-22869 is a reminder that cryptographic protocol implementations carry risk even in well-maintained libraries. The SSH key exchange phase—executed before any authentication—is a critical attack surface. By keeping golang.org/x/crypto updated and running continuous dependency scanning, you can ensure that your Go services aren't vulnerable to resource exhaustion attacks that require nothing more than a TCP connection to exploit.

For any service using golang.org/x/crypto/ssh, verify your version is at least v0.35.0 today. If you're still on v0.32.0 or earlier, you're exposed.

References

Frequently Asked Questions

What is a Denial of Service in SSH Key Exchange?

It's a vulnerability where an attacker initiates SSH connections and exploits the key exchange (kex) phase to consume excessive CPU, memory, or connection resources on the server, making it unavailable to legitimate users without needing valid credentials.

How do you prevent SSH Key Exchange DoS in Go?

Keep `golang.org/x/crypto` updated to at least v0.35.0, implement connection rate limiting, set SSH handshake timeouts, and use tools like Trivy to continuously scan dependencies for known CVEs.

What CWE is SSH Key Exchange DoS?

CWE-400 (Uncontrolled Resource Consumption), which covers scenarios where a system doesn't properly limit the resources allocated to processing requests, allowing attackers to cause resource exhaustion.

Is rate limiting enough to prevent SSH Key Exchange DoS?

Rate limiting helps reduce exposure but is not sufficient alone. The underlying library must properly bound resources during key exchange. Without the patched library, a single slow connection could still tie up resources disproportionately.

Can static analysis detect SSH Key Exchange DoS?

Yes, dependency scanners like Trivy, Snyk, and Govulncheck can detect known vulnerable versions of libraries. Trivy specifically flagged this CVE in the `cpdaemon/go.mod` file by matching the declared dependency version against the vulnerability database.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #210

Related Articles

high

How missing Dependabot cooldown happens in GitHub Actions and how to fix it

A high-severity configuration vulnerability was discovered in a `.github/dependabot.yml` file that lacked a cooldown period for package updates. Without this safeguard, Dependabot could immediately propose updates to newly published package versions—including potentially malicious or unstable releases. The fix adds a simple `cooldown` block with a 7-day waiting period before any new package version is suggested.

high

How Server-Sent Events Injection via Unsanitized Newlines happens in Node.js h3 and how to fix it

A high-severity Server-Sent Events (SSE) injection vulnerability (CVE-2026-33128) was discovered in the h3 HTTP framework, where unsanitized newline characters in event stream fields could allow attackers to inject arbitrary SSE messages. The fix upgrades h3 from version 1.15.5 to 1.15.6 in the frontend's dependency tree, ensuring that newline characters are properly sanitized before being written to event streams.

high

How Memory Exhaustion via Large Comma-Separated Selector Lists happens in Python Soup Sieve and how to fix it

A high-severity memory exhaustion vulnerability (CVE-2026-49476) was discovered in Soup Sieve version 2.8.3, affecting Python applications that parse CSS selectors from user-controlled input. The vulnerability allows attackers to craft malicious selector lists that consume excessive memory, potentially causing denial of service. The fix involves upgrading to soupsieve 2.8.4, which implements proper resource limits on selector parsing.

high

How prototype pollution via `__proto__` key happens in Node.js defu and how to fix it

A high-severity prototype pollution vulnerability (CVE-2026-35209) was discovered in the `defu` package version 6.1.4, which allowed attackers to inject properties into JavaScript's `Object.prototype` via the `__proto__` key in defaults arguments. The fix upgrades `defu` to version 6.1.5 in the frontend's dependency tree, protecting downstream consumers like `c12` and `dotenv` configuration loaders from malicious property injection.

critical

How buffer overflow in memcpy() happens in Node.js N-API bindings and how to fix it

A critical buffer overflow vulnerability was discovered in the GetBufferAsVector() function in examples_nodejs/src/zupt_napi.cpp, where memcpy() copied data from JavaScript Uint8Array buffers without proper bounds validation. This vulnerability could allow attackers to trigger memory corruption by providing maliciously crafted input arrays to the native Node.js module, potentially leading to crashes or arbitrary code execution.

high

How memory exhaustion via large comma-separated selector lists happens in Python soupsieve and how to fix it

A high-severity memory exhaustion vulnerability (CVE-2026-49476) was discovered in soupsieve 2.8.3, a CSS selector library used by BeautifulSoup in Python. An attacker who could influence CSS selector input could craft large comma-separated selector lists to exhaust system memory, causing denial of service. The fix upgrades soupsieve from 2.8.3 to 2.8.4 in the backend's `uv.lock` dependency file.