Czasami programiści zapominają, że jeśli coś wygląda jak liczba i powinno być liczbą, nie zawsze nią będzie, gdy trafi w ręce pentestera. Podczas kolejnych testów penetracyjnych potężnego narzędzia do adnotacji danych. Computer Vision Annotation Tool (CVAT), natrafiłem na klasyczny, ale bardzo niebezpieczny błąd typu Reflected Cross-Site Scripting (XSS).
Znaleziony przeze mnie błąd dorobił się oficjalnego numerka CVE-2024-47064 oraz biuletynu bezpieczeństwa na GitHubie (GHSA-hp6c-f34j-qjj7). Podatność została sklasyfikowana jako High ze scoringiem 8.1 (wektor: CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N). Zobaczmy, jak brak rygorystycznej walidacji typów danych wejściowych i odpowiedniego kodowania na wyjściu pozwolił na wstrzyknięcie złośliwego kodu JavaScript bezpośrednio do przeglądarki ofiary.
TL;DR - Najważniejsze wnioski
- Co poszło nie tak? (Endpointy i założenia)
- Proof of Concept (Weryfikacja Koncepcji)
- Jaki to ma wpływ na bezpieczeństwo?
- Jak to naprawić? (Remediacja)
Co poszło nie tak? (Endpointy i założenia)
Aplikacja CVAT (podatne wersje to m.in. Server: 2.16.3, Core: 15.1.1, Canvas: 2.20.8, UI: 1.64.51) posiada endpointy API służące do zarządzania żądaniami (Requests). W moich testach wziąłem pod lupę dwa konkretne adresy:
Standardowe zapytanie wykorzystuje w miejscu <ID> identyfikator numeryczny (typu int). Jeśli spróbujemy odpytać serwer o nieistniejące zapytanie (np. ID 2137), serwer grzecznie zwróci błąd w formacie HTML:
/api/requests/<ID>(metody GET i POST)/api/requests/<ID>/cancel(metoda POST)
"There is no request with specified id: 2137"
"There is no request with specified id: <script>alert(1)</script>"
Proof of Concept (Weryfikacja Koncepcji)
Wydaje się nieszkodliwe, prawda? A co, jeśli zamiast liczby wpiszemy tam dowolny ciąg znaków (string)? Okazuje się, że aplikacja przyjmuje go bez zająknięcia i odbija (reflect) bezpośrednio w odpowiedzi, nie filtrując znaków specjalnych HTML!
Wykorzystując fakt, że nasz ciąg znaków jest odzwierciedlany na stronie, możemy pokusić się o wstrzyknięcie kodu HTML/JavaScript. Zamiast liczby, w ścieżce URL umieszczamy złośliwy payload (odpowiednio zakodowany URL-encoded, aby serwer poprawnie go zinterpretował):
Zdekodowana wartość to po prostu: <img src=x onerror=print()>. Co się dzieje po stronie przeglądarki?
Przeglądarka próbuje wyrenderować obrazek ze źródła x. Ponieważ taki obrazek nie istnieje, uruchamia się zdarzenie onerror, które posłusznie wykonuje funkcję print(), wywołując na ekranie ofiary systemowe okno drukowania.
To samo osiągnąłem na endpoincie /cancel, używając payloadu wywołującego klasycznego alert-boxa na zdarzenie najechania myszką:
Reflected XSS, dlaczego to działa?
Serwer nie koduje danych wyjściowych. Cokolwiek umieścimy w URL jako parametr ID, zostanie wklejone bezpośrednio do kodu HTML odpowiedzi. Przeglądarka traktuje to jako poprawny HTML i posłusznie wykonuje osadzony skrypt.
Dekodowany: <img src=x onerror=print()>
Efekt: przegladarka wykonuje print() - okno drukowania
Zdarzenie: onmouseover
Efekt: alert('xss') po najechaniu myszka

