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.
| 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:
-
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.nvmrcoderenginesist ein Wunsch, kein Befund; den liefertnode -vin der jeweiligen Umgebung. -
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:24nutzt, baut neu und prüft im fertigen Image, welche Version tatsächlich enthalten ist; ein lokal zwischengespeichertes Image bleibt sonst alt. - 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.
- 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.
-
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. - 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.