|
| SECURITY ADVISORY - StreamSec Tools 4.1.1.349 to 4.1.4.360, patch P01 An explicitly pinned SSH host key does not hold. | |
| Henrick Wibell Hellström 2026-10-06 09:54:53 Registered user |
AFFECTED RELEASES
StreamSec Tools 4.1.1.349 through 4.1.4.360. The vulnerability is in the dotted StreamSec.SSH.* component stack - the units StreamSec.SSH.Client, StreamSec.SSH.SocketClient, StreamSec.SSH.BaseComponent and StreamSec.SSH.Options, behind TstSSHSocketClient, TstSSHClient and TsnipClient. That stack entered the installed packages at 4.1.1.349 and has shipped in every release since. The release after 4.1.4.360 carries the fix; until it is published, patch P01 (StreamSec_Tools_4.1.4.360_P01_SshHostKeyPin.txt) carries the same fix as a manual source edit. THE TWO SSH BRANCHES, AND WHY THE RANGE STARTS AT 4.1.1.349 The library has carried two SSH component stacks with the same component names. The dotted StreamSec.SSH.* stack above is the one that ships today. It did not exist before 4.1.1.349: it entered the installed package in that release and replaced, in the same release, the older st-prefixed stack - stSSHClient, stSSHSocketClient, stSSHBaseComponent, stSSHOptions - which was the installed SSH stack up to and including 4.1.0.348 and has not been installed since. Its source stayed in the distribution, uninstalled, through 4.1.3.356, and was removed at 4.1.3.357; a program could still compile against it in that window. So a release before 4.1.1.349 is not unaffected because it "has no SSH client" - it has the st client. It is outside this advisory because the st branch is a different, narrower case: - it pins RSA and DSS host keys only, with no ECDSA or EdDSA pinning; - it registers no host-key verification entries of its own (the application wires them up), so the algorithm-family bypass that is the core of this vulnerability - an accept-any entry of an unpinned family defeating the pin - does not arise there by default. The st branch does share one lesser defect: a key component assigned to ServerRSAKey or ServerDSSKey before its key is loaded registers accept-any entries, so a client that pins by that route accepts any RSA (or DSS) key. Whether the st stack in a still-supported release of 4.1.0.348 or earlier warrants its own advisory is assessed separately; this patch does not change the st units, as the library leaves its superseded units unchanged. If you build against the st SSH units, say so when you report, with your release (SECURITY.txt, section 2). THE VULNERABILITY A client pins a server's host key by assigning a key component to ServerRSAKey, ServerDSSKey, ServerECDSAKey or ServerEdDSAKey. On the affected releases the pin does not hold: - The pin covered only its own algorithm family. The client also offers the other standard host-key algorithms with accept-any entries, and the SERVER chooses the algorithm. A machine-in-the-middle that presents a key of any other algorithm - its own key - is accepted without comparison against anything. - A pin that yielded no key accepted any key of its algorithm, silently: a component assigned before its key was loaded, an identifier that found nothing, an ECDSA public key (which registered nothing at all), or a TstSSHPublicKeyList assigned to ServerECDSAKey or ServerEdDSAKey. - A separate defect compounds the last case: a TstSSHPublicKeyList backed by a file (PublicKeyFileName) loaded no keys at all on these releases, so pins kept in a file silently became accept-any. - On a server, a host key that was un-assigned (the property set to nil) went on being offered and signing until another key was assigned. A client that pins nothing accepts the first host key a server presents. That is the documented out-of-the-box behaviour and is not part of this advisory; the vulnerability is that an explicit pin did not hold. IMPACT An attacker who can place themselves between a pinning client and its server - on the network path, or at a spoofed address - can present their own host key and complete the handshake as "the server". Everything the client then sends, including a password login, goes to the attacker, and everything it receives comes from them. The pin, which exists to prevent exactly this, does not prevent it. SEVERITY High. CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:H/VA:N/SC:N/SI:N/SA:N The attack is over the network (AV:N) and needs an active machine-in-the-middle position, a condition of the target environment (AT:P), with no privileges and no user interaction; it yields full confidentiality and integrity of the SSH session (VC:H/VI:H). Subsequent impact on systems reached THROUGH the session is left to environmental scoring and is not counted in this base vector. The decimal score is the one the official FIRST.org CVSS v4.0 calculator returns for this vector; read it there at publication rather than computing it by hand, as the v4.0 score is a table lookup, not a formula. WHAT TO DO Do ONE of the following. 1. Upgrade to the first release after 4.1.4.360 when it is published, and rebuild your application. 2. Apply patch P01 to your release's source and rebuild the packages and your application. The patch file states the nine edits; every replaced routine is byte-identical across all twelve affected releases. 3. Use the work-around below. AN APPLICATION THAT APPLIES THE WORK-AROUND IN FULL, AND WHOSE PINS ARE RSA, DSS OR ED25519 KEYS, IS PROTECTED WITHOUT THE PATCH: it does not need to apply P01 or to rebuild against patched sources. Pinning an ECDSA or Ed448 public key cannot be made to hold by the work-around (those pins register nothing on the affected releases) - pin an RSA or Ed25519 key of the same server instead, or apply the patch. THE WORK-AROUND In the application, when setting up the client (TstSSHSocketClient, TstSSHClient, or TsnipClient.SSHClient): a. Load the key component BEFORE assigning it to the ServerXxxKey property, and assign the property again whenever the key is loaded or changed afterwards. After assigning, read the property back and treat nil as a failed pin. b. After every pin is assigned, restrict the offered algorithms to the pinned ones by setting ServerKeyOptions.SelectedOptionNames to exactly the pinned algorithm names, and nothing else: RSA pin: rsa-sha2-256, rsa-sha2-512, ssh-rsa Ed25519 pin: ssh-ed25519 DSS pin: ssh-dss The server then cannot steer the handshake onto an unpinned algorithm, because none is offered; and a pinned entry compares fail-closed. c. Verify the setup once: connect to an endpoint that presents a different key. The client must fail with "Host key not verifiable". If it connects, the pin has not taken - re-check (a) and (b). d. If the pins are kept in a TstSSHPublicKeyList: add the keys at run time with SetPublicKey. A PublicKeyFileName file does not load on the affected releases. Assign the list only to ServerRSAKey or ServerDSSKey; assigned to ServerECDSAKey or ServerEdDSAKey it registers nothing. e. On a server, replace a host key by assigning the new key component; do not merely set the property to nil and continue running. CREDIT Found in an internal security review of the Snif/Snip framework and the SSH components. There is no evidence of exploitation. IDENTIFIER This advisory is identified by the releases it applies to and the patch number P01 (counted per release, at 4.1.4.360). CVE identifiers are not used (SECURITY.txt, section 4). Attachments: |