Jaki to ma wpływ na bezpieczeństwo?
Choć jest to XSS typu Reflected (wymaga interakcji użytkownika, parametru UI:R w wektorze CVSS, np. kliknięcia w spreparowany link przesłany w mailu phishingowym lub komunikatorze), jego konsekwencje są poważne. Z tego też powodu wektor wskazuje na wysoką poufność (C:H) oraz integralność (I:H).
Gdy uwierzytelniony użytkownik (np. administrator projektu) kliknie w taki link, złośliwy skrypt uruchomi się w kontekście jego zaufanej sesji z CVAT. Atakujący może w ten sposób:
- Przejąć tokeny sesyjne lub ciasteczka, pełna kompromitacja konta.
- Wykonywać akcje z uprawnieniami ofiary (np. modyfikować adnotacje, dodawać złośliwe konta, usuwać projekty).
- Przekierować ofiarę na strony wyłudzające dane (phishing).
CVSS 8.1, High
Mimo wymogu interakcji użytkownika, brak wymaganych uprawnień (PR:N) i wysoki wpływ na poufność oraz integralność sprawiają, że ta podatność otrzymała ocenę 8.1 (High). Link phishingowy to jedyne, czego potrzebuje atakujący.
Jak to naprawić? (Remediacja)
Ten błąd przypomina, jak ważne są dwie warstwy obrony przed XSS-em:
- Rygorystyczna walidacja danych wejściowych (Input Validation): Serwer powinien na samym początku sprawdzić, czy przekazany parametr <ID> rzeczywiście jest liczbą całkowitą. Jeśli nie jest, żądanie powinno zostać natychmiast odrzucone (zwracając np. błąd 400 Bad Request), bez procesowania jego treści. Zawsze lepiej stosować białe listy (whitelisting) dozwolonych typów danych.
- Kodowanie danych wyjściowych (Context-Aware Output Encoding): To najważniejsza linia obrony. Wszelkie dane wprowadzane przez użytkownika, przed ich wyświetleniem w odpowiedzi HTTP (kontekst HTML), muszą zostać odpowiednio zakodowane. Znaki kontrolne HTML muszą zostać zamienione na odpowiednie encje:
<→<,>→>.
Złota zasada dewelopera
Kiedy wysyłasz do przeglądarki użytkownika tekst, który zawierał fragmenty jego własnych zapytań (np. komunikaty błądów, wyniki wyszukiwania), ZAWSZE koduj wyjście. Przeglądarka to ufna bestia, wykona każdy kod, który serwer uzna za poprawny HTML.

Podsumowanie
CVE-2024-47064 to klasyczny przykład podatności Reflected XSS, w której brak walidacji typu danych wejściowych i kodowania wyjściowego pozwolił na wstrzyknięcie złośliwego kodu JavaScript do przeglądarki ofiary. Podatność w narzędziu CVAT otrzymała ocenę CVSS 8.1 (High) ze względu na brak wymaganych uprawnień i wysoki wpływ na poufność oraz integralność. Została odpowiedzialnie zgłoszona i załatana, ale pozostaje doskonałą lekcją: nigdy nie ufaj danym od użytkownika i zawsze koduj wyjście.
Bibliografia
Oficjalny wpis w bazie NIST NVD opisujący podatność Reflected XSS w CVAT z oceną CVSS 8.1.
Biuletyn bezpieczeństwa opublikowany na GitHubie przez zespół CVAT, zawierający szczegóły podatności XSS i informacje o poprawce.
Kompendium wiedzy OWASP na temat ataków Cross-Site Scripting, typy, wektory, mechanizmy obrony i przykłady.
Kategoria OWASP Top 10 obejmująca ataki iniekcyjne, w tym Cross-Site Scripting (XSS), jako jedno z najczęstszych zagrożeń bezpieczeństwa aplikacji webowych.
Repozytorium open-source narzędzia CVAT do adnotacji danych w projektach uczenia maszynowego i Computer Vision.

