DEV Community

Chen Yuan
Chen Yuan

Posted on Originally published at dispatch-blog.hashnode.dev

OpenSSH 10.6 Ships a Compression Side-Channel Fix as a Default: Why It Matters

OpenSSH 10.6 arrived on 2026-10-06 with eight security fixes, two potentially incompatible configuration changes, and a stated shift in release cadence driven by AI-assisted vulnerability reports. The single change with the widest blast radius is not a new feature. It is the decision to disable the LZ77 dictionary coder in the SSH protocol's compression layer by default, mitigating a chosen-plaintext side channel described in the preprint "Crossing the Streams: SSH Plaintext Recovery via a Common Compression Context in Multiplexed Channels" by Fabian Baumer and Marcus Brinkmann. This is the kind of change that looks small in a changelog and large in a production fleet, because it quietly alters the cost model of a configuration knob that operators have tuned for decades.

The Compression Side-Channel That Was Already Documented

The SSH protocol allows compression to be negotiated at the transport layer. When a client and server both enable Compression, the negotiated cipher protects a compressed byte stream rather than the raw packet payload. For years the OpenSSH documentation itself recommended against enabling compression on connections that mix trusted and untrusted traffic, because the compression ratio can leak information about the plaintext. That warning existed precisely because the class of attack was understood, even if a concrete exploit had not been shipped against every variant of the SSH multiplexing design.

The 10.6 release notes name the specific mechanism: attacker-controlled input on one channel can recognizably reflect into the total length of transmitted ciphertexts, because LZ77 replaces repeated strings with back-references into an encoder search buffer that is shared across all channels of a single SSH session. When a victim channel carries a secret and an attacker-controlled channel runs in the same session, the attacker can craft inputs whose compressed length changes depending on the secret's content. The observable quantity is the ciphertext length, which the attacker can measure by observing the network.

How LZ77 Leaks Secrets Through Ciphertext Length

LZ77 is a sliding-window dictionary coder. It replaces a repeated byte sequence with a back-reference, which is a pair encoding a distance and a length. The compressor maintains a search buffer that holds recently seen bytes. When the encoder encounters a substring that also appears in the search buffer, it emits a back-reference instead of the literal bytes. A back-reference is typically shorter than the literal run it replaces, which is how compression reduces the output size.

The leakage appears when the search buffer is shared across channels that have different trust levels. Consider a simplified model of the encoder state:

search buffer (shared):  [..........secret-prefix..........]
attacker input:          A B C D E F G
                         ^^^^^^^^^^^^^
if "A B C D" matches a run inside the secret prefix,
the encoder emits a back-reference and the output shrinks.
otherwise the encoder emits literals and the output grows.
Enter fullscreen mode Exit fullscreen mode

The attacker does not read the secret directly. The attacker observes the length of the ciphertext produced for a given input, and infers whether the input matched something already present in the shared buffer. By submitting many crafted inputs and recording which ones shortened the output, the attacker narrows down the secret's content. This is the same family of attack that broke TLS under the CRIME and BREACH disclosures, where compression of attacker-controlled and secret-controlled data into a shared context produced a length oracle.

Why Disabling the Dictionary Coder Is the Default Now

The 10.6 fix targets the LZ77 dictionary coder specifically. OpenSSH's compression has historically used zlib, which is an LZ77-family compressor with a Huffman coding stage layered on top. Disabling the dictionary coder removes the back-reference substitution step while leaving the entropy coding stage functional. The practical effect is that compression still runs, but it no longer produces back-references that could make the compressed length depend on cross-channel buffer contents.

# ssh_config: the knob whose behavior changed under the hood
# this still enables compression, but the LZ77 dictionary coder
# is now disabled by the 10.6 transport change
Host production-ssh
    Compression yes
    # the documentation recommends application-level
    # compression for mixed-trust sessions instead
Enter fullscreen mode Exit fullscreen mode

The release notes are explicit about the trade-off. Disabling the dictionary coder makes Compression less effective at reducing payload size. The same payload that previously compressed to a third of its original size may now compress to half or more of the original, depending on the data. The OpenSSH team recommends application-level compression layered on top of the SSH transport where compression is genuinely needed, because application-level compression operates on a single trust context and is immune to the cross-channel length oracle.

The GSSAPI Credential Persistence Problem

A second security fix in 10.6 closes a credential leak in the GSSAPI authentication path. Before this release, when a client attempted GSSAPIAuthentication and the attempt failed, the credentials established during that failed attempt could persist into the session state. If a later authentication method succeeded against the same connection, those lingering GSSAPI credentials could be made available to the authenticated session in a way that the operator did not intend.

The fix has two parts. First, sshd now stores GSSAPI credentials only when authentication has succeeded. Second, sshd resets the GSSAPI authentication state before each new authentication attempt begins, so that residual state from one attempt cannot be confused with the state of a later attempt. The first part stops the leak; the second part stops the confusion that made the leak possible.

# sshd_config: the GSSAPI knobs affected by the fix
# the behavior change is server-side; the client knobs still apply
GSSAPIAuthentication yes
GSSAPICleanupCredentials yes
# 10.6 ensures failed GSSAPI attempts do not leave
# credentials available to a later successful auth
Enter fullscreen mode Exit fullscreen mode

