Remediation Guides

SSH Weak Key Exchange Algorithms Enabled: How to Fix It (Nessus 153953 and Logjam 86328)

26 September 2026 11 min read

The SSH weak key exchange algorithms enabled finding means your SSH server still offers SHA-1 or 1024-bit Diffie-Hellman key exchange methods, such as diffie-hellman-group1-sha1 or diffie-hellman-group-exchange-sha1. Fix it by setting an explicit KexAlgorithms line in sshd_config that lists only curve25519 and SHA-2 groups (on RHEL 8, where the stock crypto policy is the usual cause, by changing the policy instead), pruning small primes from /etc/ssh/moduli, restarting sshd and rescanning.

What the scanner is actually detecting

These are network checks. The scanner connects to the SSH port, reads the server’s KEXINIT message (the key exchange methods the server will accept) and compares it with a list of deprecated methods. No login is required. Each product names it differently:

Scanner Finding title Identifier
Nessus SSH Weak Key Exchange Algorithms Enabled Plugin 153953
Nessus SSH Diffie-Hellman Modulus <= 1024 Bits (Logjam) Plugin 86328 (CVE-2015-4000)
Greenbone / OpenVAS Weak Key Exchange (KEX) Algorithm(s) Supported (SSH) OID 1.3.6.1.4.1.25623.1.0.150713
Rapid7 SSH Server Supports Weak Key Exchange Algorithms ssh-weak-kex-algorithms
Qualys Deprecated SSH Cryptographic Settings QID 38739

Nessus plugin 153953 and the Greenbone check both follow RFC 9142 and flag these methods:

  • diffie-hellman-group1-sha1
  • diffie-hellman-group-exchange-sha1
  • gss-gex-sha1-*, gss-group1-sha1-* and gss-group14-sha1-* (GSSAPI key exchange)
  • rsa1024-sha1

Note what is missing: diffie-hellman-group14-sha1. RFC 9142 rates it MAY rather than SHOULD NOT, so plugin 153953 does not flag it, but stricter policies and other scanners often do. Plugin 86328 is narrower: it fires when the server will use a Diffie-Hellman prime of 1024 bits or less, either through the fixed 1024-bit group1 method or through group exchange handing out a small prime from /etc/ssh/moduli. It only runs when the scan policy’s Report Paranoia setting is Paranoid, which is one reason two scans of the same host can disagree. Upstream OpenSSH sshd already refuses group exchange primes below 2048 bits, so on a current OpenSSH server 86328 is realistically raised by diffie-hellman-group1-sha1 or by a non-OpenSSH SSH service. Qualys QID 38739 is broader still and also covers deprecated ciphers and other SSH settings, so fixing key exchange alone may not close it.

Real-world risk

Tenable rates both plugins Low (CVSS v3 base score 3.7). Nobody gets a shell from this finding; the concern is session confidentiality against a well-resourced attacker.

  • 1024-bit Diffie-Hellman (Logjam). The Logjam researchers estimated that a nation-state can break a 1024-bit prime after heavy precomputation, which would let it passively decrypt sessions that used that prime.
  • SHA-1 in the exchange hash. SHA-1 is no longer collision resistant and RFC 9142 moves most SHA-1 methods to SHOULD NOT. There is no widely known practical attack that breaks an SSH session just because the server offers a SHA-1 method; the problem is a shrinking safety margin.

Two protocol details limit exposure. The negotiated method is the first one on the client’s list that the server also supports, so modern clients, which list post-quantum hybrids and curve25519 ahead of any SHA-1 method, never pick the weak ones. And the host key signature covers both sides’ algorithm lists, so an attacker cannot quietly strip the strong options. The realistic risk is an old client silently using a weak method, plus audit pressure. The fix is cheap.

How to confirm it on the host

Start from the network side, since that is what the scanner sees:

# List what the server offers
nmap -p 22 --script ssh2-enum-algos 192.0.2.10

# Force one weak method; a host key or login prompt means it is still offered
ssh -o KexAlgorithms=diffie-hellman-group1-sha1 user@192.0.2.10
ssh -o KexAlgorithms=diffie-hellman-group-exchange-sha1 user@192.0.2.10

