Why SSH findings matter
SSH is the front door to the server itself. A weakness in your web application exposes the application; a weakness in SSH exposes everything on the machine — the database, the certificates, the backups and any other site hosted alongside it.
The findings in this guide are reported from the algorithms your server actually offers during a handshake, not from its version banner. That distinction matters, and section 4 explains why it is the single most common source of false alarms in SSH scanning.
Fix: Terrapin (CVE-2023-48795)
Terrapin is a prefix truncation attack against the SSH transport protocol itself, disclosed in December 2023. An attacker who can sit on the network path — a compromised router, a hostile Wi-Fi network, a malicious ISP — can silently delete messages at the very beginning of the connection. Neither the client nor the server notices, and the connection continues with weaker integrity protection than both sides believe they negotiated.
It applies when the server offers chacha20-poly1305@openssh.com, or a CBC cipher
together with an Encrypt-then-MAC algorithm, and does not advertise strict key exchange.
The fix: update OpenSSH
OpenSSH 9.6 introduced strict key exchange, which closes the attack for both sides that support it.
# Debian / Ubuntu
sudo apt update && sudo apt install --only-upgrade openssh-server
# RHEL / AlmaLinux / Rocky / CentOS
sudo dnf update openssh-server
sudo systemctl restart sshd
If you cannot update yet
Remove the affected algorithms. This is effective, but updating is still the correct fix.
# /etc/ssh/sshd_config
Ciphers aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-256,hmac-sha2-512
Note what this leaves out: no chacha20-poly1305, no -cbc ciphers, and no
-etm MACs. Validate and restart:
sudo sshd -t && sudo systemctl restart sshd
Fix: Outdated ciphers, MACs and key exchange
Most SSH servers still offer algorithms kept for compatibility with clients that no longer exist in practice. The weakest algorithm a server accepts is the real protection level, because the client chooses.
| Algorithm | Problem |
|---|---|
diffie-hellman-group1-sha1 | 1024-bit group, considered breakable by well-resourced attackers |
diffie-hellman-group-exchange-sha1 | SHA-1 in the key exchange |
3des-cbc, blowfish-cbc, cast128-cbc | Obsolete ciphers, small block size, CBC mode issues |
arcfour, arcfour128, arcfour256 | RC4 — broken, removed from every modern protocol |
hmac-md5, hmac-sha1-96 | Broken or truncated message authentication |
Pin a modern set explicitly:
# /etc/ssh/sshd_config
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512
Ciphers aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256
HostKeyAlgorithms ssh-ed25519,rsa-sha2-512,rsa-sha2-256
Compatibility note. Every OpenSSH client from 7.x onwards, PuTTY 0.68+, WinSCP, FileZilla and all current CI runners support these. If you have an appliance or a legacy deployment script that breaks, add the single algorithm it needs rather than reverting the whole block.
The version-number trap
This is the most misunderstood part of SSH scanning, and it is worth understanding before you act on any vulnerability report — including ours.
Enterprise Linux distributions do not upgrade software versions inside a release. When a CVE is published, RHEL, AlmaLinux, Rocky, Debian and Ubuntu LTS backport the fix into the version they already ship. The package is patched; the version string does not change.
The practical consequence: a fully patched server can report OpenSSH 8.0 and appear, to
any scanner matching CVEs against version numbers, to be vulnerable to a long list of issues it is
immune to. Check the real package version:
# RHEL / AlmaLinux / Rocky / CentOS
rpm -q openssh-server
rpm -q --changelog openssh-server | head -30 # shows backported CVE fixes
# Debian / Ubuntu
dpkg -l | grep openssh-server
zcat /usr/share/doc/openssh-server/changelog.Debian.gz | head -30
Compare that against your distribution's security advisory for the CVE — not against the upstream version number. This is why our Terrapin finding is determined from the algorithms your server offers during a real handshake: the handshake cannot be backported away, so the answer is the same whichever distribution you run.
Reduce exposure: the fix that outlasts every CVE
Everything above hardens SSH against known problems. Restricting who can reach it protects you against the ones not yet published.
Very few servers genuinely need to accept SSH from the entire internet. Administration usually comes from a handful of known addresses, an office network, or a VPN.
# UFW (Debian / Ubuntu)
sudo ufw allow from 203.0.113.10 to any port 22 proto tcp
sudo ufw deny 22
# firewalld (RHEL family)
sudo firewall-cmd --permanent --remove-service=ssh
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.10" service name="ssh" accept'
sudo firewall-cmd --reload
Before you apply this, confirm the address you are connecting from — locking yourself out of a remote server is the most common self-inflicted outage there is. Most cloud providers, including Hetzner, DigitalOcean and AWS, offer a browser console that bypasses SSH entirely, so keep that route in mind before changing firewall rules.
Changing the SSH port is often suggested. It reduces log noise from automated scanning, but it is not a security control — a port scan finds the new port in seconds. Do it for tidiness, not for protection.
A complete hardened sshd_config
Every directive below addresses a finding this scanner reports, or a common weakness behind one.
# /etc/ssh/sshd_config
# --- Cryptography ---
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512
Ciphers aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
HostKeyAlgorithms ssh-ed25519,rsa-sha2-512,rsa-sha2-256
# --- Authentication ---
PermitRootLogin prohibit-password
PasswordAuthentication no
PubkeyAuthentication yes
PermitEmptyPasswords no
MaxAuthTries 3
LoginGraceTime 30
# --- Reduce attack surface ---
X11Forwarding no
AllowAgentForwarding no
AllowTcpForwarding no
PermitTunnel no
# --- Session hygiene ---
ClientAliveInterval 300
ClientAliveCountMax 2
~/.ssh/authorized_keys and
confirm key-based login works, or PasswordAuthentication no will lock you out. Validate
with sudo sshd -t, restart, then open a second terminal and connect before
closing the first.
Verify your changes
Check what your server offers after restarting — this is the same method the scanner uses:
# What algorithms does the server actually offer?
nmap -p 22 --script ssh2-enum-algos yourdomain.com
# Is strict key exchange (the Terrapin fix) advertised?
nmap -p 22 --script ssh2-enum-algos yourdomain.com | grep kex-strict
# Verbose handshake from a client
ssh -vv yourdomain.com 2>&1 | grep -i "kex:\|cipher:\|mac:"
Then re-run a scan here. The Terrapin finding clears once
kex-strict-s-v00@openssh.com appears in the key exchange list, or once the affected
ciphers are gone.
FAQ
Will hardening SSH break my deployment pipeline?
Rarely, but test it. GitHub Actions, GitLab CI, Ansible and every modern deployment tool support the algorithms above. The usual casualties are old network appliances and Java applications pinned to a very old SSH library. If something breaks, add the one algorithm it requires rather than reverting.
Do I need to regenerate my host keys?
Only if they are DSA or an RSA key under 2048 bits. Generate a modern pair with
ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key. Clients that have connected
before will warn about the changed key, so tell your team first.
Is fail2ban enough on its own?
No. It limits brute-force attempts, which is useful, but it does nothing about weak algorithms or a vulnerability in the daemon. Use it alongside key-only authentication and a restricted firewall, not instead of them.