OpenSSH 10.3 to 10.6: what actually changes for you
OpenSSH 10.6 came out on October 6 (Happy Holiday, Egypt), and it is the fourth release since April. If you last read a changelog around 9.x, a few things in here will bite you: scp -R now warns, ssh refuses some usernames on the command line, and compression is much less useful than it was. This post covers the changes in 10.3 through 10.6 that affect people who use and administer OpenSSH, not the people who build it.
My PC still runs this:
$ ssh -V
OpenSSH_9.6p1 Ubuntu-3ubuntu13.19, OpenSSL 3.0.13 30 Jan 2024
So I'm reading these notes from a distribution that is a long way behind (viva Zorin OS). Everything below comes from the official release notes, and I have not run 10.6 myself yet. Where I say "should", I mean it.
Things that can break
These are the changes most likely to hit you on upgrade, newest first.
10.6
scp -R(copy directly from one remote host to another) prints a deprecation warning. Eventually it will be ignored, and scp will copy through the machine you run it on. If you have scripts that rely on the direct path, find them now.sshrejects usernames containing$or\when they come from the command line. AUserline inssh_configis not affected.- Compression is much weaker. More on that below.
10.5
- Portable OpenSSH needs ECC support in libcrypto, including NISTP521. If you build against a stripped-down OpenSSL, the build will tell you.
--without-opensslbuilds are fine.
10.4
- On Linux with the seccomp sandbox, failing to turn on SECCOMP or NO_NEW_PRIVS is now fatal instead of a quiet fallback. Containers and unusual kernels are the likely victims. The fix suggested upstream is to disable the sandbox at configure time, which I'd only do after confirming that's really the situation.
sshd -Gprints directives in mixed case, likePubkeyAuthentication, instead of lowercase. If you diffsshd -Goutput in CI or grep it case-sensitively, this will break your check.- A peer that sends non-key-exchange messages during a post-auth rekey gets disconnected.
10.3
- Servers and clients that don't implement rekeying are no longer tolerated. They'll fail when the connection needs to rekey, which means mid-session, not at login. That's an unpleasant way to find out, so if you have old embedded gear in the path, test with a transfer big enough to trigger a rekey.
- An empty certificate principal never matches. Wildcards in principals now work only for host certificates.
-JandProxyJumpvalues from the command line are validated.
Compression is now a bad idea
10.6 disables the LZ77 dictionary coder in both ssh and sshd. The reason is a cross-channel plaintext recovery attack: if two channels share one compressed stream, what you can learn about the compressed size of one can leak the contents of the other.
The cost is that the Compression option does much less than it used to. If you've been setting Compression yes for a slow link, the gain you were counting on is mostly gone. The upstream advice is to compress at the application level. For a bulk transfer that means something like tar | zstd | ssh host 'zstd -d | tar x', which is also what a lot of people already do.
Security fixes worth knowing about
The release notes are long. These are the ones I'd read twice.
sftp and scp writing where they shouldn't (10.4, 10.6). In 10.4, sftp host:/path . could write a download to an unexpected location if the server was malicious, and remote-to-remote scp could write into the parent of the target directory. 10.6 tightens sftp again: it validates the paths a server returns, so a recursive copy can't escape the directory you pointed it at. The shared lesson is that you shouldn't treat the remote side of a file copy as trusted.
Command injection through usernames (10.3). ssh now checks the command-line username for shell metacharacters before expanding % tokens. Without that, a hostile username could end up in a Match exec command. If you use Match exec with %r or %u, this is the one that applies to you. 10.6 goes further and refuses $ and \ in command-line usernames.
ssh-agent and session binding (10.5). The agent used to refuse session-bind@openssh.com requests while locked. That let remote operations get around restrictions that were meant to be local-only. This matters if you forward your agent anywhere.
Forwarding restrictions that didn't fully restrict (10.4, 10.5, 10.6). In 10.4, DisableForwarding yes now overrides PermitTunnel yes. In 10.5 and 10.6, the restrict keyword in authorized_keys is applied to tunnel forwarding too. I'd audit any key you've marked restrict and assumed was locked down.
Certificates with wrong expiry (10.6). ssh-keygen had daylight saving time errors that could produce certificates with the wrong expiry time. If you run an SSH CA, the certificates you issued across a clock change may not expire when you think they do. I'd check ssh-keygen -L -f on anything issued near a DST boundary.
There are more in there (a client-side use-after-free on host key change during rekeying, pre-auth DoS fixes, GSSAPI credential handling, scp -O clearing setuid bits when run as root). Per the LWN write-up of 10.6, the team says it has been getting many AI-assisted bug reports and welcomes them, as long as a human has triaged them. They also plan to release more often, which fits four releases in six months.
Post-quantum signatures arrive
OpenSSH already had post-quantum key exchange. On my 9.6 machine I can see one hybrid algorithm available:
$ ssh -Q kex | grep -E 'mlkem|sntrup'
sntrup761x25519-sha512@openssh.com
What's new is signatures. 10.4 added an experimental composite algorithm, mldsa44-ed25519, which you generate with:
$ ssh-keygen -t mldsa44-ed25519
It combines ML-DSA-44 with Ed25519, so a break in the new scheme alone doesn't break the signature. It was off by default in 10.4. In 10.6 the hybrid is enabled as ssh-mldsa44-ed25519, and keys made with the experimental version have to be regenerated. So if you played with it in July, those keys are dead.
Alongside that, 10.6 adds a WarnWeakCrypto option to sshd_config, on by default, that logs when a connection uses key agreement that isn't post-quantum. I haven't seen how noisy that gets on a mixed fleet. [TODO: check sshd logs on a 10.6 host after upgrading and report how many warnings an ordinary day produces. Then I will update this post, but don't stay tuned. There is a high chance that I will forget.]
Smaller things I'm going to use
ssh -Z user@host(10.5) lists the keyssshwill try for public key authentication, in order. This is the debugging command I wish I'd had every time a server has dropped me for "too many authentication failures".- FIDO key ordering (10.5).
sshnow tries low-friction FIDO keys first, so you're less likely to be asked to touch a token for a key the server was going to reject anyway. ssh-keygenand FIDO flags (10.5). You can set or clear the touch-required and verify-required flags on a FIDO key while changing its passphrase.PubkeyOptions max-pk-ok:nnnn(10.6, default 6). Sets how many key-acceptance checks don't count againstMaxAuthTries. Useful if you carry many keys in your agent.sftpmkdir -p(10.6). It took until 2026, but it's here, andlmkdir -ptoo.ssh -Oconninfoand-O channels(10.3). Information about a multiplexed connection without guessing, plus~Iin an interactive session.PerSourcePenalties(10.3) gains aninvaliduserpenalty and takes fractional durations. If you already use per-source penalties against scanners, an invalid-user penalty is the natural next knob.TCPKeepAlive all(10.6) extends keepalives to forwarding sockets, andChannelTimeout(10.6) accepts fractional seconds.AgentSocketPathinsshd_configandssh-agent -A(10.6) for controlling where agent sockets live.ssh-keygen -em hexdump(10.6) dumps a key's wire-format blob in hex. Niche, but it's a good one for debugging.
What I'd do this week
- Grep your scripts and CI for
scp -R, forsshd -Goutput compared case-sensitively, and forCompression yes. - If you run a CA, look at certificates issued around daylight saving changes.
- Review
restrictkeys inauthorized_keysand any host where you setPermitTunnel. - Wait for your distribution to package 10.6 before you plan around it. Mine is stuck on 9.6, and that is normal.
I'll write a follow-up once I've run 10.6 on a real host and can say what WarnWeakCrypto does to my logs. If you get there first, check your logs and let me know.