Przejdź do treści
INDEKS ANALIZ BREACHROAD / NOTA TECHNICZNA

Fastify JWT CVE-2026-18500: globalny sekret omija granicę kluczy

Błąd kolejności scalania opcji sprawia, że @fastify/jwt ignoruje klucz wybrany dla trasy. Wyjaśniamy bypass autoryzacji i aktualizację do 10.2.2.

MATERIAŁ PUBLICZNY
AUTOR
/ CEO Breachroad · OSCP · PNPT
PUBLIKACJA
15 sierpnia 2026
CZAS CZYTANIA
14 min czytania
TEMAT
Tożsamość i dostęp
Fastify JWT CVE-2026-18500: globalny sekret omija granicę kluczy

15 sierpnia 2026 roku opublikowano rekord CVE-2026-18500 dotyczący pakietu @fastify/jwt. Podatność nie polega na złamaniu kryptografii JWT ani poznaniu tajnego klucza. Problem jest bardziej podstępny: wersje starsze niż 10.2.2 mogą podczas weryfikacji zignorować klucz przekazany bezpośrednio dla konkretnej trasy i zastąpić go globalnym sekretem skonfigurowanym we wtyczce. Jeżeli aplikacja używa różnych kluczy dla różnych domen zaufania, token z mniej uprzywilejowanej domeny może zostać zaakceptowany tam, gdzie powinien obowiązywać inny klucz.

Advisory projektu Fastify ocenia błąd na 8,1 w CVSS 3.1. Atak wymaga tokenu podpisanego globalnym sekretem, więc typowo wystarcza zwykłe konto użytkownika. Nie wymaga interakcji administratora, znajomości klucza administracyjnego ani fałszowania podpisu. Poprawiona wersja 10.2.2 zmienia priorytet opcji tak, aby jawnie podany klucz był respektowany.

Co właściwie miała zapewniać aplikacja

JWT jest podpisanym komunikatem. Serwer nie powinien ufać samym polom role, scope czy tenant, dopóki nie zweryfikuje podpisu właściwym kluczem i nie sprawdzi pozostałych warunków. W wielu systemach jeden globalny sekret obsługuje zwykłe sesje, a osobny klucz chroni panel administracyjny, integrację partnera, tokeny resetu albo komunikację między usługami.

Kod trasy może wywołać request.jwtVerify z opcją key, aby wskazać klucz wymagany właśnie w tym miejscu. Z punktu widzenia projektanta jest to granica autoryzacji: token poprawny dla strefy user nie powinien otwierać strefy admin. Podatny kod scalał jednak opcje w kolejności, w której globalnie rozwiązany sekret nadpisywał wartość lokalną. W efekcie aplikacja deklarowała jedną politykę, a biblioteka wykonywała inną.

To przykład błędu confused deputy na poziomie konfiguracji kryptograficznej. Podpis nadal jest matematycznie poprawny, lecz sprawdzono go w niewłaściwej domenie. Logi mogą nawet pokazywać udaną weryfikację bez żadnego wyjątku. Problem nie wygląda jak klasyczna awaria mechanizmu bezpieczeństwa, bo mechanizm działa zgodnie z kluczem, który faktycznie otrzymał.

Jak dochodzi do bypassu

Załóżmy, że aplikacja wydaje zwykłym użytkownikom tokeny podpisane kluczem A. Trasa administracyjna jawnie podaje klucz B w wywołaniu weryfikacji. W wersji podatnej globalna konfiguracja z kluczem A ma ostatnie słowo podczas scalania. Trasa administracyjna weryfikuje więc token kluczem A, mimo że kod lokalny wskazuje B.

Atakujący nie musi zmieniać algorytmu na none, wykorzystywać confusion między RSA i HMAC ani odgadywać sekretu. Używa legalnego tokenu własnego konta. Jeżeli dodatkowa autoryzacja opiera się wyłącznie na danych znajdujących się w tym tokenie, może przygotować lub uzyskać zestaw claims, który po zaakceptowaniu w złej domenie prowadzi do dostępu do chronionych danych lub operacji.

Nie każda aplikacja korzystająca z @fastify/jwt jest podatna w praktyce. Jeżeli wszystkie trasy używają tego samego sekretu, błąd priorytetu nie zmienia wyniku. Ryzyko pojawia się wtedy, gdy per-request key ma rozdzielać zaufanie. Dlatego samo wyszukanie pakietu w SBOM nie wystarcza; potrzebny jest przegląd sposobu użycia API.

Advisory wskazuje również analogiczny problem dla reply.jwtSign, gdy klucz podawany lokalnie przy podpisywaniu jest zastępowany globalnym sekretem. To może prowadzić do wydawania tokenów w innej domenie niż zakłada kod. Weryfikacja i podpisywanie muszą więc zostać przeanalizowane razem.

Kto jest narażony

Dotknięte są wersje @fastify/jwt wcześniejsze niż 10.2.2. Najwyższy priorytet mają aplikacje Node.js i Fastify, które konfigurują globalny secret, a następnie przekazują osobne key do request.jwtVerify lub reply.jwtSign. Typowe przykłady to rozdzielenie panelu klienta i administratora, wiele issuerów, osobne klucze tenantów, migracja kluczy oraz tokeny o różnych celach.

Zespół powinien przeszukać kod, nie tylko manifest zależności. Zidentyfikuj rejestrację wtyczki, globalne sekrety i wszystkie lokalne wywołania z opcją key. Następnie zapisz oczekiwaną relację: jaki issuer, audience, algorytm i klucz powinien być akceptowany na każdej trasie. Jeżeli dokumentacja architektury nie odpowiada na to pytanie, podatność ujawnia również dług techniczny w modelu tożsamości.

