Strona główna / Blog / LatePoint CVE-2026-110653: wyścig OTP

Blog · analiza

LatePoint CVE-2026-110653: limit dziesięciu prób OTP działa, dopóki żądania przychodzą po kolei. Przejęcie konta klienta i poprawka, którą trzeba sprawdzić w kodzie

LatePoint, wtyczka do rezerwacji wizyt w WordPressie z ponad 100 tysiącami instalacji, pozwala klientom logować się jednorazowym kodem OTP. Kod ma sześć cyfr, a serwer blokuje go po dziesięciu błędnych próbach. Do wersji 5.7.4 włącznie licznik prób był jednak zwiększany nieatomowo. Kilka równoległych żądań widzi tę samą starą wartość i blokada nie zadziała. Wordfence ocenia to na 9.1: bez logowania, ze znajomością e-maila lub telefonu klienta, można przejąć jego konto w LatePoint. Changelog wersji naprawczej mówi tylko „Addressed security bugs”. Kod pokazuje więcej.

Produkt: Appointment Booking Plugin – LatePoint, wtyczka WordPress, 100 000+ aktywnych instalacji według WordPress.org. Funkcja: logowanie klienta kodem OTP (endpoint auth__verify_otp).
CVE: CVE-2026-110653, CNA Wordfence, opublikowany 17.10.2026. Zgłaszający: Ekene Umegakwe. Oś czasu CNA: vendor powiadomiony 14.10.2026, ujawnienie 16.10.2026. W NVD status „Deferred”.
CVSS 3.1 (CNA): 9.1 Critical, AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N, CWE-287. Brak oceny NVD.
Wersje podatne: do 5.7.4 włącznie.
Poprawka: 5.7.5 z 16.10.2026 (changelog: „Addressed security bugs. Props to WPScan and WordFence”). Zmiana potwierdzona w kodzie, szczegóły niżej.
Threat state: brak w CISA KEV (katalog 2026.10.21, sprawdzony 22.10.2026). SSVC od CISA: exploitation: none, automatable: yes, technical impact: total. EPSS 0,40% (22.10.2026). Nie znalazłem publicznego PoC.

Na czym polega błąd

Opis Wordfence jest wyjątkowo precyzyjny. Funkcja verifyOTP wybiera aktywny kod z warunkiem attempts < 10, sprawdza go, a potem zapisuje attempts + 1, licząc od wartości wczytanej do pamięci. UPDATE nie ma warunku na liczbę prób i nie ma blokady wiersza (SELECT … FOR UPDATE). To klasyczny TOCTOU: między odczytem a zapisem mieści się wiele równoległych żądań, a każde widzi licznik poniżej limitu. Nonce na endpoincie niczego nie zmienia, bo według CNA zwracają go publicznie endpointy request_otp i resend_otp.

To dobry przykład kontroli, która przechodzi każdy test funkcjonalny. Test „11 złych kodów po kolei, potem blokada” daje wynik pozytywny w 5.7.4. Błąd ujawnia dopiero test współbieżności. Ten sam typ problemu, w innej skali, opisywałem przy GitHub Enterprise Server.

Zakres skutku: konto klienta, nie administrator

Wektor C:H/I:H/A:N dotyczy konta klienta LatePoint: rezerwacji, danych osobowych, historii wizyt i tego, co klient może zmienić w profilu. Szkic VMRT Radar słusznie to podkreślał: to nie jest przejęcie administratora WordPressa ani wykonanie kodu. Do oceny dla konkretnej instalacji potrzebujesz trzech informacji, których źródła nie podają:

  • czy logowanie klientów kodem OTP jest u Ciebie włączone (czy jest domyślne, nie potwierdziłem),
  • czy klienci LatePoint są powiązani z kontami WordPress i jakie te konta mają role,
  • jakie dane trzymasz w profilu klienta. Gabinet medyczny, kancelaria czy poradnia psychologiczna mają tu zupełnie inny profil ryzyka niż salon fryzjerski. W UE to także pytanie o naruszenie ochrony danych osobowych.

Warunek „atakujący zna e-mail lub telefon klienta” nie jest silną barierą. Dla wybranej osoby to zwykle informacja publiczna albo łatwa do zdobycia. Dla masowego ataku trzeba listy klientów konkretnego serwisu, co ogranicza skalę, ale nie wektor.

Poprawka: changelog milczy, kod mówi

Changelog 5.7.5 nie wymienia CVE ani tego błędu, a dziękuje i WPScan, i Wordfence, więc wydanie zawiera co najmniej dwie poprawki. Porównałem w SVN WordPress.org plik lib/helpers/otp_helper.php w tagach 5.7.4 i 5.7.5:

  • W 5.7.5 przed sprawdzeniem kodu jest wywołanie increment_attempts_within_limit() z komentarzem „Claim one attempt atomically before the check; zero rows means the cap is reached, even under concurrency”.
  • Nowa metoda w modelu OTP wykonuje jedno zapytanie UPDATE … SET attempts = attempts + 1 … WHERE id = … AND attempts < … i sprawdza, czy zmieniło wiersz. Zwiększenie licznika i kontrola limitu są teraz jedną operacją w bazie, a próba jest „zużyta” przed porównaniem kodu, a nie po nim.

To poprawny wzorzec i odpowiada dokładnie przyczynie opisanej przez CNA. Dla VM to rzadki komfort: nie trzeba wierzyć changelogowi, wystarczy wskazać zmianę. Nie zwalnia to z testu po wdrożeniu, ale kryterium zamknięcia „wersja ≥ 5.7.5” ma tu pokrycie w kodzie.

Co zostaje po poprawce

