Dlaczego ta seria poprawek jest pilniejsza niż zwykle
Node.js ma wbudowaną własną kopię biblioteki Brotli i korzysta z niej zawsze, gdy aplikacja rozpakowuje dane w tym formacie. CVE-2026-111497 to zapis poza granicami bufora w tym dekoderze. Spreparowany strumień Brotli może uszkodzić pamięć procesu, ujawnić jej fragmenty, zatrzymać aplikację, a w najgorszym przypadku wykonać kod atakującego. Node.js ocenia lukę jako wysoką. W NVD Google jako CNA nadał jej 9.2 w skali CVSS 4.0, a rekord czeka jeszcze na analizę NVD.
Do 22 października nie było doniesień o atakach ani publicznego exploita, a luki nie ma w katalogu CISA KEV. Node.js nie podał szczegółowych warunków ataku, więc o ryzyku decyduje to, jak Wasze aplikacje używają kompresji.
Kto jest naprawdę narażony
Najbardziej narażone są aplikacje, które rozpakowują dane spoza Waszej kontroli:
- usługi, które wywołują funkcje Brotli z modułu
zlibna danych od użytkowników lub z systemów zewnętrznych, np. przy przyjmowaniu skompresowanych plików albo ciał żądań; - aplikacje, które pobierają treści z cudzych serwerów: integracje z API, proxy, crawlery, obsługa webhooków. Klient HTTP, który automatycznie rozpakowuje odpowiedzi z nagłówkiem
Content-Encoding: br, przekazuje do dekodera to, co przyśle druga strona.
Aplikacja, która Brotli tylko kompresuje, np. serwuje skompresowane pliki statyczne, nie podaje dekoderowi obcych danych i ta luka dotyczy jej w mniejszym stopniu. Pozostałe poprawki nadal jej dotyczą.
Trzy kolejne luki wysokiej wagi uderzają w połączenia wychodzące. Dwie z nich pozwalają obejść sprawdzanie nazwy hosta w TLS, a trzecia psuje rozwiązywanie nazw DNS zawierających znak NUL. To ważne dla aplikacji, które łączą się przez TLS z adresami podanymi z zewnątrz (np. adres webhooka wpisany przez klienta) albo bezpośrednio z adresami IP. Wtedy połączenie może przyjąć certyfikat, który nie powinien przejść weryfikacji.
Co łatać dziś, a co w najbliższym oknie serwisowym
- Dziś: usługi dostępne z internetu, które rozpakowują dane od użytkowników albo pobierają treści z zewnętrznych serwerów, oraz aplikacje łączące się przez TLS z adresami spoza Waszej kontroli.
- W najbliższym oknie: narzędzia wewnętrzne, procesy budowania front-endu i zadania CI, które nie przetwarzają obcych danych.
- Osobny plan: wszystko na Node.js 18 i 20, bo te linie nie dostaną poprawki.
Wersje z poprawką
- Node.js 22.x: 22.23.4
- Node.js 24.x: 24.22.1
- Node.js 26.x: 26.12.1
- Node.js 18, 20, 23 i 25: wersje End-of-Life, bez poprawek. Projekt Node.js zaznacza, że wersje EOL są zawsze podatne, gdy pojawia się wydanie bezpieczeństwa.
Pozostałe luki w skrócie. Wysokie: CVE-2026-105482 (dns.resolve obcina nazwy ze znakiem NUL; 22.x, 24.x, 26.x), CVE-2026-105483 (obejście sprawdzania nazwy hosta przy adresie IP zapisanym cyframi pełnej szerokości; 24.x, 26.x), CVE-2026-106069 (obejście tego sprawdzania, gdy host „luźno” rozwiązuje się do adresu IP; 22.x, 24.x, 26.x). Średnie: CVE-2026-105481 (keep-alive), CVE-2026-106072 (nazwy DNS w certyfikacie uwierzytelniają adresy IP zapisane niekanonicznie) i CVE-2026-106074 (crypto.randomUUID() i randomInt() powtarzają wartości w snapshotach startowych i aplikacjach SEA). Niskie: CVE-2026-106070 (ZipFile, tylko 26.x), CVE-2026-106071 i CVE-2026-106073 (Permission Model).
Gdzie stary Node.js lubi się ukrywać
Polecenie node -v na serwerze to łatwa część. Wynik niższy niż v22.23.4, v24.22.1 lub v26.12.1 w danej linii oznacza wersję podatną. Trudniej znaleźć Node.js, który nie jest zainstalowany w systemie:
- Obrazy Docker. Tag
node:22-alpinezawiera wersję aktualną w chwili budowania obrazu, więc starszy kontener ma starą wersję. Sprawdźcie działające kontenery:for c in $(docker ps --format '{{.Names}}'); do echo "$c: $(docker exec $c node -v 2>/dev/null)"; done. Obrazy przypięte do dokładnej wersji, np.node:20.x.y, nigdy same się nie zaktualizują. - Aplikacje z wbudowanym runtime. Programy na Electronie i aplikacje SEA mają własną kopię Node.js, którą poprawi dopiero nowa wersja od producenta.
- Agenty CI i maszyny budujące. Często mają osobne instalacje Node.js, ustawione w konfiguracji potoku albo w menedżerze wersji.
- Hosting i serverless. Wersję runtime wybiera platforma albo ustawienie w projekcie. Sprawdźcie wybraną linię i to, czy dostawca już ją zaktualizował.
Aktualizacja systemowego pakietu brotli nie pomaga, bo Node.js używa własnej kopii biblioteki.
Co zrobić po kolei
- Zaktualizujcie Node.js do 22.23.4, 24.22.1 lub 26.12.1. Producent nie podał obejścia dla luki w Brotli.
- Przebudujcie obrazy na świeżo pobranym obrazie bazowym (
docker build --pull --no-cache) i wdróżcie je ponownie. Samo ponowne uruchomienie kontenera nie zmienia wersji Node.js. Nowe obrazy, np.node:22.23.4-alpine, są już w Docker Hub. - Jeśli aktualizacja musi poczekać, sprawdźcie, czy w usługach przyjmujących dane z zewnątrz da się na ten czas wyłączyć rozpakowywanie Brotli.
- Po aktualizacji obserwujcie logi. Nieoczekiwane restarty procesu i błędy dekompresji przy obsłudze danych z zewnątrz wymagają wyjaśnienia.
Wniosek na dłużej
Przy takich wydaniach najdłużej trwa szukanie zapomnianych miejsc: obrazu zbudowanego rok temu albo aplikacji na Node.js 18, o której nikt nie pamięta. Spis miejsc, gdzie działa Node.js, razem z wersją i obrazem bazowym, skraca taką akcję do godzin. Przypinanie obrazów do dokładnej wersji ma sens tylko wtedy, gdy coś regularnie podbija tę wersję i przebudowuje obraz. Dla linii 18 i 20 potrzebny jest termin migracji na 22 lub 24 LTS, bo każde kolejne wydanie bezpieczeństwa doda im luk, których nikt już nie naprawi.