Then look at the server itself:

# Effective configuration after all Include files are merged
sudo sshd -T | grep -iE '^(kexalgorithms|gssapikeyexchange|gssapikexalgorithms)'

# Which file sets it
sudo grep -rinE 'kexalgorithms|gssapikeyexchange' /etc/ssh/sshd_config /etc/ssh/sshd_config.d/ 2>/dev/null

# Prime sizes available for group exchange (fifth field)
awk '$1 !~ /^#/ {print $5}' /etc/ssh/moduli | sort -n | uniq -c

The moduli file records sizes one below the nominal bit length (2047 for a 2048-bit prime, 3071 for a 3072-bit prime). Entries at 1023 are the 1024-bit primes that plugin 86328 cares about.

On RHEL, Rocky and AlmaLinux, the system-wide crypto policy usually supplies the algorithm lists:

update-crypto-policies --show
grep -oE '(GSSAPI)?KexAlgorithms[= ][^ ]+' /etc/crypto-policies/back-ends/opensshserver.config

On RHEL 8 and its rebuilds (Rocky, AlmaLinux and Oracle Linux 8), the stock DEFAULT crypto policy itself offers diffie-hellman-group-exchange-sha1 and diffie-hellman-group14-sha1 to sshd, plus gss-gex-sha1- and gss-group14-sha1- for GSSAPI key exchange. A fully patched RHEL 8 host is therefore flagged by plugin 153953 out of the box, with nobody having changed anything. LEGACY produces the same key exchange list there, so seeing DEFAULT does not rule the policy out. On RHEL 9, DEFAULT contains no SHA-1 key exchange; there the finding usually means LEGACY, the SHA1 subpolicy, an explicit KexAlgorithms line or GSSAPI key exchange. On RHEL 8 the policy is handed to sshd at startup through the CRYPTO_POLICY variable, so running sshd -T by hand may not reflect it; trust the nmap output there.

How to fix it

Step 1: back up and check what your build supports

sudo cp -a /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%F)
sudo cp -a /etc/ssh/moduli /etc/ssh/moduli.bak.$(date +%F)
ssh -Q kex

ssh -Q kex lists the methods your installed OpenSSH build knows. Only put names from that list into KexAlgorithms, because sshd refuses to start on a name it does not recognize.

Step 2: set an explicit KexAlgorithms line