Z kodu 5.7.5 wynikają też granice, w których poprawka działa. Limit to 10 prób na kod. Nowy kod unieważnia poprzednie. Wygenerować można do 60 kodów na godzinę dla jednego kontaktu. W najgorszym przypadku daje to więc około 600 prób na godzinę wobec miliona możliwych kodów, czyli rzędu 0,06% szansy na godzinę dla jednego konta. To nie zero, ale to już ryzyko projektowe, a nie podatność. Dwie uwagi:

  • Limit generowania jest liczony zapytaniem COUNT przed zapisem nowego kodu. Czy jest odporny na współbieżność, nie sprawdzałem. Jeśli nie, budżet prób jest większy niż powyżej.
  • Każdy wygenerowany kod jest wysyłany do ofiary e-mailem lub SMS-em. Seria kodów, o które klient nie prosił, to najlepszy sygnał wykrycia, jaki masz, także dla prób sprzed aktualizacji. Klienci zgłaszający „dziwne kody logowania” powinni trafiać do bezpieczeństwa, nie tylko do supportu.

Co powinien zrobić VE

  1. Znajdź instalacje LatePoint i ustal wersję z działającej instancji, to, czy logowanie OTP jest włączone, oraz jakie dane są w profilach klientów. Na tej podstawie ustaw priorytet: wysoki dla serwisów z danymi wrażliwymi.
  2. Aktualizuj do 5.7.5 lub nowszej. Wydanie zawiera też inne poprawki bezpieczeństwa (WPScan), więc celem jest najnowsza wersja, a nie minimalna. Najpierw staging, bo 5.7.5 dodaje też obsługę REST API.
  3. Jeśli aktualizacja musi poczekać, ogranicz liczbę równoczesnych żądań do auth__verify_otp z jednego źródła na WAF lub reverse proxy albo czasowo wyłącz logowanie OTP. Rozproszony atak z wielu adresów może taki limit ominąć, więc to tylko mitigacja.
  4. Przejrzyj logi: serie żądań request_otp, resend_otp i verify_otp dla jednego kontaktu w krótkim czasie, udane logowania klienta tuż po takiej serii, zmiany danych kontaktowych w profilu. Brak blokady w WAF nie oznacza braku ataku.
  5. Po aktualizacji zleć w kontrolowanym środowisku test limitu z równoległymi żądaniami. Pojedynczy sekwencyjny test niczego tu nie dowodzi. Przy podejrzeniu przejęcia konta unieważnij sesje klienta i postępuj według procedury obsługi naruszeń danych.

Powiązane na blogu

Źródła

  • CVE.org — CVE-2026-110653 (CNA Wordfence, CVSS 3.1 9.1, CWE-287, zakres do 5.7.4, oś czasu, zgłaszający) — cve.org
  • NVD — CVE-2026-110653 (status Deferred, SSVC CISA) — nvd.nist.gov
  • Wordfence Intelligence — wpis podatności (odnośnik z rekordu CVE) — wordfence.com
  • WordPress.org — LatePoint (wersja 5.7.5 z 16.10.2026, changelog, liczba instalacji) — wordpress.org
  • WordPress.org SVN — tagi LatePoint (lib/helpers/otp_helper.php w 5.7.4 i 5.7.5, lib/models/otp_model.php w 5.7.5) — plugins.svn.wordpress.org
  • MITRE — CWE-362: Concurrent Execution using Shared Resource with Improper Synchronization — cwe.mitre.org
  • CISA Known Exploited Vulnerabilities Catalog (brak CVE-2026-110653 w wersji 2026.10.21) — cisa.gov

Nota redakcyjna: wpis powstał na podstawie szkicu VMRT Radar z 19.10.2026 i został zweryfikowany ze źródłami pierwotnymi 20 października 2026 (ok. 19:10 CEST): rekord CVE.org (CNA Wordfence, CVSS 3.1 9.1, CWE-287, zakres do 5.7.4, oś czasu, zgłaszający), NVD API 2.0 (status „Deferred”, SSVC CISA), API wtyczek WordPress.org (wersja, data, changelog, liczba instalacji), pliki w SVN WordPress.org dla tagów 5.7.4 i 5.7.5, EPSS i katalog CISA KEV 2026.10.16. Strona Wordfence Intelligence nie była dostępna z mojego środowiska. Względem szkicu potwierdziłem poprawkę bezpośrednio w kodzie 5.7.5 (szkic oznaczał ją jako niepotwierdzoną przez changelog), dodałem wektor CVSS, CWE, oś czasu i analizę ryzyka resztkowego. Ponownie 22 października 2026 (ok. 22:40 CEST) sprawdziłem katalog CISA KEV (wersja 2026.10.21: nadal brak wpisu), EPSS (bez zmian) oraz wersje w PyPI, GitHub i WordPress.org (bez nowych wydań). Nie potwierdziłem: czy logowanie OTP jest domyślnie włączone, jak klienci LatePoint mapują się na konta WordPress, czy limit generowania kodów jest odporny na współbieżność, jaki jest czas ważności kodu, ani czy błąd był wykorzystywany. Wyliczenie budżetu prób to szacunek autora na podstawie stałych w kodzie. CWE-362 w słowach kluczowych to klasyfikacja autora, rekord podaje CWE-287.

Zapamiętaj jedno

CVE-2026-110653 w LatePoint (9.1) to licznik prób OTP, który działa sekwencyjnie, a przy równoległych żądaniach nie. Bez logowania, ze znajomością e-maila lub telefonu, da się przejąć konto klienta, ale nie administratora WordPressa. Changelog 5.7.5 nie wymienia CVE, za to kod pokazuje atomowy warunkowy UPDATE przed sprawdzeniem kodu, czyli właściwą poprawkę. Aktualizuj do najnowszej wersji, testuj limit równolegle, a jako sygnał wykrycia traktuj serie kodów OTP, o które klient nie prosił.