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

Rocket.Chat CVE-2026-28514: brak await zamienił każde hasło w poprawne

Krytyczny bypass uwierzytelniania w ddp-streamer wynikał z brakującego await. Z CVE-2026-30833 umożliwiał przejęcie konta bez pełnej znajomości loginu.

MATERIAŁ PUBLICZNY
AUTOR
/ CEO Breachroad · OSCP · PNPT
PUBLIKACJA
12 marca 2026
CZAS CZYTANIA
13 min czytania
TEMAT
Podatności i CVE
Rocket.Chat CVE-2026-28514: brak await zamienił każde hasło w poprawne

CVE-2026-28514 w Rocket.Chat jest rzadkim przykładem krytycznego błędu, którego przyczyną była jedna brakująca operacja asynchroniczna. W usłudze enterprise ddp-streamer funkcja porównująca hasło zwracała Promise<boolean>, lecz wywołanie nie używało await. Obiekt Promise jest w JavaScript prawdziwy logicznie, więc warunek odrzucający błędne hasło nie wykonywał się dla konta posiadającego hash.

GitHub Security Lab przetestował wersję 7.13.2 i opisał możliwość zalogowania się jako dowolny znany użytkownik z ustawionym hasłem, używając dowolnego ciągu. Pierwszą poprawkę wydano w Rocket.Chat 8.0.0 12 stycznia 2026 roku, a 5 marca udostępniono poprawki dla pozostałych wspieranych gałęzi. Administrator powinien korzystać z tabeli bezpieczeństwa Rocket.Chat, nie zakładać, że każda „nowsza siódemka” jest bezpieczna.

Drugi błąd wzmacniał pierwszy

Ta sama analiza ujawniła CVE-2026-30833, NoSQL injection w polu nazwy użytkownika. Dane wejściowe trafiały do selektora MongoDB bez wymuszenia typu string, dzięki czemu operator zapytania mógł dopasować niezamierzony rekord. Połączenie z CVE-2026-28514 oznaczało, że napastnik nie musiał nawet znać pełnej nazwy konta.

Powierzchnią była metoda logowania udostępniona przez usługę ddp-streamer pod ścieżką WebSocket. Nie należy przenosić wniosku na wszystkie konfiguracje Community Edition: advisory dotyczy konkretnego komponentu enterprise. Pierwszym zadaniem jest więc ustalenie, czy usługa działa i jest osiągalna.

Jak wykryć i zamknąć ekspozycję

Zaktualizuj wszystkie nody, zrestartuj procesy i potwierdź wersję z działającej instancji. Jeżeli patch wymaga okna, odetnij zewnętrzny dostęp do ddp-streamer oraz ogranicz WebSocket na reverse proxy do zaufanych sieci. WAF nie naprawia logiki uwierzytelniania, ale może czasowo zmniejszyć zasięg.

Przyjmij możliwość przejęcia kont:

  • unieważnij sesje i tokeny API,
  • przejrzyj logowania przez WebSocket z nowych adresów,
  • sprawdź zmiany ról, integracji, webhooków i aplikacji,
  • obróć sekrety dostępne w kanałach lub integracjach,
  • poszukaj eksportów wiadomości i masowych odczytów.

Błąd wykryto przy użyciu frameworka agentowego GitHub Security Lab, a następnie zweryfikowano ręcznie. To wartościowy model: AI może wskazać podejrzany przepływ, ale człowiek musi potwierdzić osiągalność, wpływ i warunki. Więcej o bezpiecznym użyciu agentów opisujemy w przeglądzie kodu z AI.

Najważniejsza lekcja dla programistów to wymuszenie reguł lintera dla „floating promises”, test negatywny każdego loginu i typowanie granic danych. Test „złe hasło ma zostać odrzucone” powinien być obowiązkowym regression testem. Możemy sprawdzić tę klasę błędów w aplikacji i API.

Dlaczego TypeScript nie zatrzymał błędu sam

Promise<boolean> i boolean są różnymi typami, ale JavaScript pozwala użyć obiektu w warunku. Kompilator nie zawsze zgłosi to jako błąd bez odpowiednich reguł ESLint, np. zakazu misused promises i wymagania obsługi zwracanych Promise. Typy pomagają dopiero wtedy, gdy pipeline traktuje ostrzeżenie jako blokujące.

W krytycznej funkcji warto rozdzielić operacje:

  1. Sprawdź, czy hash istnieje.
  2. Jawnie await wynik porównania.
  3. Wymuś typ boolean.
  4. Zwróć jednolity błąd bez ujawniania, czy użytkownik istnieje.
  5. Zapisz audyt decyzji bez hasła i hasha.

Test jednostkowy powinien użyć dobrego i złego hasła. Test integracyjny musi przejść przez prawdziwy WebSocket i usługę mikroserwisową, bo błąd znajdował się na granicy komponentów, a nie w samym bcrypt.

NoSQL injection jako problem typu, nie „złego znaku”

Filtrowanie znaków takich jak $ jest kruche. Pole username ma być stringiem o określonej długości i normalizacji, a obiekt lub tablica powinny zostać odrzucone przed dotknięciem query buildera. Schemat walidacji należy współdzielić między REST, DDP i wewnętrznymi komunikatami.

Odtwarzanie zakresu po patchu

Wyszukaj udane logowania z nietypowo krótkim czasem między próbami różnych haseł, nowym IP lub client fingerprintem. Porównaj aktywność konta z rzeczywistą obecnością pracownika. Dla kont administracyjnych przyjmij kompromitację przy każdym niewyjaśnionym sukcesie i zbadaj zmiany globalne.

Czy reset haseł wszystkich użytkowników wystarczy? Nie. Podatność akceptowała dowolne hasło na podatnej usłudze, więc najpierw patch i odcięcie ścieżki, potem revoke sesji oraz rotacja.

Wniosek dla procesu secure development

Authentication code powinien mieć właściciela i wyższy próg review niż zwykła funkcja biznesowa. Zmiana dotycząca hasła, tokenu lub selektora użytkownika wymaga dwóch recenzentów, uruchomienia pełnego zestawu negatywnych testów i analizy różnic między edycjami produktu.

Warto dodać mutation testing: narzędzie celowo usuwa await, odwraca warunek lub zastępuje wynik stałą. Jeżeli testy nadal przechodzą, nie sprawdzają właściwości bezpieczeństwa. Ten przypadek pokazuje też, że mikroserwis „pomocniczy” musi mieć ten sam standard uwierzytelniania co główna aplikacja.


Źródła pierwotne: GitHub Security Lab — CVE-2026-28514 i CVE-2026-30833, GitHub — AI-powered vulnerability research framework.

UDOSTĘPNIJ / KOPIUJ