Alle Beiträge

Blog · Sicherheitslage ·

Node2Shell: Die Node.js-Lücke im Brotli-Decoder

Am 21. Oktober 2026 hat das Node.js-Projekt Sicherheitsreleases für die Linien 22, 24 und 26 veröffentlicht. Sie schließen zehn Lücken. Eine davon, CVE-2026-111497 im mitgelieferten Brotli-Decoder, erlaubt es, mit präparierten komprimierten Daten den Speicher eines Prozesses zu beschädigen und im ungünstigen Fall fremden Code auszuführen. Imperva hat das unter dem Namen Node2Shell vorgeführt. Hier steht, auf welchen Pfaden solche Daten in eine Anwendung gelangen, welche Versionen die Lücke schließen und was Agenturen in ihren Projekten jetzt prüfen.

Was passiert ist

Stand: 24. Oktober 2026. Am 21. Oktober erschienen die Versionen 22.23.4, 24.22.1 und 26.12.1 zusammen mit dem Advisory des Node.js-Projekts. Die höchste Schwere darin ist High. Das Advisory nennt zehn CVEs: vier der Stufe High, drei Medium, drei Low. Zugleich aktualisieren die Releases die mitgelieferten Bibliotheken c-ares, die Stammzertifikate, OpenSSL, SQLite und Undici.

Die zehn Lücken des Sicherheitsreleases vom 21. Oktober 2026
CVE Schwere Betrifft Linien
CVE-2026-111497 High Brotli-Decoder schreibt über das Ende eines Puffers hinaus 22, 24, 26
CVE-2026-105482 High dns.resolve kürzt Namen mit einem NUL-Zeichen 22, 24, 26
CVE-2026-105483 High TLS-Hostnamenprüfung bei IP-Adressen in Vollbreitenziffern 24, 26
CVE-2026-106069 High TLS-Hostnamenprüfung bei Hosts, die lose zu einer IP-Adresse werden 22, 24, 26
CVE-2026-105481 Medium Keep-alive-Socket verarbeitet eine Antwort vor der Anfrage 22, 24, 26
CVE-2026-106072 Medium Nicht kanonische IPv4-Hostnamen gegen DNS-SANs 22, 24, 26
CVE-2026-106074 Medium Zufallsvorräte von randomUUID landen in Snapshots 22, 24, 26
CVE-2026-106070 Low ZipFile liefert fremde Bytes nach fehlgeschlagener Prüfung 26
CVE-2026-106071 Low Permission Model gewährt per Platzhalter zu viel 26
CVE-2026-106073 Low Permission Model umgehbar mit fs.realpathSync 22, 24, 26

Im Mittelpunkt steht CVE-2026-111497. Node.js liefert einen Brotli-Decoder mit und stellt ihn über das Modul node:zlib bereit. Brotli ist ein Kompressionsverfahren, das Browser und Server für Antworten aushandeln, erkennbar am Header Content-Encoding: br. Der Decoder arbeitet als Strom: Er liest Block für Block, und wenn ein Block noch nicht vollständig vorliegt, meldet er, dass er mehr Eingabe braucht. Genau dort lag der Fehler. Einen ungültigen Blockwechsel, also einen dauerhaften Formatfehler, meldete der Decoder als vorübergehenden Bedarf an mehr Eingabe. Also hängte er weitere Bytes an einen internen Puffer von acht Byte an, über dessen Ende hinaus.

Wer einer Anwendung Brotli-Daten unterschieben kann, die sie mit node:zlib entpackt, kann so den Speicher des Prozesses beschädigen. Die Folge ist nach Angaben des Projekts ein Absturz, das Offenlegen von Prozessspeicher oder die Ausführung fremden Codes. Das Projekt stuft die Lücke als High ein; andere Stellen bewerten sie höher. Gemeldet haben sie Khai Tran und Sylvie Mayer von OpenAI Codex Security. Einen Workaround innerhalb der Laufzeit nennt das Advisory nicht. Für Versionslinien, deren Wartung beendet ist, gilt wie bei jedem Sicherheitsrelease: Sie sind betroffen und bekommen keine Korrektur.

Von den zehn Lücken ist diese die einzige, bei der Daten von außen den Prozess selbst übernehmen können. Die drei anderen der Stufe High betreffen die Prüfung von Hostnamen beim TLS-Aufbau und die Namensauflösung, also die Frage, ob eine Anwendung mit dem richtigen Server spricht. Das ist ernst, aber ein anderer Angriff: Er braucht eine Position zwischen Anwendung und Ziel. Für den Brotli-Decoder reicht es, der Anwendung Daten zu liefern, die sie ohnehin entpackt.

