MittelCVE-2026-116774

    Eugeny Russh: Endlosschleife (CVE-2026-116774)

    Veröffentlicht Zuletzt geändert Quellen: OSV, CVE.org, EUVD, Hersteller

    Teilen

    Was ist betroffen, was ist zu tun

    Aktualisieren Sie russh auf Version 0.65.

    Betroffen
    • Eugeny Russh gte 0.60.0, < 0.65.0..*

    Unklar, ob und wie Sie betroffen sind? Frage zu dieser Schwachstelle stellen

    Metriken

    4,3

    XIEM Effective CVSS

    Höchste verfügbare CVSS-Bewertung aus NVD- und Herstellerangaben.

    Quelle: Hersteller (CNA), CVSS v3

    4,3

    CVSS v3

    Schweregrad Mittel auf der Skala von 0 bis 10.

    Quelle: OSV, CVE.org, EUVD, Hersteller

    0,3 %

    EPSS-Score

    Niedrig – Modell schätzt < 1 % Ausnutzungs-Wahrscheinlichkeit.

    Quelle: FIRST EPSS, Perzentil 17,8

    Alle Metriken anzeigen
    Schweregrad
    Mittel
    Priorität (0–325)

    Der Priorisierungs-Score ist eine zusammengeführte Kennzahl, die mehrere Einzelsignale zu einer einzigen, handlungsleitenden Rangfolge verdichtet: technische Schwere (CVSS), Ausnutzungswahrscheinlichkeit (EPSS), der Status als bekannt ausgenutzt (KEV) und der Kontext des betroffenen Assets. Ziel ist die Antwort auf die einzig wirklich wichtige Frage im Schwachstellenmanagement: Was zuerst?

    Im Glossar lesen
    54.03 Methodik
    Exploit-Reife

    Ein Exploit ist Code oder eine Technik, die eine konkrete Schwachstelle gezielt ausnutzt, um ein unbeabsichtigtes Verhalten zu erzwingen — etwa Code auszuführen oder Rechte auszuweiten. Er ist das Werkzeug, das aus einer theoretischen Lücke einen praktischen Angriff macht.

    Im Glossar lesen
    kein öffentlicher PoC bekannt
    XIEM Effective CVSS

    XIEM® ist das gestufte Managed-Security-Betriebsmodell von NEOSEC und eine eingetragene Marke der NEOSEC GmbH. Es erweitert klassisches SIEM — die zentrale Sammlung, Normalisierung und Korrelation sicherheitsrelevanter Ereignisse — um Endpunkt-Forensik, Netzwerk-Sichtbarkeit und Täuschungstechnik und führt diese zu drei aufeinander aufbauenden Stufen zusammen: Sentry, Orchestrate und Command.

    Im Glossar lesen
    4,3 Methodik
    CVSS v3

    CVSS ist der weltweit verbreitete, offene Standard zur Bewertung der technischen Schwere einer Schwachstelle auf einer Skala von 0 bis 10. Er beschreibt, wie leicht eine Lücke ausnutzbar ist und welchen Schaden sie anrichten kann — nicht jedoch, wie wahrscheinlich ihre tatsächliche Ausnutzung ist. CVSS und das ergänzende EPSS beantworten bewusst unterschiedliche Fragen.

    Im Glossar lesen
    4,3
    EPSS-Score

    Der EPSS-Score ist der absolute Modell-Output für eine einzelne Schwachstelle: die geschätzte Wahrscheinlichkeit einer realen Ausnutzung in den nächsten 30 Tagen, ausgedrückt als Wert zwischen 0 und 1 (bzw. 0 % bis 100 %). Ein Score von 0,42 bedeutet „das Modell schätzt eine 42-prozentige Chance auf reale Ausnutzung binnen 30 Tagen“.

    Im Glossar lesen
    0,3 %
    Niedrig – Modell schätzt < 1 % Ausnutzungs-Wahrscheinlichkeit.
    EPSS-Perzentil

    Das EPSS-Perzentil ist die relative Einordnung einer Schwachstelle innerhalb aller EPSS-bewerteten CVEs, ausgedrückt als Wert zwischen 0 und 1. Ein Perzentil von 0,90 bedeutet „diese CVE hat einen höheren EPSS-Score als 90 % aller anderen bewerteten CVEs“. Anders als der EPSS-Score ist es keine Wahrscheinlichkeit — sondern eine Positionierung im Ranking.

    Im Glossar lesen
    17,8
    Erhöht – CVE ist relevanter als mindestens 10 % der heute bewerteten CVEs.
    KEV-Status

    Der KEV-Katalog ist eine von der US-Behörde CISA gepflegte Liste von Schwachstellen, für die eine aktive Ausnutzung in der Praxis nachgewiesen ist. Er beantwortet nicht die Frage „wie schwer?“, sondern „wird es bereits angegriffen?“ — und priorisiert damit das Patchen scharf.

    Im Glossar lesen
    —
    Veröffentlicht
    CISA-Bewertung (SSVC)
    Ausnutzung: keine bekannt · nicht automatisierbar · Auswirkung: teilweise
    Quelle: CISA Vulnrichment, Stand 28. Oktober 2026
    CWE

    CWE ist ein Katalog typischer Schwächen-Arten in Software und Hardware — etwa fehlerhafte Eingabevalidierung, unsichere Speicherbehandlung oder mangelhafte Authentisierung. Während eine CVE eine konkrete Schwachstelle in einem konkreten Produkt benennt, beschreibt eine CWE die zugrunde liegende Fehlerklasse.

    Im Glossar lesen
    CWE-400, CWE-835

    Erkennungsregeln

    Für diese Schwachstelle liegt noch keine NEOSEC-Erkennungsregel vor.

    Einordnung nach NIS2 und CRA

    Regelbasierte Einordnung aus Ausnutzungsstatus und Schweregrad. Sie ersetzt keine Prüfung im Einzelfall.

    NIS2

    NIS2 ist die EU-Richtlinie (EU) 2022/2555 zur Erhöhung des Cybersicherheitsniveaus in der Union. Sie weitet Pflichten gegenüber der ersten NIS-Richtlinie deutlich aus: mehr Sektoren, verbindliches Risikomanagement, gestufte Meldepflichten und persönliche Verantwortung der Geschäftsleitung.

    Im Glossar lesen
    Behandeln Sie die Schwachstelle im regulären Schwachstellenmanagement nach Art. 21 Abs. 2 lit. e NIS2.
    CRA

    Der CRA ist die EU-Verordnung (EU) 2024/2847 mit horizontalen Cybersicherheitsanforderungen an „Produkte mit digitalen Elementen“ — von Industriesteuerungen über Software bis zu vernetzten Verbrauchergeräten. Erstmals müssen Hersteller Sicherheit über den gesamten Produktlebenszyklus gewährleisten, Schwachstellen behandeln und Sicherheitsupdates bereitstellen.

    Im Glossar lesen
    Ab dem 11.12.2027 verpflichtet Anhang I Teil II CRA Hersteller betroffener Produkte mit digitalen Elementen, Schwachstellen unverzüglich zu behandeln und Sicherheitsupdates bereitzustellen.
    ISO/IEC 27001

    ISO/IEC 27001 ist der international führende Standard für ein Informationssicherheits-Managementsystem (ISMS). Er beschreibt einen risikobasierten, prozessorientierten Rahmen, um Informationssicherheit systematisch zu planen, umzusetzen, zu überprüfen und zu verbessern.

    Im Glossar lesen
    Maßnahme A.8.8, Management technischer Schwachstellen: Relevanz für Ihre Systeme bewerten, Behebung einplanen und nachweisen.

    Beschreibung

    Summary

    A peer can advertise maximum packet size = 0 in its channel-open message (CHANNEL_OPEN when attacking a server, CHANNEL_OPEN_CONFIRMATION when attacking a client). russh accepts the value without validation and copies it into the channel write state, where it caps the size of every outgoing data chunk. In the AsyncWrite code path (ChannelTx::poll_writable, used by Channel::data(), Channel::make_writer() and Channel::into_stream()), a cap of 0 makes every write future stay Poll::Pending forever: writable = max_packet_size.min(window_size).min(buf_len) is always 0, and no future event can ever raise it (a static maximum packet size of 0 can never be satisfied by any amount of peer-granted window). The write neither completes nor errors, so the application task hangs silently.

    Every other write path in russh already treats max_packet_size == 0 as an error (Error::Inconsistent): Channel::reserve_writable_chunk (russh/src/channels/mod.rs:363-365) and the session packetizers (russh/src/session.rs:489-492 and 549-552). The AsyncWrite path is the only one that lacks the guard - it contradicts the crate's own invariant.

    Root cause

    (1) Peer value accepted without validation:

    • russh/src/parsing.rs:44 (OpenChannelMessage::parse): let maxpacket = map_err!(u32::decode(r))?; stored as recipient_maximum_packet_size (:25-30); no range check. Same for ChannelOpenConfirmation::decode at russh/src/parsing.rs:194-207.
    • The only packet-size validation anywhere is an upper bound on the local config that merely logs (russh/src/client/mod.rs:1189-1194, russh/src/server/mod.rs:912-917). Nothing validates the peer's value - 0 passes silently.

    (2) The value flows into the channel write state verbatim:

    • Server: russh/src/server/encrypted.rs:1877-1900 - ChannelParams { recipient_maximum_packet_size: msg.recipient_maximum_packet_size, .. }, then Channel::new(..., channel_params.recipient_maximum_packet_size, ...).
    • Client: russh/src/client/encrypted.rs:471-488 - parameters.confirm(&msg) (russh/src/lib_inner.rs:519-523) and ChannelMsg::Open { max_packet_size: msg.maximum_packet_size, .. }, consumed by wait_channel_confirmation (russh/src/client/mod.rs:698-722), which builds ChannelWriteHalf { max_packet_size, .. }.
    • The write half hands the value to the writer: make_writer_ext (russh/src/channels/mod.rs:433-441) and into_stream (russh/src/channels/mod.rs:661-670) pass self.max_packet_size to ChannelTx::new.

    (3) The hang - russh/src/channels/io/tx.rs:82-108 (current v0.64.1, byte-identical in v0.60.0):

    fn poll_writable(&mut self, cx: &mut Context<'_>, buf_len: usize) -> Poll<NonZeroUsize> {
        ...
        let writable = (self.max_packet_size).min(*window_size).min(buf_len as u32) as usize;
        match NonZeroUsize::try_from(writable) {
            Ok(w) => {
                *window_size -= writable as u32;
                if *window_size > 0 {
                    self.notify.notify_one();
                }
                Poll::Ready(w)
            }
            Err(_) => {
                drop(window_size);
                ready!(self.window_size_notication.poll_unpin(cx));
                self.window_size_notication = WatchNotification::new(Arc::clone(&self.notify));
                cx.waker().wake_by_ref();
                Poll::Pending
            }
        }
    }
    

    With max_packet_size == 0, writable is always 0 regardless of window_size and buf_len; the task parks on the window notification, gets re-polled on every CHANNEL_WINDOW_ADJUST, recomputes 0, and parks again - forever.

    (4) The guard exists everywhere else:

    // russh/src/channels/mod.rs:363-365 (used by send_bytes -> data_bytes / extended_data_bytes)
    if self.max_packet_size == 0 {
        return Err(Error::Inconsistent);
    }
    
    // russh/src/session.rs:490-492 and :550-552 (packetizer)
    if max_packet_size == 0 {
        return Err(crate::Error::Inconsistent);
    }
    

    Note that Channel::data(reader) (russh/src/channels/mod.rs:321-323) goes through send_data -> tokio::io::copy(&mut data, &mut tx) (:350-360) into the same ChannelTx, so the primary documented data API hangs as well; only the *_bytes variants reach the guard.

    Attack scenarios

    • Server (authenticated remote DoS): with the default configuration, an authenticated client opens a session channel advertising maximum packet size = 0. Whenever the server application writes on that channel through AsyncWrite (echo, shell prompts, SFTP - russh's own examples echo via into_stream()), the write future never completes. The handler task is stranded and no error surfaces, so application cleanup paths do not trigger. Repeat per channel and per connection; keep-alive traffic resets the server inactivity_timeout (default 600 s), so stranded resources persist as long as the attacker wants.
    • Client (malicious server): a malicious or buggy server confirms an opened channel with maximum packet size = 0; the client application's writes on that channel stall forever. The client inactivity_timeout defaults to None, so nothing ever tears the session down.
    • This is distinct from a window_size == 0 stall: a zero window is dynamic flow control that a well-behaved peer releases as soon as its buffers drain, while maximum packet size is a static peer declaration where 0 can never be satisfied by any future packet. RFC 4254 section 5.1 recommends a minimum of 32768 - legitimate peers do not send 0.

    Impact

    Permanent, silent denial of service for the affected writes, with stranded tasks/channels/connections that accumulate for the attacker - resource exhaustion of a server or of a client application. Because the failure mode is Poll::Pending instead of Err, ordinary application mitigations (error handling, timeouts on writes, connection teardown) do not engage on their own.

    Reproducer

    Two stock russh instances are enough (no raw SSH crafting required):

    1. Server: default config plus a host key; channel_open_session accepts and echoes using tokio::io::copy into channel.into_stream() (the pattern from russh's own examples).
    2. Client: default config except config.maximum_packet_size = 0 (accepted silently; see above), then authenticate_publickey, channel_open_session().await, channel.data(&b"hello"[..]).await.

    The client's CHANNEL_OPEN goes out with maximum packet size = 0 (russh/src/client/session.rs:21-44 encodes self.common.config.maximum_packet_size verbatim). All three scenarios below were verified end-to-end against a stock russh v0.64.1 build (ring backend), default settings otherwise:

    • control (both sides default, 32768): the server echoes and the client receives hello;
    • client maximum_packet_size = 0: the server prints the received bytes and then the echo write never completes - no data, no error, the client times out;
    • server maximum_packet_size = 0: the client's channel.data(...) future never completes - no error, it times out.

    Observed output (abridged):

    === SCENARIO A (control): both sides default (maxpacket 32768) ===
    [server] read 5 bytes; echoing via AsyncWrite ...
    [server] echo write completed
    RESULT A: echo received: "hello"
    
    === SCENARIO B: client advertises maximum_packet_size = 0 ===
    [server] read 5 bytes; echoing via AsyncWrite ...
    RESULT B: TIMEOUT after 6s - server-side echo write is permanently stalled (no error, no data)
    
    === SCENARIO C: server advertises maximum_packet_size = 0 ===
    RESULT C: TIMEOUT after 6s - client-side channel.data() is permanently stalled
    

    The server task stays parked inside ChannelTx::poll_writable; nothing is logged and nothing is returned to the handler. The harness source (server: into_stream() echo; client: one config toggle) can be attached on request.

    Unit-level sketch of the core defect:

    let mut tx = ChannelTx::<Msg>::new(
        sender, ChannelId(0),
        Arc::new(Mutex::new(4096)),   // window_size
        Arc::new(Notify::new()),      // notify
        0,         
    

    Quelle: OSV (Open Source Vulnerabilities), cvelistv5, ENISA EUVD, GitHub Security Advisories, NVD (NIST)

    Betroffene Produkte

    Betroffen sind die folgenden Versionen. Ältere Stände derselben Reihe sind ebenfalls verwundbar, sofern nicht anders angegeben.

    Betroffene Produkte
    Betroffene VersionenBehoben in
    Eugenyrussh
    • ≥ 0.60.0, < 0.65.0
    • —
    crates.iorussh
    • 0.60.0
    • 0.65
    rustrussh
    • >= 0.60.0, <= 0.64.1
    • 0.65

    Hersteller und Produkte

    Weakness-Klassen (CWE)

    • CWE-400Uncontrolled Resource Consumption

      Class

      The product does not properly control the allocation and maintenance of a limited resource.

      Eintrag bei MITRE CWE-400
    • CWE-835Loop with Unreachable Exit Condition ('Infinite Loop')

      Base

      The product contains an iteration or loop with an exit condition that cannot be reached, i.e., an infinite loop.

      Eintrag bei MITRE CWE-835

    Quellen & Referenzen

    • github.comEugeny/russh/commit/39cb9dbaa37caf555d34c6c22efa3bbbff9e186cx_refsource_MISC, web, euvd
    • github.comEugeny/russh/releases/tag/v0.65.0x_refsource_MISC, web, euvd
    • github.comEugeny/russh/security/advisories/GHSA-fw5c-8223-6h42x_refsource_CONFIRM, web, euvd
    • NVD (NIST)vuln/detail/CVE-2026-116774advisory
    • github.comEugeny/russhpackage

    Änderungen an der CVE

    Wer diese CVE wann geändert hat: die NVD (Analyse, betroffene Produkte, CVSS), der Herausgeber der CVE (CNA) und ergänzende Stellen wie CISA (ADP).

    1. Eintrag geändertCISA ADP

      CISA-Einschätzung (SSVC): Ausnutzung: keine bekannt, automatisierbar: nein

      Einzeländerung im Original anzeigen
      Einzeländerungen dieses Ereignisses im Original der NVD
      ArtAktionVorherNachher
      SSVC-Einschätzungergänzt
      —
      {"id":"CVE-2026-116774","role":"CISA Coordinator","options":[{"exploitation":"none"},{"automatable":"no"},{"technicalImpact":"partial"}],"version":"2.0.3","timestamp":"2026-10-28T14:34:53.983359Z"}

      Kennung der Quelle: 134c704f-9b21-4f2e-91b3-4a467353bcc0

    2. Neu erfasstGitHub

      8 Einzeländerungen im Original anzeigen
      Einzeländerungen dieses Ereignisses im Original der NVD
      ArtAktionVorherNachher
      Beschreibungergänzt
      —
      russh is a Rust SSH client and server library that includes an SSH agent protocol implementation. From 0.60.0 until 0.65.0, channel-open parsing accepts a peer-declared maximum_packet_size of zero and passes it into ChannelTx::poll_writable in russh/src/channels/io/tx.rs. The Channel::data, Channel::make_writer, and Channel::into_stream asynchronous write paths then calculate a writable size of zero and remain pending forever because window adjustments cannot satisfy a static zero packet maximum. An authenticated client can strand server writes, and a malicious server can strand client writes, allowing affected tasks, channels, and connections to accumulate without surfacing an error. This issue is fixed in version 0.65.0.
      CVSSergänzt
      —
      AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L
      Schwachstellentyp (CWE)ergänzt
      —
      CWE-400
      Schwachstellentyp (CWE)ergänzt
      —
      CWE-835
      Betroffene Versionen (Herausgeber)ergänzt
      —
      New affected value received. <a href="https://github.com/CVEProject/cvelistV5/blob/main/cves/2026/116xxx/CVE-2026-116774.json">CVE-2026-116774</a>
      Referenzergänzt
      —
      https://github.com/Eugeny/russh/commit/39cb9dbaa37caf555d34c6c22efa3bbbff9e186c
      Referenzergänzt
      —
      https://github.com/Eugeny/russh/releases/tag/v0.65.0
      Referenzergänzt
      —
      https://github.com/Eugeny/russh/security/advisories/GHSA-fw5c-8223-6h42

      Kennung der Quelle: security-advisories@github.com

    Badge einbetten

    Zeigen Sie Schweregrad und KEV-Status dieser Schwachstelle auf Ihrer Seite – mit Link hierher. Das Bild wird stündlich aktualisiert.

    Badge-Vorschau für CVE-2026-116774
    <a href="https://intel.neosec.eu/cve/CVE-2026-116774"><img src="https://intel.neosec.eu/badge/cve/CVE-2026-116774.svg" alt="CVE-2026-116774 – NEOSEC Intel" height="20"></a>