Szczególną uwagę trzeba poświęcić mikroserwisom kopiującym wspólny moduł uwierzytelniania. Jedna wadliwa abstrakcja może powielić się w wielu API. Lockfile może też zawierać kilka wersji pakietu, więc wynik skanera na poziomie repozytorium należy powiązać z artefaktem faktycznie wdrożonym.

Co zrobić teraz

Zaktualizuj @fastify/jwt do 10.2.2 lub nowszej wersji zgodnej z aplikacją. Odtwórz lockfile, uruchom testy i potwierdź wersję wewnątrz finalnego obrazu kontenera. Sama zmiana package.json bez przebudowania obrazu lub ponownego wdrożenia nie usuwa ryzyka.

Po aktualizacji wykonaj test negatywny dla każdej granicy kluczy. Token poprawnie podpisany kluczem użytkownika musi zostać odrzucony na trasie wymagającej klucza administratora, nawet jeśli ma podobne claims. Analogicznie token jednego tenanta nie może przechodzić w drugim. Test powinien sprawdzać nie tylko status HTTP, lecz także brak skutku ubocznego.

Jeżeli aktualizacja musi poczekać, advisory proponuje bezpośrednią weryfikację przez fastify.jwt.verify(token, { key }), która respektuje podany klucz. Jest to obejście tymczasowe. Nie polegaj na per-request key w podatnych metodach jako granicy autoryzacji. Zmianę obejścia należy otoczyć testami i usunąć po aktualizacji, aby nie utrzymywać dwóch ścieżek weryfikacji.

Rozważ unieważnienie lub skrócenie ważności tokenów wydanych przez domeny, które mogły przekroczyć granicę. Rotacja klucza nie jest automatycznie konieczna, ponieważ CVE nie ujawnia sekretu, ale może być zasadna, gdy logi wskazują nadużycie albo nie da się ustalić zakresu zaakceptowanych tokenów.

Detekcja i analiza historyczna

Najlepszym źródłem jest korelacja issuer, audience, kid, trasy i decyzji autoryzacyjnej. Szukaj tokenów ze strefy użytkownika zaakceptowanych na endpointach administracyjnych, integracyjnych lub międzyserwisowych. Jeżeli logi nie zawierają surowego tokenu — i nie powinny — powinny zachowywać bezpieczny identyfikator tokenu, issuer, audience, wybrany algorytm oraz skrót identyfikatora klucza.

Przejrzyj operacje o wysokim wpływie: zmiany ról, eksport danych, konfigurację integracji, tworzenie kluczy API i modyfikacje tenantów. Sukces weryfikacji JWT nie jest dowodem poprawnej autoryzacji, więc alerty o błędach podpisu mogą pozostać puste mimo wykorzystania.

W czasie testów można dodać instrumentację pokazującą, z którego źródła pochodzi efektywny klucz: globalnej konfiguracji czy opcji trasy. Nie loguj materiału kryptograficznego. Wystarczy stabilny, niesekretny identyfikator. Taki ślad ułatwia wykrywanie przyszłych regresji kolejności scalania.

Lekcja dla projektantów bibliotek i API

Opcje bezpieczeństwa powinny mieć jednoznaczną hierarchię. Jeżeli lokalna trasa podaje bardziej szczegółowy klucz, biblioteka musi go respektować albo jawnie odrzucić konflikt. Ciche nadpisanie jest najgorszym zachowaniem, ponieważ kod wygląda bezpiecznie podczas review.

Testy biblioteki powinny obejmować macierz globalne–lokalne, nie tylko poprawne podpisy. Potrzebne są przypadki z dwoma różnymi kluczami i asercją, że token domeny A nie działa w domenie B. W aplikacji warto ponadto weryfikować issuer, audience, typ tokenu i dozwolony algorytm. Sam klucz nie opisuje pełnego kontekstu zaufania.

Silniejszą architekturą jest oddzielenie weryfikatorów dla różnych domen zamiast dynamicznego przełączania opcji w jednym obiekcie. Osobna instancja, jawna funkcja adminVerifier lub niezależny middleware redukują ryzyko nieoczekiwanego merge. Następna osoba czytająca kod widzi granicę bez rekonstruowania kolejności spread operatorów.

Fakty i wnioski Breachroad

Faktem jest, że CVE-2026-18500 dotyczy wersji poniżej 10.2.2, ma ocenę 8,1 i pozwala globalnemu sekretowi nadpisać klucz przekazany dla wywołania. Faktem jest również to, że bezpośrednie fastify.jwt.verify z lokalnym kluczem jest wskazanym obejściem, a wydanie 10.2.2 zawiera poprawkę. Advisory nie stanowi dowodu masowego wykorzystania w Internecie.

Wnioskiem Breachroad jest traktowanie konfiguracji JWT jako kodu autoryzacyjnego, nie wygodnej opcji biblioteki. Każda zmiana kolejności scalania może zmienić granicę zaufania bez błędu kryptograficznego. Testy negatywne między domenami są równie ważne jak test poprawnego logowania.

Jeśli chcesz sprawdzić granice tokenów, tenantów i ról w działającym API, zobacz testy penetracyjne aplikacji webowych i API. Zespołom deweloperskim i platformowym polecamy także szkolenia cyberbezpieczeństwa dla organizacji, które przekładają takie przypadki na powtarzalne praktyki projektowe.

UDOSTĘPNIJ / KOPIUJ