scp in OpenSSH before 10.4 may place a file in the parent directory of an intended directory when the copy occurs between two remote destinations.
Last updated 13 July 2026
internal-sftp in sshd in OpenSSH before 10.4 recognizes only the first 9 command-line arguments, which can be important if a later command-line argument would have helped to ensure the intended security properties of an SFTP connection.
Last updated 13 July 2026
Last updated 22 September 2026
OpenSSH 10.4 has just been released. It will be available from the mirrors listed at https://www.openssh.com/ shortly.
OpenSSH is a 100% complete SSH protocol 2.0 implementation and includes sftp client and server support.
Once again, we would like to thank the OpenSSH community for their continued support of the project, especially those who contributed code or patches, reported bugs, tested snapshots or donated to the project. More information on donations may be found at: https://www.openssh.com/donations.html
Potentially-incompatible changes --------------------------------
sshd(8): configuration dump mode ("sshd -G") now writes directives in mixed case (e.g. "PubkeyAuthentication") whereas previously it emitted only lower-case names.
sshd(8): on Linux systems with the seccomp sandbox enabled, failures to enable SECCOMP or NONEWPRIVS are now fatal. Previously sshd(8) would log the error but continue operation, to support systems that lacked these features. Now systems that lack these should instead disable the sandbox at configure time.
ssh(1), sshd(8): make the transport protocol stricter by disconnecting if the peer sends non-KEX messages during a post- authentication key re-exchange. Previously a malicious peer could continue sending non-key exchange messages without penalty. These would be buffered, causing memory to be wasted up until the connection terminated or the server/client hit a memory limit. Implementations that do not restrict messages sent during key exchange as per RFC4253 section 7.1 may be disconnected. Reported by Marko Jevtic.
Changes since OpenSSH 10.3 ==========================
This release contains a number of security fixes as well as general bugfixes and a couple of new features.
Security ========
sftp(1): when downloading files on the command-line using "sftp host:/path .", a malicious server could cause the file to be downloaded to an unexpected location. This issue was identified by the Swival Security Scanner.
scp(1): when copying files between two remote destinations, do not allow a malicious server to write files to the parent directory of the intended target directory. This issue was identified by the Swival Security Scanner.
sshd(8): when using the "internal-sftp" SFTP server implementation (this is not the default), long command lines were previously truncated silently after the 9th argument. If a security-relevant option was in the 10th or later position, it would be discarded. Reported by Steve Caffrey.
sshd(8): add a documentation note to mention that the GSSAPIStrictAcceptorCheck option is ineffective when the server is joined to a Windows Active Directory. Reported by Yarin Aharoni of Safebreach.
sshd(8): DisableForwarding=yes didn't override PermitTunnel=yes as it was documented to do. Note that PermitTunnel is not enabled by default. Reported independently by Huzaifa Sidhpurwala of Redhat and Marko Jevtic.
sshd(8): avoid a potential pre-authentication denial of service when GSSAPIAuthentication was enabled (this feature is off by default). This was not mitigated by MaxAuthTries, but would be penalised by PerSourcePenalties. This was reported by Manfred Kaiser of the milCERT AT (Austrian Ministry of Defence).
sshd(8): fix a number of cases where the minimum authentication delay was not being enforced. Reported by the Orange Cyberdefense Vulnerability Team.
ssh(1): fix a possible client-side use-after-free if the server changes its host key during a key reexchange. This was reported by Zhenpeng (Leo) Lin of Depthfirst.
New features ------------
All: add experimental support for a composite post-quantum signature scheme that combines ML-DSA 44 and Ed25519 as specified in draft-miller-sshm-mldsa44-ed25519-composite-sigs.
This scheme is not enabled by default. To use it, you'll need to add it to HostKeyAlgorithms, PubkeyAcceptedAlgorithms, etc. Keys may be generated using "ssh-keygen -t mldsa44-ed25519".
ssh(1), sshd(8): replace the wildcard pattern matcher with an implementation based on an NFA. This avoids exponential worst-case behaviour for the old implementation.
Bugfixes --------
ssh-agent(1): fix incorrect reply to "query" SSHAGENTCEXTENSION requests. bz3967
sshd(8): avoid sending observably different messages for valid vs invalid users in GSSAPIAuthentication (disabled by default).
ssh(1), sshd(8): fix several bugs that incorrectly classified bulk traffic as interactive. bz3972, bz3958
ssh-keygen(1), ssh-add(1): skip unsupported key types when downloading resident keys from a FIDO token. Previously, downloads would abort when one was encountered. GHPR657
ssh(1): fix a potential use-after-free on an error path if cipherinit() fails.
sshd(8): perform stricter encoding and validation of transport state passed between sshd privilege separation subprocesses. This somewhat further hardens the server against attacks on sshd-auth or sshd-session subprocesses.
ssh-agent(1): avoid possible runtime denial of service by enforcing some limits on the length of usernames in key use constraints.
sftp(1): fix two separate one-byte out-of-bounds reads, in SSH2FXPREALPATH and batch command processing.
sftp-server(8): disallow use of the copy-data extension to read and write to the same inode simultaneously.
ssh(1), sshd(8): avoid strlen(NULL) crash if an X11 channel was created before the x11-req SSHMSGCHANNELREQUEST was sent. GHPR679
sftp(1), scp(1): avoid a situation where sftpdownload() could get stuck in a loop if a broken server repeatedly returned zero length while reading a file.
ssh(1): avoid leaking DNS0x20 case-randomised names into names canonicalised using CanonicalizePermittedCNAMEs. bz3966
sftp-server(8): avoid truncation of pathnames passed to lstat() during SSHFXPREALPATH handling on systems where PATHMAX is not the actual max. GHPR688
ssh(1), sshd(8): correct arming of poll(2) event masks for some socket-type channels. GHPR660
sshd(8): major refactor of sshdconfig parsing and management code, to allow for more exact serialisation/deserialisation across privilege separation boundaries.
ssh-add(1): open connection to the agent only after getopt() processing has completed, to give options like "-v" a chance to display debug information about this operation.
crypto code: fix bounds checking when signing messages of length greater than will fit in a sizet. In OpenSSH, message sizes are bounded by SSHBUFSIZEMAX so this was unreachable.
crypto code: add signature malleability and pubkey validity checks to ed25519 verification. SSH doesn't depend on these properties
crypto code: fix ECDSA order check for curves with cofactor != 1. All supported EC curves have cofactor 1, so this was unreachable.
sshd(8): differentiate between execution failures and a subsystem that was not found when logging why a subsystem failed to start. GHPR637
All: use safer idioms for timegm(3) and mktime(3) error detection.
ssh(1), sshd(8): avoid accepting invalid cipher or MAC lists in config files or command-line arguments. This could cause runtime failures later.
ssh(1): fix NULL deref crash during pubkey auth when using a PEM style private key with no corresponding .pub key adjacent to it.
sshd(8): don't print an error message when trying to load a host private key when PKCS#11 keys are in use, as these don't need the private half on the filesystem. GHPR664
All: don't use deprecated ERRloadcryptostrings(). GHPR650
ssh(1): properly report errors during configuration default setting. GHPR649
ssh(1): use correct directive name (Match instead of Host) in error message. bz3968
sftp(1): fix "ls -ln" which was not correctly showing numeric UID/GIDs but rather user and group names. bz3953
sshd(8): avoid possible NULL dereference if an allocation fails during config parsing. bz3948
All: fix ineffective guards against loading overly large public keys in several places. bz3969 and bz3970
sftp(1): ensure file descriptors used by sftp to communicate to its ssh(1) subprocess don't leak into executed subprocesses (e.g. via "!"). GHPR693
Portability -----------
Sync fmtscaled.c with OpenBSD upstream, picking up an exactness fix for large exponents (GHPR671)
sshd(8): remove duplicate sandbox entry for clockgettime64.
ssh(1), sshd(8): use correct IPTOSDSCPVA value if not provided by the system headers.
Sync getrrsetbyname.c with OpenBSD upstream, picking up robustness fixes.
Disable replacements in openbsd-compat for strvisx(3) and stravis(3), as these are unused in OpenSSH
Avoid fortify warnings on Android bz3954
Fix a number of memory leaks on error paths in the portability code. GHPR681
Revise the README.privsep documentation to reflect sshd's recent switch to a multi-binary model.
Checksums: ==========
- SHA1 (openssh-10.4.tar.gz) = 8502b516230865e229d55045bb4ccc67aeae905b - SHA256 (openssh-10.4.tar.gz) = qUVI+wMg4mVpiQbXvfMVkF3Zuyy2JrS+ZjN764mtyGE=
- SHA1 (openssh-10.4p1.tar.gz) = ae8650a71cc52dbbd049519cee276ae6d65c2c4d - SHA256 (openssh-10.4p1.tar.gz) = 72Am3SrqjVYFljjV0yYpAsiSzrqfiDlYNeDQbT+2Mjg=
Please note that the SHA256 signatures are base64 encoded and not hexadecimal (which is the default for most checksum tools). The PGP key used to sign the releases is available from the mirror sites: https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/RELEASEKEY.asc
Reporting Bugs: ===============
- Please read https://www.openssh.com/report.html Security bugs should be reported directly to openssh () openssh com
AIONLYREPORT package: openssh-10.2p1-10.1.hum1 ------ Summary: Heap out-of-bounds read in GSSAPI indicator cleanup: missing trailing NULL termination in the GSSAPI auth-indicators array allows sentinel-based consumers to read past the allocated pointer array and may trigger an invalid free during cleanup. Requirements to exploit: An attacker needs network access to SSH on openssh-10.2p1-10.1.hum1 built with GSSAPI support and deployed with GSSAPIAuthentication yes; in this tree that option defaults to disabled. The Kerberos environment must provide a ticket containing at least one authenticated auth-indicators value, and execution must then reach either the failed sshgssapiuserok() cleanup path or the GSSAPIIndicators matching path. Component affected: openssh-10.2p1-10.1.hum1, server-side GSSAPI authentication code in gss-serv.c (sshgssapigetindicators()), with sentinel-based consumption in gss-serv.c (sshgssapiuserok()) and gss-serv-krb5.c (sshgssapicheckindicators()) Version affected: openssh-10.2p1-10.1.hum1 when built with GSSAPI support; remote triggerability additionally requires GSSAPIAuthentication yes and a Kerberos deployment that supplies authenticated auth-indicators Patch available: no released package fix established; proposed patch included below Version fixed: unknown Upstream coordination: Not yet established. CVSS: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L - 3.7 (LOW) AV:N - the vulnerable path is reachable through network SSH authentication traffic. AC:H - exploitation depends on a GSSAPI-enabled build, GSSAPIAuthentication yes, a Kerberos ticket carrying authenticated auth-indicators, and reaching a sentinel-based consumer path. PR:N - no prior privileges on the target host are required beyond initiating the SSH authentication exchange. UI:N - no separate user interaction is required once the target is configured this way. S:U - the effect is limited to the vulnerable SSH authentication component. C:N - no reliable confidentiality impact is established from the available evidence. I:N - no integrity impact is established from the available evidence. A:L - the demonstrated consequence is limited to out-of-bounds reads that may crash or abort the affected authentication path. Impact: Moderate. Red Hat classifies easily triggered remote denial of service issues as Important, but the trigger conditions here are materially narrower: the issue depends on GSSAPI support, non-default SSH configuration, Kerberos indicator issuance, and a specific authentication control flow. The demonstrated impact is limited to availability loss in privileged authentication code, so Moderate is a better fit than Important, while remaining above Low because the out-of-bounds iteration is concrete rather than merely theoretical. Embargo: no Reason: The issue is configuration-dependent, the demonstrated impact is limited to availability, and the proposed fix is small and low-risk. A normal public fix cycle appears more appropriate than an embargo. Acknowledgement: Aisle Research Vulnerability Details: In sshgssapigetindicators(), the client->indicators array is reallocated from count to count + 1 elements and the newly added slot is immediately filled with a newly allocated string: c client->indicators = xrecallocarray(client->indicators, count, count + 1, sizeof(char)); if (client->indicators == NULL) { fatal("sshgssapigetindicators failed to allocate memory"); } client->indicators[count] = xmalloc(value.length + 1); memcpy(client->indicators[count], value.value, value.length); client->indicators[count][value.length] = '\0'; count++; In this source tree, xrecallocarray() wraps recallocarray(), which zeroes only the newly added region when the allocation grows. Here the newly added region is exactly one pointer wide, and that pointer is overwritten before count is incremented. As a result, once at least one authenticated indicator is collected, there is no guaranteed trailing NULL entry after the last valid element even though later code relies on sentinel termination. Two consumers iterate until NULL: c if (gssapiclient.indicators != NULL) { for (i = 0; gssapiclient.indicators[i] != NULL; i++) free(gssapiclient.indicators[i]); free(gssapiclient.indicators); } c for (i = 0; client->indicators[i] != NULL; i++) { ret = matchpatternlist(client->indicators[i], options.gssindicators, 1); ... } These loops may read beyond the allocated pointer array while searching for a terminator. On the sshgssapiuserok() failure cleanup path, that out-of-bounds read may also cause free() to be called on a non-owned pointer if adjacent heap contents are interpreted as another indicator entry. Based on the available evidence, the established security consequence is an availability problem; reliable confidentiality or integrity impact is not demonstrated. Steps to reproduce: 1. Build openssh-10.2p1-10.1.hum1 with GSSAPI support and memory sanitizers such as ASan/UBSan. 2. Run sshd with GSSAPIAuthentication yes. 3. Authenticate with a Kerberos ticket that contains at least one authenticated auth-indicators name attribute. 4. Trigger a sentinel-based consumer by either causing sshgssapiuserok() to return false, for example through principal-to-local-user authorization failure, or by configuring GSSAPIIndicators so sshgssapicheckindicators() iterates the list. 5. Observe a sanitizer-reported read past the end of the indicators pointer array; depending on heap layout, cleanup may also attempt to free a non-owned pointer. Mitigation: Disabling GSSAPIAuthentication removes the remotely reachable path. If GSSAPI authentication is required, avoiding GSSAPIIndicators removes one consumer but does not remove the cleanup path after sshgssapiuserok() failure; the safer temporary mitigation is to restrict or disable use of Kerberos tickets carrying authenticated auth-indicators values until a fix is deployed. Proposed Fix: Ensure sshgssapigetindicators() leaves a dedicated trailing NULL slot after indicator collection so all sentinel-based consumers remain within bounds. diff diff --git a/gss-serv.c b/gss-serv.c @@ done: - / slot [count] is zeroed by recallocarray, serves as NULL sentinel / + / + Ensure a trailing NULL sentinel for sentinel-based consumers. + / + if (client->indicators != NULL) + client->indicators = xrecallocarray(client->indicators, + count, count + 1, sizeof(char )); ------ This report was generated using AI technology. Always review AI-generated content prior to use
A flaw was found in OpenSSH. A local unprivileged attacker on a Linux client host can hijack client-side X11 forwarding connections. This is possible by pre-binding the preferred abstract X socket name when X11 forwarding is enabled and a local UNIX-domain X socket is used. A successful attack can compromise the confidentiality of forwarded X11 traffic, including sensitive window contents and input, and may allow some manipulation of the forwarded session.
AIONLYREPORT package: openssh-9.9p1-22.el102 ------ Summary: Local MITM of X11 forwarding via preferred Linux abstract UNIX socket connection: a local unprivileged process on the Linux client host can hijack the client-side X11 forwarding connection by pre-binding the preferred abstract X socket name. Requirements to exploit: An attacker needs local unprivileged code execution on the Linux host running the OpenSSH client, client-side X11 forwarding enabled (-X, -Y, or equivalent configuration), a local DISPLAY that resolves to a UNIX-domain X socket such as :0 or unix:0, and a forwarded X11 connection to be opened while the attacker has pre-bound the matching abstract socket name. Component affected: openssh-9.9p1-22.el102, client-side X11 forwarding code in openssh-9.9p1/channels.c (connectlocalxsocket(), x11openhelper()). Version affected: openssh-9.9p1-22.el102; reachable on Linux in the client-side X11 forwarding path when X11 forwarding is enabled and DISPLAY resolves to a local UNIX-domain X socket Patch available: no released package fix established; proposed patch included below Version fixed: unknown Upstream coordination: Not notified. CVSS: CVSS:3.1/AV:L/AC:H/PR:L/UI:R/S:U/C:H/I:L/A:N - 5.3 (MEDIUM) AV:L - The attacker must already have local code execution on the Linux system running the OpenSSH client. AC:H - Exploitation depends on a feature-specific client configuration, successful pre-binding of the matching abstract X11 socket, and a forwarded X11 connection actually being opened. PR:L - An unprivileged local user account or equivalent local process execution is sufficient. UI:R - A user must enable X11 forwarding and the session must trigger a forwarded X11 connection. S:U - The impact stays within the client-side OpenSSH/X11 forwarding security scope. C:H - A successful hijack can expose forwarded X11 traffic, including sensitive window contents and input; when real xauth data is available, the saved X11 authentication data may also be substituted into the hijacked stream. I:L - The attacker can influence the X11 protocol stream presented to the forwarded application, but the demonstrated effect is narrower than general host compromise. A:N - The issue does not require a direct availability impact to succeed. Impact: Moderate. A successful attack can compromise the confidentiality of forwarded X11 traffic and allow some integrity impact on the forwarded session, but exploitation is limited to a local attacker on the client host and depends on the non-default, feature-specific condition that X11 forwarding is enabled and used. Under Red Hat’s criteria, this is better classified as Moderate than Important because it is real but not easily exploitable in typical deployments. Embargo: no Reason: This is a local, configuration-dependent client-side issue with straightforward mitigation by disabling X11 forwarding where it is not required, and it does not present an easily exploitable remote compromise path. Acknowledgement: Aisle Research Vulnerability Details: This issue is in the OpenSSH client’s Linux X11 forwarding path. When the client receives an X11 open request, the call path reaches x11connectdisplay(), which parses DISPLAY and, for local UNIX-domain displays such as :0 or unix:0, calls connectlocalxsocket(). In the vulnerable path, Linux tries the abstract UNIX socket name before the filesystem socket: c len = snprintf(buf + 1, sizeof (buf) - 1, PATHUNIXX, dnr); #ifdef linux / try abstract socket first / buf[0] = '\0'; if ((ret = connectlocalxsocketpath(buf, len + 1)) >= 0) return ret; #endif if ((ret = connectlocalxsocketpath(buf + 1, len)) >= 0) return ret; PATHUNIXX resolves to /tmp/.X11-unix/X%u, so on Linux the first attempted endpoint is the abstract socket name \0/tmp/.X11-unix/X<display>. Because Linux abstract UNIX sockets are not mediated by filesystem permissions, an unprivileged local process can pre-bind that name and receive the forwarded X11 connection before the legitimate filesystem socket. The connection helper performs a direct connect() and does not verify peer credentials or ownership after the connection succeeds. OpenSSH’s X11 spoofing logic validates the fake cookie received from the remote side, but it does not authenticate the local X11 endpoint. After the fake cookie check passes, the client replaces it with the saved X11 authentication data: c if (datalen != sc->x11fakedatalen || timingsafebcmp(ucp + 12 + ((protolen + 3) & ~3), sc->x11fakedata, sc->x11fakedatalen) != 0) { debug2("X11 auth data does not match fake data."); return -1; } ... memcpy(ucp + 12 + ((protolen + 3) & ~3), sc->x11saveddata, sc->x11saveddatalen); As a result, an attacker-controlled abstract socket can receive the forwarded X11 session first. Where real xauth data was obtained, the rewritten first packet will contain the saved X11 authentication data. If xauth data is unavailable, OpenSSH can fall back to generated fake data, which reduces credential-leak impact but does not prevent the connection hijack or interception of the forwarded X11 stream. The available evidence supports interception and limited manipulation of forwarded X11 sessions, not arbitrary code execution or privilege escalation in the client itself. Steps to reproduce: 1. On a Linux system running the OpenSSH client, confirm the local display uses a UNIX-domain socket such as :0 or unix:0. 2. Before opening a forwarded X11 connection, start a local unprivileged listener bound to the matching abstract socket name. For display :0: python import socket s = socket.socket(socket.AFUNIX, socket.SOCKSTREAM) s.bind("\0/tmp/.X11-unix/X0") s.listen(1) c, = s.accept() print("accepted; first bytes:", c.recv(64).hex()) 3. In another terminal, start an SSH session with X11 forwarding enabled: bash ssh -X user@remote 4. From the remote shell, trigger an X11 application so that the client opens the forwarded X11 channel, for example: bash xclock 5. Observe that the attacker listener accepts the connection and receives the initial X11 bytes before the legitimate filesystem socket /tmp/.X11-unix/X0 is used. 6. Optional confirmation: bash strace -f -e connect ssh -X user@remote Expected result: tracing shows a successful AFUNIX connect to the abstract socket name \0/tmp/.X11-unix/X0 before any successful connect to /tmp/.X11-unix/X0. Mitigation: Disable X11 forwarding on affected clients when it is not required, for example by avoiding -X/-Y and using ForwardX11 no. On shared Linux systems where untrusted local users or processes may be present, avoid relying on client-side X11 forwarding until a fix that prefers the filesystem X socket has been applied. Proposed Fix: Prefer the filesystem X11 socket first, and retain Linux abstract sockets only as a compatibility fallback. diff diff --git a/openssh-9.9p1/channels.c b/openssh-9.9p1/channels.c @@ static int connectlocalxsocket(uint dnr) len = snprintf(buf + 1, sizeof (buf) - 1, PATHUNIXX, dnr); + / Prefer filesystem socket (permission/ownership mediated) / + if ((ret = connectlocalxsocketpath(buf + 1, len)) >= 0) + return ret; #ifdef linux - / try abstract socket first / + / Abstract socket fallback for compatibility / buf[0] = '\0'; if ((ret = connectlocalxsocketpath(buf, len + 1)) >= 0) return ret; #endif - if ((ret = connectlocalxsocketpath(buf + 1, len)) >= 0) - return ret; error("connect %.100s: %.100s", buf + 1, strerror(errno)); return -1; ------ This report was generated using AI technology. Always review AI-generated content prior to use
On 4/6/26 19:27, Damien Miller wrote: On Mon, 6 Apr 2026, Demi Marie Obenour wrote: Probably, but this is the essence of the problem as we see it: we can't know for sure whether this is safe, because we don't can effectively reason about what shell is in use (and thus what its metacharacters are) and what the user is doing with these characters in their configuration file. What about using execve() directly for these commands, rather than a shell? That would break backwards compatibility for what I suspect to be rare configurations, while fixing most of these injection problems. People definitely use shell constructs in Match exec and LocalCommand so this would be quite a loss on the client side. If OpenSSH knew what the shell was, could it quote appropriately? Presumably most people are using POSIX-compatible shells. On the server-side, we already use execve(), but that's not a guarantee of safety. As an extreme example, consider
AuthorizedPrincipalsCommand sh -c %u That is true, but also presumably nobody is doing that :). It's still possible to shoot youself in the foot with these if you try hard enough though, e.g. if you've rigged NSS to allow arbitrary usernames with no character filtering, then there is the potential for shell injection if the admin has specified token expansion in a Command directive. Does NSS generally enforce some sort of validation? Typically it's configured to perform a lookup in some database (e.g. LDAP) and return only users that exist there. These are fine.
Other configurations are possible, e.g. someone might naively create a NSS configuration that accepted any username and returned default account information for it. sshd isn't the only thing that might have problems here. There's probably plenty of other things that would have difficulty with getpwnam() returning valid user information for the name "../../../../../../etc/shadow" Good point! -- Sincerely, Demi Marie Obenour (she/her/hers)
On Mon, 6 Apr 2026, Demi Marie Obenour wrote: Probably, but this is the essence of the problem as we see it: we can't know for sure whether this is safe, because we don't can effectively reason about what shell is in use (and thus what its metacharacters are) and what the user is doing with these characters in their configuration file. What about using execve() directly for these commands, rather than a shell? That would break backwards compatibility for what I suspect to be rare configurations, while fixing most of these injection problems. People definitely use shell constructs in Match exec and LocalCommand so this would be quite a loss on the client side.
On the server-side, we already use execve(), but that's not a guarantee of safety. As an extreme example, consider
AuthorizedPrincipalsCommand sh -c %u It's still possible to shoot youself in the foot with these if you try hard enough though, e.g. if you've rigged NSS to allow arbitrary usernames with no character filtering, then there is the potential for shell injection if the admin has specified token expansion in a Command directive. Does NSS generally enforce some sort of validation? Typically it's configured to perform a lookup in some database (e.g. LDAP) and return only users that exist there. These are fine.
Other configurations are possible, e.g. someone might naively create a NSS configuration that accepted any username and returned default account information for it. sshd isn't the only thing that might have problems here. There's probably plenty of other things that would have difficulty with getpwnam() returning valid user information for the name "../../../../../../etc/shadow"
-d
On 4/6/26 02:20, Damien Miller wrote: On Fri, 3 Apr 2026, Demi Marie Obenour wrote: ssh(1): validation of shell metacharacters in user names supplied on the command-line was performed too late to prevent some situations where they could be expanded from %-tokens in sshconfig. For certain configurations, such as those that use a "%u" token in a "Match exec" block, an attacker who can control the user name passed to ssh(1) could potentially execute arbitrary shell commands. Reported by Florian Kohnhäuser.
We continue to recommend against directly exposing ssh(1) and other tools' command-lines to untrusted input. Mitigations such as this can not be absolute given the variety of shells and user configurations in use. Is it safe (from a shell injection perspective) to pass inputs that are sanitized for character set, but otherwise untrusted? For instance, is it sufficient to limit usernames to ^[A-Za-z][A-Za-z0-9-]{0,31}$ and domain names to valid host names [1]? Probably, but this is the essence of the problem as we see it: we can't know for sure whether this is safe, because we don't can effectively reason about what shell is in use (and thus what its metacharacters are) and what the user is doing with these characters in their configuration file. What about using execve() directly for these commands, rather than a shell? That would break backwards compatibility for what I suspect to be rare configurations, while fixing most of these injection problems. To make things harder, this isn't the full set of characters that appear in usernames. At least %, @, \ and / are relatively common too :( \ cannot be used safely unless single quoted on POSIX shells. Can one assume that in situations where entries come from an untrusted source (such as AuthorizedKeysCommand), OpenSSH does do such checking? The Command options in sshdconfig require that the user exist in the system password database, otherwise they will not be executed.
It's still possible to shoot youself in the foot with these if you try hard enough though, e.g. if you've rigged NSS to allow arbitrary usernames with no character filtering, then there is the potential for shell injection if the admin has specified token expansion in a Command directive. Does NSS generally enforce some sort of validation? [1]: No more than 254 bytes (plus optional trailing '.'), no leading '.', each '.'-delimited component must start and end with [a-z0-9], not be more than 63 bytes, and only have [a-z0-9-]. This too would block some hostnames that people use frequently. As a trivial example, '' is common in hostnames despite being strictly invalid. IIRC there are other more esoteric ones too.
-d -- Sincerely, Demi Marie Obenour (she/her/hers)
On Fri, 3 Apr 2026, Demi Marie Obenour wrote: ssh(1): validation of shell metacharacters in user names supplied on the command-line was performed too late to prevent some situations where they could be expanded from %-tokens in sshconfig. For certain configurations, such as those that use a "%u" token in a "Match exec" block, an attacker who can control the user name passed to ssh(1) could potentially execute arbitrary shell commands. Reported by Florian Kohnhäuser.
We continue to recommend against directly exposing ssh(1) and other tools' command-lines to untrusted input. Mitigations such as this can not be absolute given the variety of shells and user configurations in use. Is it safe (from a shell injection perspective) to pass inputs that are sanitized for character set, but otherwise untrusted? For instance, is it sufficient to limit usernames to ^[A-Za-z][A-Za-z0-9-]{0,31}$ and domain names to valid host names [1]? Probably, but this is the essence of the problem as we see it: we can't know for sure whether this is safe, because we don't can effectively reason about what shell is in use (and thus what its metacharacters are) and what the user is doing with these characters in their configuration file.
To make things harder, this isn't the full set of characters that appear in usernames. At least %, @, \ and / are relatively common too :( Can one assume that in situations where entries come from an untrusted source (such as AuthorizedKeysCommand), OpenSSH does do such checking? The Command options in sshdconfig require that the user exist in the system password database, otherwise they will not be executed.
It's still possible to shoot youself in the foot with these if you try hard enough though, e.g. if you've rigged NSS to allow arbitrary usernames with no character filtering, then there is the potential for shell injection if the admin has specified token expansion in a Command directive. [1]: No more than 254 bytes (plus optional trailing '.'), no leading '.', each '.'-delimited component must start and end with [a-z0-9], not be more than 63 bytes, and only have [a-z0-9-]. This too would block some hostnames that people use frequently. As a trivial example, '' is common in hostnames despite being strictly invalid. IIRC there are other more esoteric ones too.
-d
On 4/2/26 05:25, Damien Miller wrote: OpenSSH 10.3 has just been released. It will be available from the mirrors listed at https://www.openssh.com/ shortly.
OpenSSH is a 100% complete SSH protocol 2.0 implementation and includes sftp client and server support.
Once again, we would like to thank the OpenSSH community for their continued support of the project, especially those who contributed code or patches, reported bugs, tested snapshots or donated to the project. More information on donations may be found at: https://www.openssh.com/donations.html
Potentially-incompatible changes --------------------------------
ssh(1), sshd(8): remove bug compatibility for implementations that don't support rekeying. If such an implementation tries to interoperate with OpenSSH, it will now eventually fail when the transport needs rekeying.
sshd(8): prior to this release, a certificate that had an empty principals section would be treated as matching any principal (i.e. as a wildcard) when used via authorizedkeys principals="" option. This was intentional, but created a surprising and potentially risky situation if a CA accidentally issued a certificate with an empty principals section: instead of being useless as one might expect, it could be used to authenticate as any user who trusted the CA via authorizedkeys. [Note that this condition did not apply to CAs trusted via the sshdconfig(5) TrustedUserCAKeys option.]
This release treats an empty principals section as never matching any principal, and also fixes interpretation of wildcard characters in certificate principals. Now they are consistently implemented for host certificates and not supported for user certificates.
ssh(1): the -J and equivalent -oProxyJump="..." options now validate user and host names for ProxyJump/-J options passed via the command-line (no such validation is performed for this option in configuration files). This prevents shell injection in situations where these were directly exposed to adversarial input, which would have been a terrible idea to begin with. Reported by rabbit.
Changes since OpenSSH 10.2 ==========================
This release contains some relatively minor security fixes as well as a number of feature improvements and general bugfixes.
Security ========
ssh(1): validation of shell metacharacters in user names supplied on the command-line was performed too late to prevent some situations where they could be expanded from %-tokens in sshconfig. For certain configurations, such as those that use a "%u" token in a "Match exec" block, an attacker who can control the user name passed to ssh(1) could potentially execute arbitrary shell commands. Reported by Florian Kohnhäuser.
We continue to recommend against directly exposing ssh(1) and other tools' command-lines to untrusted input. Mitigations such as this can not be absolute given the variety of shells and user configurations in use. Is it safe (from a shell injection perspective) to pass inputs that are sanitized for character set, but otherwise untrusted? For instance, is it sufficient to limit usernames to ^[A-Za-z][A-Za-z0-9-]{0,31}$ and domain names to valid host names [1]?
Can one assume that in situations where entries come from an untrusted source (such as AuthorizedKeysCommand), OpenSSH does do such checking?
[1]: No more than 254 bytes (plus optional trailing '.'), no leading '.', each '.'-delimited component must start and end with [a-z0-9], not be more than 63 bytes, and only have [a-z0-9-]. -- Sincerely, Demi Marie Obenour (she/her/hers)
Hi Agostino,
On Fri, Apr 03, 2026 at 09:43:49AM +0200, Agostino Sarubbo wrote: On giovedì 2 aprile 2026 11:25:08 Ora legale dell’Europa centrale Damien Miller wrote: Security ========
ssh(1): validation of shell metacharacters in user names supplied on the command-line was performed too late to prevent some situations where they could be expanded from %-tokens in sshconfig. For certain configurations, such as those that use a "%u" token in a "Match exec" block, an attacker who can control the user name passed to ssh(1) could potentially execute arbitrary shell commands. Reported by Florian Kohnhäuser.
We continue to recommend against directly exposing ssh(1) and other tools' command-lines to untrusted input. Mitigations such as this can not be absolute given the variety of shells and user configurations in use.
sshd(8): when matching an authorizedkeys principals="" option against a list of principals in a certificate, an incorrect algorithm was used that could allow inappropriate matching in cases where a principal name in the certificate contains a comma character. Exploitation of the condition requires an authorizedkeys principals="" option that lists more than one principal and a CA that will issue a certificate that encodes more than one of these principal names separated by a comma (typical CAs stronly constrain which principal names they will place in a certificate). This condition only applies to user- trusted CA keys in authorizedkeys, the main certificate authentication path (TrustedUserCAKeys/AuthorizedPrincipalsFile) is not affected. Reported by Vladimir Tokarev.
scp(1): when downloading files as root in legacy (-O) mode and without the -p (preserve modes) flag set, scp did not clear setuid/setgid bits from downloaded files as one might typically expect. This bug dates back to the original Berkeley rcp program. Reported by Christos Papakonstantinou of Cantina and Spearbit.
sshd(8): fix incomplete application of PubkeyAcceptedAlgorithms and HostbasedAcceptedAlgorithms with regard to ECDSA keys. Previously if one of these directives contains any ECDSA algorithm name (say "ecdsa-sha2-nistp384"), then any other ECDSA algorithm would be accepted in its place regardless of whether it was listed or not. Reported by Christos Papakonstantinou of Cantina and Spearbit.
ssh(1): connection multiplexing confirmation (requested using "ControlMaster ask/autoask") was not being tested for proxy mode multiplexing sessions (i.e. "ssh -O proxy ..."). Reported by Michalis Vasileiadis. Hello Damien,
thank you for bringing this to oss-security so that everyone is aware of it.
Regarding the security changes, we do not see any CVE assigned. Could you please clarify your perspective on this? Are these changes considered simply hardening improvements, or do they have a security impact that would warrant a CVE? I think since yesterday there were CVE assigned actually by MITRE, they should be:
https://www.cve.org/CVERecord?id=CVE-2026-35414 https://www.cve.org/CVERecord?id=CVE-2026-35385 https://www.cve.org/CVERecord?id=CVE-2026-35386 https://www.cve.org/CVERecord?id=CVE-2026-35387 https://www.cve.org/CVERecord?id=CVE-2026-35388
Regards, Salvatore
On giovedì 2 aprile 2026 11:25:08 Ora legale dell’Europa centrale Damien Miller wrote: Security ========
ssh(1): validation of shell metacharacters in user names supplied on the command-line was performed too late to prevent some situations where they could be expanded from %-tokens in sshconfig. For certain configurations, such as those that use a "%u" token in a "Match exec" block, an attacker who can control the user name passed to ssh(1) could potentially execute arbitrary shell commands. Reported by Florian Kohnhäuser.
We continue to recommend against directly exposing ssh(1) and other tools' command-lines to untrusted input. Mitigations such as this can not be absolute given the variety of shells and user configurations in use.
sshd(8): when matching an authorizedkeys principals="" option against a list of principals in a certificate, an incorrect algorithm was used that could allow inappropriate matching in cases where a principal name in the certificate contains a comma character. Exploitation of the condition requires an authorizedkeys principals="" option that lists more than one principal and a CA that will issue a certificate that encodes more than one of these principal names separated by a comma (typical CAs stronly constrain which principal names they will place in a certificate). This condition only applies to user- trusted CA keys in authorizedkeys, the main certificate authentication path (TrustedUserCAKeys/AuthorizedPrincipalsFile) is not affected. Reported by Vladimir Tokarev.
scp(1): when downloading files as root in legacy (-O) mode and without the -p (preserve modes) flag set, scp did not clear setuid/setgid bits from downloaded files as one might typically expect. This bug dates back to the original Berkeley rcp program. Reported by Christos Papakonstantinou of Cantina and Spearbit.
sshd(8): fix incomplete application of PubkeyAcceptedAlgorithms and HostbasedAcceptedAlgorithms with regard to ECDSA keys. Previously if one of these directives contains any ECDSA algorithm name (say "ecdsa-sha2-nistp384"), then any other ECDSA algorithm would be accepted in its place regardless of whether it was listed or not. Reported by Christos Papakonstantinou of Cantina and Spearbit.
ssh(1): connection multiplexing confirmation (requested using "ControlMaster ask/autoask") was not being tested for proxy mode multiplexing sessions (i.e. "ssh -O proxy ..."). Reported by Michalis Vasileiadis. Hello Damien,
thank you for bringing this to oss-security so that everyone is aware of it.
Regarding the security changes, we do not see any CVE assigned. Could you please clarify your perspective on this? Are these changes considered simply hardening improvements, or do they have a security impact that would warrant a CVE?
Thank you. Agostino
In OpenSSH before 10.3, command execution can occur via shell metacharacters in a username within a command line. This requires a scenario where the username on the command line is untrusted, and also requires a non-default configurations of % in sshconfig.
OpenSSH before 10.3 can use unintended ECDSA algorithms. Listing of any ECDSA algorithm in PubkeyAcceptedAlgorithms or HostbasedAcceptedAlgorithms is misinterpreted to mean all ECDSA algorithms.
OpenSSH before 10.3 omits connection multiplexing confirmation for proxy-mode multiplexing sessions.
OpenSSH before 10.3 mishandles the authorizedkeys principals option in uncommon scenarios involving a principals list in conjunction with a Certificate Authority that makes certain use of comma characters.
In OpenSSH before 10.3, a file downloaded by scp may be installed setuid or setgid, an outcome contrary to some users' expectations, if the download is performed as root with -O (legacy scp protocol) and without -p (preserve mode).
Last updated 22 September 2026
OpenSSH 10.3 has just been released. It will be available from the mirrors listed at https://www.openssh.com/ shortly.
OpenSSH is a 100% complete SSH protocol 2.0 implementation and includes sftp client and server support.
Once again, we would like to thank the OpenSSH community for their continued support of the project, especially those who contributed code or patches, reported bugs, tested snapshots or donated to the project. More information on donations may be found at: https://www.openssh.com/donations.html
Potentially-incompatible changes --------------------------------
ssh(1), sshd(8): remove bug compatibility for implementations that don't support rekeying. If such an implementation tries to interoperate with OpenSSH, it will now eventually fail when the transport needs rekeying.
sshd(8): prior to this release, a certificate that had an empty principals section would be treated as matching any principal (i.e. as a wildcard) when used via authorizedkeys principals="" option. This was intentional, but created a surprising and potentially risky situation if a CA accidentally issued a certificate with an empty principals section: instead of being useless as one might expect, it could be used to authenticate as any user who trusted the CA via authorizedkeys. [Note that this condition did not apply to CAs trusted via the sshdconfig(5) TrustedUserCAKeys option.]
This release treats an empty principals section as never matching any principal, and also fixes interpretation of wildcard characters in certificate principals. Now they are consistently implemented for host certificates and not supported for user certificates.
ssh(1): the -J and equivalent -oProxyJump="..." options now validate user and host names for ProxyJump/-J options passed via the command-line (no such validation is performed for this option in configuration files). This prevents shell injection in situations where these were directly exposed to adversarial input, which would have been a terrible idea to begin with. Reported by rabbit.
Changes since OpenSSH 10.2 ==========================
This release contains some relatively minor security fixes as well as a number of feature improvements and general bugfixes.
Security ========
ssh(1): validation of shell metacharacters in user names supplied on the command-line was performed too late to prevent some situations where they could be expanded from %-tokens in sshconfig. For certain configurations, such as those that use a "%u" token in a "Match exec" block, an attacker who can control the user name passed to ssh(1) could potentially execute arbitrary shell commands. Reported by Florian Kohnhäuser.
We continue to recommend against directly exposing ssh(1) and other tools' command-lines to untrusted input. Mitigations such as this can not be absolute given the variety of shells and user configurations in use.
sshd(8): when matching an authorizedkeys principals="" option against a list of principals in a certificate, an incorrect algorithm was used that could allow inappropriate matching in cases where a principal name in the certificate contains a comma character. Exploitation of the condition requires an authorizedkeys principals="" option that lists more than one principal and a CA that will issue a certificate that encodes more than one of these principal names separated by a comma (typical CAs stronly constrain which principal names they will place in a certificate). This condition only applies to user- trusted CA keys in authorizedkeys, the main certificate authentication path (TrustedUserCAKeys/AuthorizedPrincipalsFile) is not affected. Reported by Vladimir Tokarev.
scp(1): when downloading files as root in legacy (-O) mode and without the -p (preserve modes) flag set, scp did not clear setuid/setgid bits from downloaded files as one might typically expect. This bug dates back to the original Berkeley rcp program. Reported by Christos Papakonstantinou of Cantina and Spearbit.
sshd(8): fix incomplete application of PubkeyAcceptedAlgorithms and HostbasedAcceptedAlgorithms with regard to ECDSA keys. Previously if one of these directives contains any ECDSA algorithm name (say "ecdsa-sha2-nistp384"), then any other ECDSA algorithm would be accepted in its place regardless of whether it was listed or not. Reported by Christos Papakonstantinou of Cantina and Spearbit.
ssh(1): connection multiplexing confirmation (requested using "ControlMaster ask/autoask") was not being tested for proxy mode multiplexing sessions (i.e. "ssh -O proxy ..."). Reported by Michalis Vasileiadis.
New features ------------
ssh(1), sshd(8): support IANA-assigned codepoints for SSH agent forwarding, as per draft-ietf-sshm-ssh-agent. Support for the new names is advertised via the EXTINFO message. If a server offers support for the new names, then they are used preferentially.
Support for the pre-standardisation "@openssh.com" extensions for agent forwarding remains supported.
ssh-agent(1): implement support for draft-ietf-sshm-ssh-agent "query" extension.
ssh-add(1): support querying the protocol extensions via the agent "query" extension with a new -Q flag.
ssh(1): support multiple files in a sshconfig RevokedHostKeys directive. bz3918
sshd(8): support multiple files in a sshdconfig RevokedKeys directive bz3918
ssh(1): add a ~I escape option that shows information about the current SSH connection.
ssh(1): add an "ssh -Oconninfo user@host" multiplexing command that shows connection information, similar to the ~I escapechar.
ssh(1): add an "ssh -O channels user@host" multiplexing command to get a running mux process to show information about what channels are currently open.
sshd(8): add 'invaliduser' penalty to PerSourcePenalties, which is applied to login attempts for usernames that do not match real accounts. Defaults to 5s to match 'authfail' but allows administrators to block such attempts for longer if desired.
sshd(8): add a GSSAPIDelegateCredentials option for the server, controlling whether it accepts delegated credentials offered by the client. This option mirrors the same option in sshconfig. GHPR614
ssh(1), sshd(8): support the VA DSCP codepoint in the IPQoS directive.
sshd(8): convert PerSourcePenalties to using floating point time, allowing penalties to be less than a second. This is useful if you need to penalise things you expect to occur at >=1 QPS.
ssh-keygen(1): support writing ED25519 keys in PKCS8 format. GHPR570
Support the ed25519 signature scheme via libcrypto.
Bugfixes --------
sshd(8): make IPQoS first-match-wins in sshdconfig, like other configuration directives. bz3924
sshd(8): fix potential crash when MaxStartups is using a single argument (i.e. not using the MaxStartps x:y:z form) to a value below 10. bz3941
sshd(8): fix a potential hang during key exchange if needed DH group values were missing from /etc/moduli.
ssh-agent(1): fix return values from extensions to be correct wrt draft-ietf-sshm-ssh-agent: extension requests should indicate failure using SSHAGENTEXTENSIONFAILURE rather than the generic SSHAGENTFAILURE error code. This allows the client to discern between "the request failed" and "the agent doesn't support this extension".
ssh(1): use fmprintf for showing challenge-response name and info to preserve UTF-8 characters where appropriate. Prompted by GitHub PR#452.
scp(1): when uploading a directory using sftp/sftp (e.g. during a recursive transfer), don't clobber the remote directory permissions unless either we created the directory during the transfer or the -p flag was set. bz3925
All: implement missing pieces of FIDO/webauthn signature support, mostly related to certificate handling and enable acceptance of this signature format by default. bz3748 GHPR624 GHPR625
sshdconfig(5): make it clear that DenyUsers/DenyGroups overrides AllowUsers/AllowGroups. Previously we specified the order in which the directives are processed but it was ambiguous as to what happened if both matched.
ssh(1): don't try to match certificates held in an agent to private keys. This matching is done to support certificates that were loaded without their private key material, but is unnecessary for agent-hosted certificate which always have private key material available in the agent. Worse, this matching would mess up the request sent to the agent in such a way as to break usage of these keys when the key usage was restricted in the agent. bz3752
sftp(1): if editline has been switched to vi mode (i.e. via "bind -v" in .editrc), setup a keybinding so that command mode can be entered.
ssh(1), sshd(8): improve performance of keying the sntrup761 key agreement algorithm.
ssh(1), sshd(8): enforce maximum packet/block limit during pre-authentication phase.
sftp(1): don't misuse the sftp limits extension's open-handles field. This value is supposed to be the number of handles a server will allow to be opened and not a number of outstanding read/write requests that can be sent during an upload/download.
sshd(8): don't crash at connection time if the main sshdconfig lacks any subsystem directive but one is defined in a Match block. bz3906
sshdconfig(5): add a warning next to the ForceCommand directive that forcing a command doesn't automatically disable forwarding.
sshdconfig(5): add a warning that TOKENS are replaced without filtering or escaping and that it's the administrator's responsibility to ensure they are used safely in context.
scp(1): correctly quote filenames in verbose output for local-> local copies. bz3900
sshd(8): don't mess up the PerSourceNetBlockSize IPv6 mask if sscanf didn't decode it. GHPR598
ssh-add(1): when loading FIDO2 resident keys, set the comment to the FIDO application string. This matches the behaviour of ssh-keygen -K. GHPR608
sshd(8): don't strnvis() log messages that are going to be logged by sshd-auth via its parent sshd-session process, as the parent will also run them though strnvis(). Prevents double-escaping of non-printing characters in some log messages. bz3896
ssh-agent(1): escape SSHAUTHSOCK paths that are sent to the shell as setenv commands. Unbreaks ssh-agent for home directory paths that contain whitespace. bz3884
All: Remove unnecessary checks for ECDSA public key validity.
sshd(8): activate UnusedConnectionTimeout only after the last channel has closed. Previously UnusedConnectionTimeout could fire early after a ChannelTimeout. This was not a problem for the OpenSSH client because it terminates once all channels have closed but could cause problems for other clients (e.g. API clients) that do things differently. bz3827
All: fix PKCS#11 key PIN entry problems introduced in openssh-10.1/10.2. bz3879
scp(1): when using the SFTP protocol for transfers, fix implicit destination path selection when source path ends with "..". bz3871
sftp(1): when tab-completing a filename, ensure that the completed string does not end up mid-way through a multibyte character, as this will cause a fatal() later on. GHPR#587
ssh-keygen(1): fix crash at exit (visible via ssh-keygen -D) when multiple keys loaded.
scp(1)/sftp(1): correctly display bandwidths >2GBps in the progress meter.
Portability -----------
sshd(8): fix condition intoduced in openssh 10.2p1 stable branch here a PAM module that changed the requested username between SSHMSGUSERAUTHREQUEST messages during authentication could confuse the PAM stack and let it proceed with a different understanding of the active username than the rest of sshd. Reported by Mike Damm.
sshd(8): immediately report interactive instructions to clients when using keyboard-interactive authentication with PAM. bz2876
sshd(8): fix duplicate PAM messages under some situations.
sshd(8): don't leak PAM handle on repeat invocations. bz3882
All: support linking libcrypto implementations (e.g. BoringSSL) that require libstdc++.
sshd(8): fix uttype for btmp records, correctly using LOGINPROCESS and USERPROCESS.
sshd(8): allow uname(3) in the seccomp sandbox. This is needed by zlib-ng on RISC-V platforms.
All: remove remaining OpenSSLaddallalgorithms() calls. We already have OPENSSLinitcrypto() in the compat layer. Prompted by github PR#606
All: fix builds on older Mac OS wrt nfdst.
mdoc2man: several improvements including better support for Dl and Ns inside Ic.
Checksums: ==========
- SHA1 (openssh-10.3.tar.gz) = 854863c04cd28242d73ac6c3ee9c37fa756f1a2f - SHA256 (openssh-10.3.tar.gz) = aCU5P47rM+m4N8/i2JOHMOMhafMYqBhvQQSnPXczN5M=
- SHA1 (openssh-10.3p1.tar.gz) = 9c78838ec07af14aff54f3755ac56ce6812452a9 - SHA256 (openssh-10.3p1.tar.gz) = VmgqNruS3PS08Bb9jsjnQFm3mo3iXBXWcNcx59GORfQ=
Please note that the SHA256 signatures are base64 encoded and not hexadecimal (which is the default for most checksum tools). The PGP key used to sign the releases is available from the mirror sites: https://cdn.openbsd.org/pub/OpenBSD/OpenSSH/RELEASEKEY.asc
Reporting Bugs: ===============
- Please read https://www.openssh.com/report.html Security bugs should be reported directly to openssh () openssh com
Dear Alexander,
On Wed, Mar 18, 2026 at 3:09 PM Solar Designer <solar () openwall com> wrote: Hi Dmitry,
On Wed, Mar 18, 2026 at 09:14:31AM +0100, Dmitry Belyavskiy wrote: Can we somehow establish some better coordination in case of widely used downstream patches, especially for such an important, ubiquitous and heavily patched component as OpenSSH? This was brought to the distros list on March 5. On March 6, I wrote:
"Looks like Red Hat packages are also affected. In particular, I looked at openssh-8.0p1-gssapi-keyex.patch from RHEL 9."
so it's not like Red Hat could assume this was limited to Debian/Ubuntu.
I now recall that something similar happened on a previous occasion, where you were not aware of a relevant issue until public disclosure.
So we seem to have a question to the Red Hat security team here - are you going to be informing your package maintainers of embargoed issues (which I consider fitting the need-to-know condition of the distros list), or are you deliberately handling them differently, or neither? Thanks, I will investigate it. I suppose this could reasonably vary by package - security updates to be prepared by security team vs. by package maintainer.
Should I be taking care of notifying Dmitry for OpenSSH specifically, where we know that he's eager to prepare for these disclosures but is often left out of the loop? IIRC, from the previous occasion I actually planned to start doing that, but I forgot, I'm sorry. No problem, thank you! I think OpenSSH, being heavily patched, deserves some special procedure, and can invite you to the discussion, if you are interested.
Meanwhile, I see the Mitigation section in https://access.redhat.com/security/cve/cve-2026-3497 has been updated to correctly refer to GSSAPI key exchange rather than authentication, but it still seems to imply the default configuration is affected - which I think it is not, or is it? I don't think so; I'll double-check. I wasn't too concerned about this issue for the Rocky Linux SIG/Security package that I maintain because we build it without Kerberos and GSSAPI support since March 2024. The patch is still applied, but the GSSAPIKeyExchange setting does not exist for real (is silently ignored via an extra patch for compatibility with FIPS configs that disable it), so it can't possibly be enabled there. Ditto in CIQ's RLC Pro Hardened. Thank you very much!
-- Dmitry Belyavskiy
Hi Dmitry,
On Wed, Mar 18, 2026 at 09:14:31AM +0100, Dmitry Belyavskiy wrote: Can we somehow establish some better coordination in case of widely used downstream patches, especially for such an important, ubiquitous and heavily patched component as OpenSSH? This was brought to the distros list on March 5. On March 6, I wrote:
"Looks like Red Hat packages are also affected. In particular, I looked at openssh-8.0p1-gssapi-keyex.patch from RHEL 9."
so it's not like Red Hat could assume this was limited to Debian/Ubuntu.
I now recall that something similar happened on a previous occasion, where you were not aware of a relevant issue until public disclosure.
So we seem to have a question to the Red Hat security team here - are you going to be informing your package maintainers of embargoed issues (which I consider fitting the need-to-know condition of the distros list), or are you deliberately handling them differently, or neither?
I suppose this could reasonably vary by package - security updates to be prepared by security team vs. by package maintainer.
Should I be taking care of notifying Dmitry for OpenSSH specifically, where we know that he's eager to prepare for these disclosures but is often left out of the loop? IIRC, from the previous occasion I actually planned to start doing that, but I forgot, I'm sorry.
Meanwhile, I see the Mitigation section in https://access.redhat.com/security/cve/cve-2026-3497 has been updated to correctly refer to GSSAPI key exchange rather than authentication, but it still seems to imply the default configuration is affected - which I think it is not, or is it?
I wasn't too concerned about this issue for the Rocky Linux SIG/Security package that I maintain because we build it without Kerberos and GSSAPI support since March 2024. The patch is still applied, but the GSSAPIKeyExchange setting does not exist for real (is silently ignored via an extra patch for compatibility with FIPS configs that disable it), so it can't possibly be enabled there. Ditto in CIQ's RLC Pro Hardened.
Alexander
Dear colleagues,
Thanks for sharing your findings! Can we somehow establish some better coordination in case of widely used downstream patches, especially for such an important, ubiquitous and heavily patched component as OpenSSH?
On Thu, Mar 12, 2026 at 7:09 PM Marc Deslauriers < marc.deslauriers () canonical com> wrote: Hello,
Jeremy Brown discovered a security issue in the GSSAPI Key Exchange patch a lot of distros carry on top of the OpenSSH package.
Unfortunately, there seems to be quite a few different versions of this patch being used, but a lot of them share the same core issue. Different compiler options also result in different outcomes, so the severity of this issue varies.
We have assigned CVE-2026-3497 to this issue.
Attached is the full pdf from the reporter, along with the patch we used in Ubuntu. I suggest reading the full pdf, but I have extracted some of the most important excerpts from it:
"The patch contains a code defect where sshpktdisconnect() (a non-terminating function that queues a disconnect message and returns) is used where sshpacketdisconnect()(which terminates the process) was intended. This causes the default: error-handling case in the GSSAPI KEX server loop to fall through into code that reads an uninitialized stack variable (recvtok), sends its contents to the privileged monitor process via IPC, and then passes it to gssreleasebuffer() which may call free() on a garbage pointer."
"Bug: Non-terminating error handler (sshpktdisconnect) in GSSAPI KEX server code allows fallthrough to uninitialized variable use
- Impact: Pre-auth uninitialized pointer dereference (CWE-824, CWE-908); confirmed heap corruption via free() on uninitialized pointer (SIGABRT on x8664); privsep boundary violation (up to 127KB of heap data to root monitor via IPC); SIGSEGV (signal 11) and SIGABRT (signal 6) on x8664 with 90-second SSH lockout; 100% reliable child process crash
- Trigger: Single crafted SSH packet (~300 bytes), no authentication or credentials needed
- Potentially Affected: Ubuntu/Debian OpenSSH servers with GSSAPIKeyExchange yes
- Potential Fix: Replace sshpktdisconnect() with sshpacketdisconnect() at the 3 server-side call sites in kexgsss.c"
"The uninitialized recvtok contains different stack residue depending on compiler, optimization level, and flags."
"Different compilers produce fundamentally different residue. Clang -O0 leaves 0xfffbe600 with length 4. GCC -O2 -fno-stack-protector leaves a valid heap address with length 127344. The 8-build matrix shows that recvtok.value ranges from NULL to stack addresses to heap addresses to unmapped addresses."
Thanks,
Marc. -- Marc Deslauriers Ubuntu Security Engineer | http://www.ubuntu.com/ Canonical Ltd. | http://www.canonical.com/ -- Dmitry Belyavskiy
Dear Alexander,
Thanks for notifying! Yes, GSSAPIKeyExchange should be mentioned instead of GSSAPIAuthentication.
On Sat, Mar 14, 2026 at 8:50 PM Solar Designer <solar () openwall com> wrote: On Thu, Mar 12, 2026 at 02:03:23PM -0400, Marc Deslauriers wrote: Jeremy Brown discovered a security issue in the GSSAPI Key Exchange patch a lot of distros carry on top of the OpenSSH package. I'm Bcc'ing Jeremy on this. Thank you for discovering and reporting the issue, Jeremy! Unfortunately, there seems to be quite a few different versions of this patch being used, but a lot of them share the same core issue. Different compiler options also result in different outcomes, so the severity of this issue varies.
We have assigned CVE-2026-3497 to this issue.
Attached is the full pdf from the reporter, along with the patch we used in Ubuntu. I suggest reading the full pdf, but I have extracted some of the most important excerpts from it:
"The patch contains a code defect where sshpktdisconnect() (a non-terminating function that queues a disconnect message and returns) is used where sshpacketdisconnect()(which terminates the process) was intended. This causes the default: error-handling case in the GSSAPI KEX server loop to fall through into code that reads an uninitialized stack variable (recvtok), sends its contents to the privileged monitor process via IPC, and then passes it to gssreleasebuffer() which may call free() on a garbage pointer."
"Bug: Non-terminating error handler (sshpktdisconnect) in GSSAPI KEX server code allows fallthrough to uninitialized variable use
- Impact: Pre-auth uninitialized pointer dereference (CWE-824, CWE-908); confirmed heap corruption via free() on uninitialized pointer (SIGABRT on x8664); privsep boundary violation (up to 127KB of heap data to root monitor via IPC); SIGSEGV (signal 11) and SIGABRT (signal 6) on x8664 with 90-second SSH lockout; 100% reliable child process crash
- Trigger: Single crafted SSH packet (~300 bytes), no authentication or credentials needed
- Potentially Affected: Ubuntu/Debian OpenSSH servers with GSSAPIKeyExchange yes Red Hat has now acknowledged that RHEL 8, 9, 10 are also affected (but 6 and 7 are not):
https://access.redhat.com/security/cve/cve-2026-3497
They suggest setting "GSSAPIAuthentication no" to mitigate this, which I find puzzling. Per the brief discussion we had on the distros list pre-disclosure, it appeared that GSSAPIKeyExchange is the option, and moreover it was said that GSSAPIKeyExchange could conceivably be used without GSSAPIAuthentication. So which of these two options is/are actually responsible for exposing the vulnerability? Does it maybe vary by patch revision (Debian vs. Red Hat) or (more likely?) is this just an error in the current Red Hat statement?
Also, the statement is worded such that it's implied the default configuration is affected and the mitigation needs to be applied, but prior understanding was that these features are disabled by default. - Potential Fix: Replace sshpktdisconnect() with sshpacketdisconnect() at the 3 server-side call sites in kexgsss.c"
"The uninitialized recvtok contains different stack residue depending on compiler, optimization level, and flags."
"Different compilers produce fundamentally different residue. Clang -O0 leaves 0xfffbe600 with length 4. GCC -O2 -fno-stack-protector leaves a valid heap address with length 127344. The 8-build matrix shows that recvtok.value ranges from NULL to stack addresses to heap addresses to unmapped addresses." Thank you for bringing this to oss-security, Marc!
Alexander -- Dmitry Belyavskiy
On Thu, Mar 12, 2026 at 02:03:23PM -0400, Marc Deslauriers wrote: Jeremy Brown discovered a security issue in the GSSAPI Key Exchange patch a lot of distros carry on top of the OpenSSH package. I'm Bcc'ing Jeremy on this. Thank you for discovering and reporting the issue, Jeremy! Unfortunately, there seems to be quite a few different versions of this patch being used, but a lot of them share the same core issue. Different compiler options also result in different outcomes, so the severity of this issue varies.
We have assigned CVE-2026-3497 to this issue.
Attached is the full pdf from the reporter, along with the patch we used in Ubuntu. I suggest reading the full pdf, but I have extracted some of the most important excerpts from it:
"The patch contains a code defect where sshpktdisconnect() (a non-terminating function that queues a disconnect message and returns) is used where sshpacketdisconnect()(which terminates the process) was intended. This causes the default: error-handling case in the GSSAPI KEX server loop to fall through into code that reads an uninitialized stack variable (recvtok), sends its contents to the privileged monitor process via IPC, and then passes it to gssreleasebuffer() which may call free() on a garbage pointer."
"Bug: Non-terminating error handler (sshpktdisconnect) in GSSAPI KEX server code allows fallthrough to uninitialized variable use
- Impact: Pre-auth uninitialized pointer dereference (CWE-824, CWE-908); confirmed heap corruption via free() on uninitialized pointer (SIGABRT on x8664); privsep boundary violation (up to 127KB of heap data to root monitor via IPC); SIGSEGV (signal 11) and SIGABRT (signal 6) on x8664 with 90-second SSH lockout; 100% reliable child process crash
- Trigger: Single crafted SSH packet (~300 bytes), no authentication or credentials needed
- Potentially Affected: Ubuntu/Debian OpenSSH servers with GSSAPIKeyExchange yes Red Hat has now acknowledged that RHEL 8, 9, 10 are also affected (but 6 and 7 are not):
https://access.redhat.com/security/cve/cve-2026-3497
They suggest setting "GSSAPIAuthentication no" to mitigate this, which I find puzzling. Per the brief discussion we had on the distros list pre-disclosure, it appeared that GSSAPIKeyExchange is the option, and moreover it was said that GSSAPIKeyExchange could conceivably be used without GSSAPIAuthentication. So which of these two options is/are actually responsible for exposing the vulnerability? Does it maybe vary by patch revision (Debian vs. Red Hat) or (more likely?) is this just an error in the current Red Hat statement?
Also, the statement is worded such that it's implied the default configuration is affected and the mitigation needs to be applied, but prior understanding was that these features are disabled by default. - Potential Fix: Replace sshpktdisconnect() with sshpacketdisconnect() at the 3 server-side call sites in kexgsss.c"
"The uninitialized recvtok contains different stack residue depending on compiler, optimization level, and flags."
"Different compilers produce fundamentally different residue. Clang -O0 leaves 0xfffbe600 with length 4. GCC -O2 -fno-stack-protector leaves a valid heap address with length 127344. The 8-build matrix shows that recvtok.value ranges from NULL to stack addresses to heap addresses to unmapped addresses." Thank you for bringing this to oss-security, Marc!
Alexander
The function matchpattern() is used to match conditionals in client configuration files or known hosts against the hostname the client is connecting to.
When the configuration file or knownhosts file is controlled by the attacker, connecting to specific hostnames could cause timeouts and resource exhaustion due to the ineffective backtracking of complex regular expressions.
The pattern matching was modified to avoid the needless backtracing.
A malicious SCP server can send unexpected paths that could make the client application override local files outside of working directory. This could be misused to create malicious executable or configuration files and make the user execute them under specific consequences.
This is the same issue as in OpenSSH, tracked as CVE-2019-6111.