russh CVE-2026-111062
LOWAttack ChainAIDerived
Hypothetical attack flow derived from CVE metadata – not a confirmed exploit chain
-
AccessConnect with authorized RSA key
-
ExploitAnnounce rsa-sha2-512 in publickey request
-
ExecutionAttach ssh-rsa SHA-1 signature
-
ImpactServer accepts, bypassing algorithm policy
Vulnerability Assessment
| Weakness |
CWE
OWASP Top 10:2025
A04:2025 - Cryptographic Failures
ASVS 5.0
V11 - Cryptography Signature verification
|
| Exploitation Conditions | Exploitation requires the attacker to already possess a valid RSA private key that the russh-based SSH server accepts for publickey authentication - it grants nothing to anyone without an authorized key. It only has security impact on servers that rely on the requested algorithm name: specifically servers configured to reject SHA-1 (ssh-rsa) signatures (as OpenSSH does by default since 8.8) or servers that log/audit which signature algorithm a client authenticated with. Limiting factors: russh clients are unaffected; authentication strength beyond the hash choice is unchanged because a valid signature by the private key is still mandatory; and servers that neither enforce an algorithm policy nor record the algorithm are effectively unaffected. Authentication requirements are not confirmed from CVSS (none provided), but the description establishes that a valid authorized RSA key is a prerequisite. |
| Impact | Key quantitative signals are absent: no CVSS score or vector, no EPSS probability, and no CISA KEV listing are provided in the input, so there is no evidence of active exploitation or high exploitation likelihood. A working proof-of-concept (a self-contained unit test) is published in the vendor advisory, but PoC availability is not the same as in-the-wild exploitation. Crucially, the described impact is narrow and does NOT constitute an authentication bypass: the attacker must already hold a valid RSA private key that the server would accept, and a cryptographically valid signature by that key is still required. The flaw (CWE-347, improper verification of a signature's algorithm) only lets a legitimate key holder downgrade the signature hash (e.g. present an ssh-rsa/SHA-1 signature for a request announcing rsa-sha2-512) or cause the server to mis-record the algorithm. Real-world priority is therefore low-to-moderate: it matters almost exclusively to russh-based SSH servers that enforce an algorithm policy (e.g. refusing SHA-1 like OpenSSH 8.8+) or that log/audit the authenticating signature algorithm for compliance. Because no CVSS vector was supplied, authentication requirements cannot be asserted as a CVSS-derived fact, though the description makes a valid authorized key a hard prerequisite. Absence of EPSS/KEV data should be read as 'not provided,' not as 'confirmed safe.' |
| Exploit ScenarioDerived | A user holding a valid RSA key that is authorized on a russh-based SSH server - one configured to reject SHA-1 (ssh-rsa) signatures or to audit the signature algorithm used - sends a publickey authentication request that announces rsa-sha2-512 while attaching an ssh-rsa (SHA-1) signature. russh verifies the signature using the algorithm in the signature blob rather than the announced one, so authentication succeeds and the SHA-1 ban / audit record is bypassed. A reproducible PoC unit test is published in the vendor's GHSA advisory. |
Get an e-mail when this CVE is exploited, patched or re-scored. Free account.
Alert meAnalysisAIv1 – Oct 19, 2026
Signature-algorithm confusion in the russh Rust SSH server library (every release from 0.34.0-beta.1 through 0.63.3, plus main) allows a client to announce one publickey algorithm (e.g. rsa-sha2-512) while presenting a signature made with a different one (e.g. ssh-rsa/SHA-1) and still be authenticated, because the requested algorithm name is never compared against the signature's own algorithm. The practical impact is limited: the attacker must already hold an RSA private key that the server accepts, so authentication strength is not weakened - only servers that rely on the announced algorithm to block SHA-1 signatures (as OpenSSH does by default since 8.8) or to record/audit which algorithm a user authenticated with are meaningfully affected, giving low integrity impact. No CISA KEV listing, no EPSS score and no CVSS vector were supplied, so there is no evidence of active exploitation; the upstream advisory does include a proof-of-concept unit test that reproduces the acceptance of a SHA-1 signature, and the vendor has released a fix in 0.64.0.
RemediationAI
Upgrade to russh 0.64.0, the vendor-released version that adds the missing comparison between the announced algorithm and sig.algorithm() (release tag https://github.com/Eugeny/russh/releases/tag/v0.64.0; advisory https://github.com/Eugeny/russh/security/advisories/GHSA-j7h2-66j4-ghjf). Note that the patch commit referenced in the advisory data (a0ded76bdc352f8fbeaaeb175fb2a0c586fbc8f2) shows unrelated global-request plumbing in its diff, so treat the tagged 0.64.0 release, not the diff alone, as the authoritative fix and verify the added check is present in your vendored copy. If upgrading is not immediately possible, the practical compensating control is to stop trusting the algorithm name: do not rely on russh's announced-algorithm value for policy enforcement or audit records, and instead treat any RSA authentication as potentially SHA-1 signed - the trade-off is that you lose the ability to block SHA-1 via this field at all, and log entries naming rsa-sha2-512 become unreliable. A stronger but more disruptive workaround is to reject RSA keys entirely at the Handler::auth_publickey stage and require Ed25519 or ECDSA client keys, which removes the multi-algorithm ambiguity but forces key rotation for every RSA user. Servers that neither enforce an algorithm policy nor log the algorithm need no urgent action beyond normal upgrade cadence, since a valid signature from an authorized private key is still mandatory in every case.
Affected Packages
Source: OSV (Open Source Vulnerabilities)
Affects your stack
Affects 1 package in cargo
Checking this CVE against your own stacks and servers is part of the Basic plan and up.
Technical ContextAI · show details
russh is a Rust implementation of the SSH protocol (forked from thrussh) that uses the ssh-key crate for key and signature primitives. Under RFC 8332 §3, the signature algorithm in a publickey authentication request must match the algorithm name carried in the request, which is how servers enforce a policy such as 'no SHA-1'. In russh's server_read_auth_request_pk (russh/src/server/encrypted.rs), the announced name (pubkey_algo) is used only to decode the key via PublicKeyOrCertificate::decode; the derived hash algorithm is then discarded. The signature blob is decoded separately with Signature::decode, and ssh-key selects the digest from the signature's own algorithm (sig.algorithm()) when Verifier::verify runs. Since pubkey_algo and sig.algorithm() are never compared, an RSA key can sign with SHA-1 while the request claims rsa-sha2-512, verification succeeds, and Handler::auth_publickey is invoked. The flaw is CWE-347 (improper verification of cryptographic signature) and is inherited from thrussh 0.33.5. The mechanism shifted over time - releases up to 0.46 overwrote the key's hash with the algorithm read from the signature blob (pubkey.set_algorithm(algo_)), while 0.47/0.48 onward (after the migration to ssh-key) decode and verify the signature with its embedded algorithm - but the outcome is identical across versions. Only RSA keys (which admit several signature algorithms) were examined; other key types were not tested, and russh clients are not affected.
Know when SSH gets its next vulnerability
- Watch products and get an email when something new is published
- Check this CVE against your own stack and servers
- Exploit and PoC references, threat intelligence from 22 sources
No credit card · 7-day full trial
Severity by source
Remote over SSH (AV:N) but requires a valid authorized RSA key (PR:L); impact is limited to bypassing signature-algorithm policy and audit integrity (I:L), with no confidentiality or availability effect.
DescriptionCVE.org
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 private = Arc::new(PrivateKey::from(rsa));
let mut session = test_auth_session();
let mut handler = AcceptAnyKey::default();
// The request says rsa-sha2-512; the signature blob is ssh-rsa (SHA-1).
let packet = signed_request_announcing("alice", private, "rsa-sha2-512", None);
session.process_packet(&mut handler, &packet).await.unwrap();
// RFC 8332 §3: the signature algorithm must be the requested one, so
// this request must be rejected. On russh 0.63.3 it is accepted.
assert!(
!handler.authenticated,
"an ssh-rsa (SHA-1) signature was accepted for a request announcing rsa-sha2-512"
);
}Result on unmodified 0.63.3:
test server::encrypted::tests::poc_sha1_signature_accepted_when_rsa_sha2_512_is_announced ... FAILED
panicked at src/server/encrypted.rs: an ssh-rsa (SHA-1) signature was accepted for a request announcing rsa-sha2-512With the fix below, the test passes and the whole library suite still passes: cargo test --lib gives 186 passed.
Suggested fix: reject a mismatch through the existing reject_auth_request(until, ...) path, so the constant rejection time is kept.
--- a/russh/src/server/encrypted.rs
+++ b/russh/src/server/encrypted.rs
@@ -1023,6 +1023,21 @@
map_err!(ensure_end(&signature_reader))?;
map_err!(ensure_end(r))?;
+ // RFC 8332 §3: the signature must use the algorithm the
+ // request names.
+ let offered_algorithm = match pk_or_cert {
+ PublicKeyOrCertificate::PublicKey { .. } => ssh_key::Algorithm::new(&pubkey_algo),
+ PublicKeyOrCertificate::Certificate(_) => {
+ <ssh_key::Algorithm as crate::helpers::AlgorithmExt>::new_certificate_ext(&pubkey_algo)
+ }
+ };
+ if offered_algorithm.ok().as_ref() != Some(&sig.algorithm()) {
+ debug!("signature algorithm does not match the requested one");
+ auth_user.clear();
+ reject_auth_request(until, &mut self.write, auth_request).await?;
+ return Ok(());
+ }
+
let is_valid = if accepted_probe_matches && user == auth_user {
true
} else {Impact
This is a missing check on the signature algorithm (improper verification of a cryptographic signature's algorithm, CWE-347) in the server's publickey authentication.
Who is impacted: applications that use russh as an SSH server and rely on the requested algorithm to restrict, record or audit user-key signature algorithms. For example:
- a server that refuses SHA-1 (
ssh-rsa) signatures, as OpenSSH does by default since 8.8; - a server that logs which algorithm a client authenticated with.
Such a server can be made to accept a SHA-1 signature, or to record rsa-sha2-512 for one, by any holder of a valid RSA key.
Not impacted:
- russh clients;
- authentication strength beyond the choice of hash, since a valid signature by the private key is still required;
- Te RSA keys were examined, the case where one key admits several signature algorithms (
ssh-rsa,rsa-sha2-256,rsa-sha2-512). We did not test other key types.
Threat Intelligence Overview
How this decision was reached
The engine reads each signal below and applies a fixed list of rules from top to bottom. The first rule that matches sets the recommended action – like a statement, every line is shown.
What every action level means
Attack Technique
Information disclosure occurs when an application unintentionally exposes sensitive data that aids attackers in reconnaissance or directly compromises security.
Affected Products (CPE)CVE.org
GNU Bash through 4.3 processes trailing strings after function definitions in the values of environment variables, which
GNU Bash through 4.3 bash43-026 does not properly parse function definitions in the values of environment variables, whi
GNU Bash through 4.3 bash43-025 processes trailing strings after certain malformed function definitions in the values of
freeSSHd.exe in freeSSHd through 1.2.6 allows remote attackers to bypass authentication via a crafted session, as demons
GNU Bash through 4.3 bash43-026 does not properly parse function definitions in the values of environment variables, whi
The PKCS#11 feature in ssh-agent in OpenSSH before 9.3p2 has an insufficiently trustworthy search path, leading to remot
OpenSSH server (sshd) 9.1 introduced a double-free vulnerability during options.kex_algorithms handling. Rated medium se
sshd in OpenSSH before 7.3, when SHA256 or SHA512 are used for user password hashing, uses BLOWFISH hashing on a static
The kbdint_next_device function in auth2-chall.c in sshd in OpenSSH through 6.9 does not properly restrict the processin
The auth_password function in auth-passwd.c in sshd in OpenSSH before 7.3 does not limit password lengths for password a
Remote code execution in OpenSSH's sshd server (regression of CVE-2006-5051) allows unauthenticated remote attackers to
An issue was discovered in OpenSSH 7.9. Rated medium severity (CVSS 5.9), this vulnerability is remotely exploitable, no
GHSA-j7h2-66j4-ghjf
CVE.org
Exploit-DB