This is a privilege-boundary fix rather than a cryptographic one. Its severity depends on whether an operator had GSSAPIAuthentication enabled alongside other methods, and whether the subsequent successful authentication was expected to inherit the GSSAPI context. In configurations where GSSAPI was the only enabled method, the practical exposure is narrower, because a failed GSSAPI attempt that does not fall back to another method simply rejects the connection.

Username Injection Through ProxyCommand and Match Exec

A third fix restricts the characters allowed in destination usernames entered on the command line. OpenSSH 10.6 refuses usernames that contain backslash or dollar-sign characters when those usernames are provided as command-line arguments. Usernames specified through the User directive in a configuration file are not subject to the new restriction.

The motivation is injection. OpenSSH exposes several configuration directives that interpolate values into shell contexts, including ProxyCommand, Match exec, and related directives that run external programs. When a username is supplied from an untrusted source and the configuration uses that username inside a shell-evaluated directive, a username containing shell metacharacters can produce a command the operator did not intend.

# the attack surface: a username from an untrusted source
# fed into a directive that runs an external program
# a username containing shell metacharacters such as
# backtick, dollar-sign, or semicolon, when interpolated
# into ProxyCommand or Match exec, runs an external program
# the operator did not authorize
ssh 'user<metacharacters>@host'
# 10.6: the command-line username is rejected before
# it reaches ProxyCommand or Match exec evaluation
Enter fullscreen mode Exit fullscreen mode

The release notes are careful to say that this mitigation cannot be absolute, because the variety of shells and user configurations in use means a different metacharacter set could still produce injection in some environment. The recommendation remains to avoid exposing the ssh command line to untrusted input at all. The fix closes a known concrete vector without claiming to close the entire class.

authorized_keys Restrict and the Match Override Bug

A fourth fix corrects the handling of the restrict keyword in authorized_keys entries. The restrict keyword in an authorized_keys line applies a set of restrictions to that key, including disabling port forwarding, agent forwarding, X11 forwarding, and PTY allocation. Before 10.6, the restrict keyword was not being properly applied to tunnel forwarding, which is controlled by the PermitTunnel directive and is disabled by default.

The interaction that produced the bug is a Match block override. Some options, including AuthorizedPrincipalsFile, were documented as accepting the string none as a way to disable them. When an option set to none was overridden by a Match block, the override code path was interpreting the literal string none as a filename rather than as the documented sentinel value. The fix ensures that the none sentinel is honored under Match overrides.

# authorized_keys: the restrict keyword now fully applies
# including PermitTunnel, which was previously missed
restrict,port-forwarding="no",pty="no" ssh-ed25519 AAAA... user@host
# 10.6: PermitTunnel is now covered by restrict, closing
# the gap left by the 10.5 fix for the same keyword
Enter fullscreen mode Exit fullscreen mode

This is a continuation of a fix shipped in 10.5. The earlier release addressed restrict handling for most forwarding types but missed tunnel forwarding. The 10.6 release closes that remaining gap, which means the restrict keyword now applies uniformly across the forwarding directives it is documented to control.

AI-Assisted Security Reports and the New Release Cadence

The release notes include an unusual statement about the source of recent security reports. The OpenSSH team writes that they have received a large number of security bug reports, many of which are findings produced by AI models or produced with AI assistance. The team distinguishes between reports that have security impact under a realistic threat model and reports that do not, and notes that AI-assisted reports are most valuable when combined with human triage, analysis, test cases, and proposed fixes.

The statement that drives the cadence change is the observation that some bugs identified by AI tools were subsequently discovered independently by a different researcher. The team infers from this that adversaries who do not report bugs are likely able to discover the same bugs. On that basis, OpenSSH will for now ship more frequent releases to put fixes into users' hands more quickly, rather than batching fixes until a planned release.

This is a release-process decision with a measurable operational consequence. Operators who pin to specific OpenSSH versions and update on a fixed cadence will need to account for a faster stream of security-focused releases. Operators who track the latest release already will see more frequent updates. The decision does not change the codebase's stability guarantees, but it does change the patch-management rhythm that operators have built around OpenSSH.

What These Changes Mean for Existing Configurations

The two potentially incompatible changes in 10.6 are both consequences of the security work. Compression is less effective because the LZ77 dictionary coder is disabled, which means bandwidth-sensitive workloads that relied on transport compression will see higher byte counts for the same payload. Destination usernames entered on the command line are now more strictly validated, which means any automation that constructs ssh command lines from untrusted input will need to handle the new rejection of backslash and dollar-sign characters.

Operators who already followed the documentation's recommendation to avoid compression on mixed-trust sessions will see no behavioral change, because the vulnerable configuration was already discouraged. Operators who expose the ssh command line to untrusted input remain exposed to the broader class of injection, and the 10.6 username validation is one closed vector within that class rather than a full defense. The GSSAPI credential fix and the authorized_keys restrict fix are server-side corrections that tighten privilege boundaries without requiring configuration changes from operators who were using those features as documented.

The release cadence shift is the change that outlasts the individual fixes. A faster stream of security releases means the interval between a vulnerability being reported and a fix being available shrinks, which is good for defenders. It also means the interval between releases shrinks, which raises the operational cost of pinning and validation. The OpenSSH team has stated the cadence change is for now, which leaves open the possibility that the cadence returns to the previous rhythm once the current surge of AI-assisted reports subsides. Until then, operators tracking OpenSSH should expect security releases to arrive on their own schedule rather than on the calendar of a planned major release. The fixes in 10.6 are the first batch shipped under that new discipline.


Originally published on Dispatch.

Top comments (0)