Welche Anwendungen betroffen sind

Betroffen ist jeder Node.js-Prozess der Linien 22, 24 und 26 vor den genannten Versionen, sobald er fremde Brotli-Daten entpackt. Entscheidend ist der Pfad, auf dem solche Daten in den Decoder gelangen. Imperva hat zwei untersucht.

Der erste Pfad ist das eingebaute fetch(). Holt eine Anwendung eine Ressource von einem fremden Server und liefert dieser die Antwort Brotli-komprimiert, entpackt Node.js sie von selbst. Der Angreifer ist in diesem Fall der Server, den die Anwendung anspricht: eine Schnittstelle, ein Webhook-Ziel, ein Dienst, dessen Antworten die Anwendung weiterverarbeitet. Das betrifft also auch Anwendungen, die selbst keine Anfragen von außen annehmen.

Der zweite Pfad sind Body-Parser. Ein einfacher HTTP-Server in Node.js entpackt einen komprimierten Anfragekörper nicht, nur weil er ihn erhält. Express 5 tut es: Die Parser express.json(), express.urlencoded(), express.text() und express.raw() entpacken einen Körper mit Content-Encoding: br, sobald sie an einer Route hängen. Imperva hat das für Express 5.0.0 bis 5.3.0 und body-parser 2.0.0 bis 2.3.0 geprüft. Auf diesem Pfad reicht eine einzelne Anfrage von außen.

In Agenturprojekten kommen beide Pfade täglich vor. Ein Serverteil ruft per fetch() ein Headless-CMS, einen Zahlungsdienst oder eine Karten-API ab und reicht die Antwort weiter. Eine Kontaktformular-Route nimmt mit express.json() Anfragen aus dem Browser an. Ein Build in der CI holt zur Bauzeit Inhalte von einer fremden Schnittstelle, oft mit einer Node-Version, die niemand seit Monaten angefasst hat. Jede dieser Stellen entpackt fremde Brotli-Daten, sobald der Gegenüber sie so sendet.

Den Nachweis hat Imperva auf dem offiziellen Node.js-Image 24.22.0 für Linux auf arm64 geführt, ohne Debugger und ohne eigenen Build. Der Angriff gelang nicht bei jedem Versuch, sondern erst nach mehreren Anläufen; andere Architekturen und die Linien 22 und 26 hat Imperva nicht getestet. Auf 24.22.1 wies der Decoder dieselben Daten zurück, und es lief kein Code. Angriffe in freier Wildbahn waren bis zum 22. Oktober nicht gemeldet. Das ist kein Grund zu warten: Die Details sind öffentlich, und der Weg von einem unzuverlässigen zu einem zuverlässigen Exploit ist Fleißarbeit.

Ein Punkt, den Imperva zu Recht betont: Node.js steckt nicht nur dort, wo eine package.json liegt. Container-Images bringen ihre eigene Laufzeit mit, Build-Werkzeuge und Desktop-Anwendungen bündeln eine Node-Binärdatei, CI-Runner halten eine eigene Version vor. Ein Inventar, das nur Abhängigkeiten zählt, übersieht diese Stellen.

Was Sie jetzt prüfen