sshd uses the first value it reads for each keyword, and on most current distributions sshd_config starts with Include /etc/ssh/sshd_config.d/*.conf. A line appended to the bottom of sshd_config can therefore be silently overridden. Use an early-sorting drop-in instead, for example /etc/ssh/sshd_config.d/10-kex-hardening.conf:

KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256

If ssh -Q kex shows post-quantum hybrids such as mlkem768x25519-sha256 or sntrup761x25519-sha512@openssh.com, you can put them at the front; recent OpenSSH releases include them in the default list. If your sshd_config has no Include line (older releases), put the directive near the top of sshd_config, above any Match block.

Step 3: handle GSSAPI key exchange

If sshd -T reports gssapikeyexchange yes, the server may also offer gss-gex-sha1- and gss-group14-sha1-; check the gssapikexalgorithms value in the same output. The Debian and Ubuntu default for that list includes both SHA-1 methods, the RHEL 9 DEFAULT policy includes neither, and the server only advertises GSSAPI key exchange when it holds usable host Kerberos credentials (a host keytab). The GSSAPIKeyExchange keyword exists only in distribution builds that carry the GSSAPI key exchange patch, such as Debian, Ubuntu and the Red Hat family, and its default is no. If you do not rely on Kerberos-based host verification, turn it off (GSSAPIAuthentication for user logins is a separate setting and keeps working):

GSSAPIKeyExchange no

If you do need it, restrict it to SHA-2 methods instead:

GSSAPIKexAlgorithms gss-curve25519-sha256-,gss-nistp256-sha256-,gss-group14-sha256-,gss-group16-sha512-

On RHEL 8, a GSSAPIKexAlgorithms line in sshd_config is overridden by the crypto policy in the same way as KexAlgorithms. It takes effect only after you opt sshd out of the policy (CRYPTO_POLICY=, see Step 5); alternatively, DEFAULT:NO-SHA1 removes the gss-*-sha1 methods through the policy itself.

Step 4: remove small primes for the Logjam finding (86328)

The /etc/ssh/moduli file is only used by the diffie-hellman-group-exchange methods. On current upstream OpenSSH, pruning it is defense in depth: sshd already refuses group exchange primes below 2048 bits (DH_GRP_MIN, following RFC 8270), so a 1023 entry is never handed out. It matters mainly on old or non-OpenSSH builds, and it keeps the file clean if someone re-adds group exchange later. As root:

awk '$5 >= 3071' /etc/ssh/moduli > /etc/ssh/moduli.safe && mv /etc/ssh/moduli.safe /etc/ssh/moduli
chown root:root /etc/ssh/moduli && chmod 644 /etc/ssh/moduli
restorecon -v /etc/ssh/moduli   # SELinux systems only
wc -l /etc/ssh/moduli

This keeps 3072-bit and larger primes. Confirm the file still has entries (wc -l). sshd starts without them, because it reads the file only when group exchange is negotiated, but clients that negotiate a diffie-hellman-group-exchange method would then be disconnected with “no matching DH grp found”. On SELinux hosts such as the RHEL family, restorecon resets the label on the file you just replaced. Removing diffie-hellman-group1-sha1 (a fixed 1024-bit group) in Step 2 is the other half of this fix.

Step 5: RHEL 8 and RHEL 9 with crypto-policies

  • RHEL 9 family: the policy is pulled in by /etc/ssh/sshd_config.d/50-redhat.conf. Red Hat’s RHEL 9 documentation says a drop-in with a two-digit prefix lower than 50 takes precedence, so the 10-kex-hardening.conf file from Step 2 works as is.
  • RHEL 8 family, policy route: here the stock DEFAULT policy is usually the source of the finding, and KexAlgorithms in sshd_config is overridden while the policy is active. update-crypto-policies –set DEFAULT:NO-SHA1 removes diffie-hellman-group-exchange-sha1 and diffie-hellman-group14-sha1 (and the gss-*-sha1 GSSAPI methods) from sshd, which closes 153953 while keeping central policy management. Red Hat’s documentation describes NO-SHA1 as disabling SHA-1 in signatures, but the module also removes SHA-1 from the policy’s hash list, and the sshd configuration it generates contains no SHA-1 key exchange method. It also disables SHA-1 signatures system-wide: ssh-rsa host and user key signatures, and SHA-1-signed certificates in TLS. Test it on a non-critical host first, then reboot.
  • RHEL 8 family, custom module: for a narrower change, write your own module. The file name must be upper case with a .pmod extension, for example /etc/crypto-policies/policies/modules/NO-SSH-SHA1.pmod containing the single scoped line hash@SSH = -SHA1, which drops SHA-1 key exchange for SSH only. Apply it with update-crypto-policies –set DEFAULT:NO-SSH-SHA1 and reboot.
  • RHEL 8 family, opt-out route: to manage sshd outside the policy, uncomment CRYPTO_POLICY= in /etc/sysconfig/sshd, then set KexAlgorithms near the top of /etc/ssh/sshd_config. Opting out stops sshd taking Ciphers, MACs, HostKeyAlgorithms, PubkeyAcceptedKeyTypes, CASignatureAlgorithms and GSSAPIKexAlgorithms from the policy. They fall back to compiled-in defaults, which for OpenSSH 8.0 include ssh-rsa (SHA-1) signatures, so set the ones your hardening baseline requires explicitly.

Whichever policy route you take, check what sshd will receive:

grep -oE '(GSSAPI)?KexAlgorithms[= ][^ ]+' /etc/crypto-policies/back-ends/opensshserver.config

Step 6: validate and restart

sudo sshd -t && sudo systemctl restart sshd   # RHEL family, SUSE
sudo sshd -t && sudo systemctl restart ssh    # Debian, Ubuntu

Keep your current session open and confirm a new login works from a second terminal before you disconnect. For switches, firewalls, Dropbear and other non-OpenSSH servers, Tenable’s advice applies: follow the vendor’s documentation for disabling the weak methods.

How to verify the fix and rescan

  1. Run sshd -T again and confirm kexalgorithms matches your new line.
  2. From another machine, run the nmap ssh2-enum-algos command and confirm no sha1 method or group1 method appears.
  3. Repeat the forced ssh -o KexAlgorithms=… tests. The expected result is “no matching key exchange method found”.
  4. Rescan with the same scanner and policy that raised the finding. If you also run credentialed checks, confirm the scanner still logs in afterwards; our guide to SSH credentials for Linux authenticated scans covers that setup.

What can break and how to roll back

Anything that can only negotiate SHA-1 or 1024-bit key exchange will fail to connect: old SFTP and backup clients, embedded SSH libraries in monitoring tools, and outdated network devices. The server log shows who is affected:

sudo journalctl -u sshd -u ssh --since today | grep -i 'no matching key exchange'

Update the client where possible. If you cannot, document an exception and restrict that host’s SSH port to the legacy client’s address with a host firewall rather than weakening every server. To roll back, delete the drop-in file (or restore sshd_config.bak), restore moduli.bak, re-comment CRYPTO_POLICY= on RHEL 8 (or return to the previous policy with update-crypto-policies –set DEFAULT and reboot), run sshd -t and restart. Keep console or out-of-band access available while you work.

Common false positive reasons

Before calling it a false positive, rule out these causes. For the wider picture, see our breakdown of why vulnerability scanners report false positives.

  • sshd was not restarted, or the scan ran before the change.
  • First value wins: an earlier drop-in, or the crypto policy on RHEL 8, overrides your line. sshd -T and nmap settle it.
  • A different SSH server answered: an appliance service, container, SFTP application or second daemon on another port that sshd_config does not control.
  • NAT or a load balancer forwards port 22 to a host you did not change.
  • Scanner scope differs: one tool flags diffie-hellman-group14-sha1 and another does not, or Qualys QID 38739 remains open because of ciphers or other settings rather than key exchange. Plugin 86328 also appears only in scans whose policy has Report Paranoia set to Paranoid.

FAQ

Is diffie-hellman-group14-sha1 weak?

It uses a 2048-bit group but SHA-1 for the exchange hash. RFC 9142 rates it MAY and Nessus plugin 153953 does not flag it, but current OpenSSH no longer enables it by default. Remove it unless a client you cannot upgrade needs it.

Why does a fully patched OpenSSH still get flagged?

OpenSSH has disabled diffie-hellman-group1-sha1 by default since version 7.0, and current upstream defaults contain no SHA-1 key exchange. A server that still offers them usually gets them from vendor defaults (for example the RHEL 8 DEFAULT crypto policy, which keeps diffie-hellman-group-exchange-sha1), an explicit KexAlgorithms line, a LEGACY crypto policy or GSSAPI key exchange. Non-OpenSSH servers on appliances are the other common case.

Does pruning /etc/ssh/moduli fix the Logjam finding on its own?

No. diffie-hellman-group1-sha1 uses a fixed 1024-bit group that does not come from the moduli file, so it must be removed from KexAlgorithms as well.

Do I need a reboot?

Not for sshd_config changes; restarting sshd is enough. Red Hat recommends a reboot after changing the system-wide crypto policy so that every service picks it up.

Tracking this finding across many hosts

This finding often appears on many hosts at once, so the hard part is proving every one is closed. SITEY is a self-hosted vulnerability management platform that imports findings from 16 scanners (Nessus results by uploading a .nessus export) and merges duplicates per scanner. Its AI can draft host-specific remediation scripts, such as the KexAlgorithms change above, that run on Linux endpoints through its agents only after human approval, and then re-tests to verify closure, with per-finding retest available for Nessus findings.

Sources

SITEY closes the loop, not just the report.Discover, validate, fix and verify in your own infrastructure.

See pricing