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

Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #210

Related Articles

critical

deleteNestedProperty Prototype Pollution via Dot-Notation Path

The `deleteNestedProperty` function in propertyUtils.ts allowed attackers to manipulate JavaScript object prototypes by passing specially crafted dot-notation paths like `__proto__.polluted`. A fix now blocks dangerous keys before processing, preventing prototype pollution attacks that could affect all objects in the application.

high

How Denial of Service via Infinite Loop Happens in JavaScript Dependencies and How to Fix It

CVE-2026-67213 is a high-severity denial of service vulnerability in nanoid before version 5.1.6 that triggers an infinite loop during random ID generation when processing specially crafted input. We upgraded nanoid across the entire dependency tree to patch this flaw and prevent attackers from freezing application threads. This fix ensures that ID generation remains resilient even when handling adversarial input patterns.

high

How Sensitive Data Exposure happens in Zotero plugins and how to fix it

A high-severity data exposure vulnerability in `Zotero.ts` automatically transmitted complete document metadata—including private notes, attachment paths, and tags—to external LLM services without user consent. The fix replaces broad `item.toJSON()` serialization with explicit field selection, sending only essential bibliographic data.

high

How missing dependency update cooldowns happen in GitHub Dependabot configurations and how to fix it

A semgrep scan flagged `.github/dependabot.yml` for lacking a cooldown period, meaning Dependabot would immediately propose updates to brand-new package versions across npm, Bundler, and Docker ecosystems. The fix adds a `cooldown: default-days: 7` block to every `package-ecosystem` entry, forcing a one-week waiting period before newly published releases are considered — reducing exposure to malicious or unstable package drops.

high

How Path Traversal Happens in TensorFlow's Data Service and How to Fix It

TensorFlow's data service dispatcher validated dataset IDs against forward-slash traversal attacks but overlooked backslash characters on non-Windows platforms, allowing attackers to escape the root directory. A targeted fix adds explicit backslash validation across all platforms, closing a high-severity path traversal vulnerability in the snapshot management system.

critical

How Unbounded WebSocket Message Handling Causes Resource Exhaustion in Node.js and How to Fix It

The WebSocketCrossServerAdapter class in a popular Node.js WebSocket library lacked any rate limiting on inbound messages, allowing attackers to flood Redis nodes and WebSocket servers with high-volume traffic. The fix introduces a configurable `rateLimit` option that caps messages per connection per second, preventing resource exhaustion while preserving legitimate functionality.