Für eine Agentur mit mehreren Kundenprojekten ist die Lücke vor allem eine Inventarfrage. Zuerst kommen Prozesse an die Reihe, die Anfragen von außen annehmen und einen Body-Parser nutzen, dann Dienste, die viele fremde Server abrufen, zuletzt Werkzeuge, die nur in der CI laufen. Die Reihenfolge, die sich bewährt:

  1. Laufzeiten inventarisieren. Für jedes Projekt die Node-Version an jeder Stelle, an der ein Prozess läuft: der Server oder Container in Produktion, die FROM node:-Zeile jeder Dockerfile, das Image der CI, die Funktionen bei Serverless- und Edge-Anbietern, die Build-Werkzeuge auf Entwicklerrechnern. Die Angabe in .nvmrc oder engines ist ein Wunsch, kein Befund; den liefert node -v in der jeweiligen Umgebung.
  2. Aktualisieren. Auf 22.23.4, 24.22.1 oder 26.12.1. Ein Projekt auf Node.js 20 oder älter bekommt keine Korrektur und wandert auf eine gewartete Linie. Wer in Dockerfiles einen beweglichen Tag wie node:24 nutzt, baut neu und prüft im fertigen Image, welche Version tatsächlich enthalten ist; ein lokal zwischengespeichertes Image bleibt sonst alt.
  3. Neu bauen und ausrollen. Eine neue Laufzeit wirkt erst, wenn der Prozess mit der neuen Binärdatei gestartet ist. Container werden neu gebaut und ausgerollt, Funktionen neu veröffentlicht, Dienste neu gestartet.
  4. Anbieter fragen. Wo ein Dienstleister die Laufzeit stellt, bei Hosting, Serverless-Funktionen oder einem CMS auf Node-Basis, zählt dessen Aussage: welche Version läuft, seit wann. Eine WAF-Regel des Anbieters ist eine Zwischenlösung, kein Ersatz für das Update.
  5. Pfade kennen. Wo entpackt die Anwendung fremde Brotli-Daten? Bei fetch() gegen Dritte und bei Body-Parsern an öffentlichen Routen. Einen Workaround innerhalb der Laufzeit gibt es nicht. Imperva rät, bis zum Update ungeprüften Brotli-Verkehr auf diesen Pfaden zu begrenzen, wo das geht. Imperva hat Regeln in seine eigene WAF aufgenommen, und Vercel hat am 21. Oktober Regeln gegen präparierte eingehende Anfragen eingeführt. Beide decken keine Antworten ab, die eine Anwendung selbst von fremden Servern abruft.
  6. Festhalten. Welches Projekt, welche Version, wann aktualisiert. Für Kunden mit Wartungsvertrag ist das die Antwort auf die Frage, die in den nächsten Tagen kommt. Wie ein solcher Vertrag diese Arbeit vorsieht, steht im Beitrag zu Wartung und Betrieb.

Was das für Kunden von obhut heißt

obhut hostet statische Websites. Eine Website, die bei obhut liegt, besteht aus fertigen Dateien; für sie läuft am Edge keine Node.js-Laufzeit, die diese Lücke betreffen könnte. Die Build-Werkzeuge, die solche Dateien erzeugen, laufen bei Ihnen oder in Ihrer CI, und dort gilt die Prüfliste oben. Die Edge-Knoten, die Websites ausliefern, sind in Go geschrieben; eine Node.js-Lücke betrifft sie nicht.

Die Steuerungsebene von obhut, also API und Hintergrunddienste, läuft auf Node.js 24 und nutzt Express 5. Sie liegt damit auf einem der betroffenen Pfade. Sicherheitsreleases von Node.js erreichen sie über den Release-Zug, der vor jeder Auslieferung jede Prüfung durchläuft. Seit dem Release 20261024152023-1a9c0b9213c6 vom 24. Oktober 2026 läuft sie in Produktion auf Node.js 24.22.1, der korrigierten Version.

Häufige Fragen

Reicht ein Update der Abhängigkeiten?

Nein. Die Lücke liegt in der Laufzeit, nicht in einem Paket. Ein npm update ändert die Node-Binärdatei nicht. Aktualisiert wird Node.js selbst, und zwar an jeder Stelle, an der ein Prozess läuft: Server, Container, CI, Funktionen.

Ist mein Next.js-Projekt betroffen?

Entscheidend ist nicht das Framework, sondern die Laufzeit und die Pfade. Läuft das Projekt auf Node.js 22, 24 oder 26 vor den korrigierten Versionen und entpackt es fremde Brotli-Daten, etwa über fetch() gegen Dritte oder einen Body-Parser an einer API-Route, liegt es auf einem betroffenen Pfad. Ein statischer Export, der als fertige Dateien ausgeliefert wird, bringt keine Laufzeit mit. Welche Node-Version Ihr Hosting für den Serverteil verwendet, beantwortet der Anbieter.

Hilft eine WAF?

Als Zwischenlösung. Eine WAF kann präparierte Anfragekörper erkennen, die von außen kommen, und so den Pfad über Body-Parser verengen. Antworten, die eine Anwendung selbst von fremden Servern abruft, sieht sie nicht. Das Update entfernt die Lücke, die Regel verkleinert nur das Fenster. Was eine WAF leistet und was nicht, steht im Beitrag Was ist eine WAF?.

Was ist mit Node.js 20?

Der Zeitplan des Projekts führt die Linie 20 als beendet; sie erhält keine Korrektur, und das Advisory nennt sie nicht. Die ungerade Linie 25 führt er ebenfalls als beendet: Bis einschließlich Node.js 26 verlieren ungerade Linien nach sechs Monaten ihre Unterstützung. Beide wandern auf 22 oder 24, oder auf 26.

Der Edge vor Ihren Anwendungen.

Autoritatives DNS, Zertifikate, TLS, eine WAF und Hosting für statische Websites, aus Deutschland betrieben. Erzählen Sie uns kurz von Ihrem Vorhaben, wir antworten persönlich.