CVE-2026-XXXXX — Persistent XSS w Zextras Carbonio WebMail — funkcja Print
Jak podczas testu penetracyjnego infrastruktury odkryłem podatność Persistent XSS w funkcji drukowania wiadomości Zextras Carbonio WebMail — nazwy uczestników korespondencji trafiają do szablonu wydruku bez escapowania, a okno wydruku nie ma nagłówków CSP.
Persistent Cross-Site Scripting w funkcji Print aplikacji Zextras Carbonio WebMail (carbonio-mails-ui)
Zextras Carbonio to open-source'owa platforma do współpracy i poczty e-mail (e-mail, kalendarz, pliki, wideokonferencje), rozwijana jako alternatywa dla Zimbry i wdrażana m.in. w administracji publicznej oraz przedsiębiorstwach. Komponent carbonio-mails-ui odpowiada za webowy interfejs poczty.
Kontekst odkrycia
Podatność zidentyfikowałem pierwotnie podczas autoryzowanego testu penetracyjnego infrastruktury klienta korzystającego ze starszej, komercyjnej wersji Carbonio. Aby potwierdzić problem na czystym, publicznie dostępnym środowisku, odtworzyłem go następnie na świeżej instalacji Carbonio Community Edition pobranej bezpośrednio ze strony producenta (carbonio-mails-ui v1.31.4, carbonio-appserver 4.4.4, Ubuntu 24.04 LTS).
Oznacza to, że problem dotyczy zarówno edycji Community, jak i wersji komercyjnych — nie tylko najnowszego wydania. Zgłoszenie przekazałem do zespołu bezpieczeństwa Zextras w ramach responsible disclosure.
Szczegóły podatności
| CVE ID | CVE-2026-XXXXX — w trakcie przydzielania (MITRE CNA-LR) |
|---|---|
| Typ | CWE-79: Stored (Persistent) Cross-Site Scripting |
| Produkt | Zextras Carbonio WebMail (carbonio-mails-ui) |
| Testowana wersja | v1.31.4 (Carbonio CE) oraz wcześniejsze wersje komercyjne |
| Komponent | Funkcja Print (podgląd wydruku wiadomości) |
| Wektor ataku | Sieciowy (dostarczenie przez e-mail) |
| Interakcja użytkownika | Wymagana (jedno kliknięcie: Print) |
| CVSS 3.1 | 8.1 HIGH |
| Wektor CVSS 3.1 | AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N |
| Status | Naprawione przez producenta w Carbonio 26.03.0 |
Analiza techniczna
Przyczyna źródłowa
Funkcja Print buduje stronę HTML zawierającą metadane wiadomości. Nazwy wyświetlane uczestników korespondencji (fullName dla pól From, To, CC, BCC, Reply-To) są interpolowane bezpośrednio do szablonu wydruku bez kodowania encji HTML. Co znamienne — pole Subject w tym samym szablonie jest poprawnie escapowane funkcją _.escape() z biblioteki lodash. To wskazuje, że deweloperzy byli świadomi ryzyka injection, ale nie zastosowali tej samej ochrony do pól z nazwami uczestników.
Dodatkowo okno wydruku otwierane jest przez window.open("","_blank"), co tworzy dokument about:blank renderowany przez document.write() — bez żadnych nagłówków odpowiedzi HTTP, a więc bez Content-Security-Policy. Brak CSP oznacza nieograniczone wykonanie wstrzykniętego kodu JavaScript.
Kluczowa obserwacja: selektywne escapowanie to częsty antywzorzec — wystarczy, że jedno pole w szablonie zostanie pominięte, by cały mechanizm ochrony przestał działać. Kodowanie wyjścia (output encoding) musi być stosowane konsekwentnie do każdej wartości pochodzącej od użytkownika, niezależnie od tego, jak „niewinne" wydaje się dane pole.
Payload
Payload umieszczany jest w nazwie wyświetlanej nadawcy (From display name). W normalnym widoku wiadomości jest bezpiecznie wyświetlany jako tekst — dopiero użycie funkcji Print powoduje jego wykonanie w kontekście uwierzytelnionej sesji ofiary.
Proof of Concept — okno wydruku renderuje payload z pola From. Alert wyświetla document.domain, potwierdzając wykonanie JavaScript w origin aplikacji Carbonio
Kroki reprodukcji
- Zainstaluj Carbonio CE (testowano na Ubuntu 24.04, carbonio-mails-ui v1.31.4)
- Wyślij do użytkownika Carbonio wiadomość z payloadem XSS w nazwie wyświetlanej nadawcy (pole From)
- Zaloguj się do Carbonio WebMail jako odbiorca
- Otwórz otrzymaną wiadomość
- Wybierz menu akcji (…) i kliknij „Print"
- Otwiera się nowe okno z podglądem wydruku
- Payload JavaScript wykonuje się —
alert(document.domain)potwierdza wykonanie kodu
PoC (Python)
Wpływ (Impact)
Ciasteczka sesyjne są chronione flagą HttpOnly i nie da się ich odczytać przez document.cookie. Jednak payload wykonuje się w tym samym origin co aplikacja Carbonio — przeglądarka automatycznie dołącza ciasteczka do żądań same-origin (fetch, XMLHttpRequest), dając atakującemu pełny dostęp do Carbonio SOAP API bez znajomości wartości ciasteczek.
Odczyt korespondencji
Odczyt wszystkich wiadomości ofiary przez SearchRequest / GetMsgRequest — pełny dostęp do skrzynki.
Wysyłka jako ofiara
Wysyłanie wiadomości w imieniu ofiary (SendMsgRequest) oraz modyfikacja ustawień konta.
Ciche przechwytywanie poczty
Utworzenie reguł przekierowania (forwarding) w celu niewidocznej eksfiltracji całej przychodzącej korespondencji.
Propagacja i lateral movement
Rozprzestrzenienie ataku na kontakty (zachowanie robaka) oraz dostęp do modułów Files, Contacts i Calendar współdzielących origin.
Sugerowana naprawa
Rekomendacja przekazana producentowi:
- Escapowanie encji HTML nazw wyświetlanych uczestników w szablonie wydruku — tą samą funkcją
_.escape()(lodash), która jest już stosowana do pola Subject. - Dodanie nagłówka / meta tagu Content-Security-Policy do szablonu HTML wydruku, aby blokować wykonanie inline-skryptów jako zabezpieczenie defense-in-depth.
Oś czasu (Disclosure Timeline)
| Data | Zdarzenie |
|---|---|
| 2026-03-16 | Odkrycie podatności i reprodukcja na Carbonio CE v1.31.4 |
| 2026-03-17 | Zgłoszenie do zespołu bezpieczeństwa Zextras ([email protected]) z pełnym raportem, PoC i screenshotami |
| 2026-03 | Potwierdzenie podatności przez Zextras; poprawka w przygotowaniu (deklarowany termin ~60 dni) |
| 2026-07-28 | Wydanie poprawki przez producenta — Carbonio 26.03.0 (changelog: „Stored XSS in Print Email Feature", z podziękowaniem dla Grzegorz Tworek (sec4check)) |
| 2026-08 | Wniosek o przydzielenie numeru CVE (MITRE CNA-LR) |
Wnioski
1. Output encoding musi być konsekwentne
Poprawne escapowanie jednego pola (Subject), a pominięcie innych (nazwy uczestników) w tym samym szablonie to klasyczny błąd. Każda wartość pochodząca od użytkownika wymaga kodowania wyjścia — bez wyjątków.
2. Nietypowe konteksty renderowania są równie ważne
Funkcja „Print" wydaje się drugorzędna, ale renderuje dane użytkownika w oknie about:blank pozbawionym CSP. Podczas pentestingu warto testować wszystkie ścieżki wyświetlania danych — nie tylko główny widok aplikacji.
3. Pola „metadanych" bywają wektorem ataku
Nazwa wyświetlana nadawcy jest w pełni kontrolowana przez atakującego i trafia do wielu widoków. To idealny kandydat na stored XSS, jeśli choć jeden z tych widoków pomija sanityzację.
Referencje
- Poprawka producenta: Carbonio 26.03.0 changelog — Stored XSS in Print Email Feature
- Producent: Zextras Carbonio
- CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
- OWASP: Cross Site Scripting (XSS)
- MITRE CVE: numer w trakcie przydzielania — link zostanie dodany po publikacji.
Szukasz podatności w swojej aplikacji?
Profesjonalne testy penetracyjne aplikacji webowych, API i infrastruktury. Identyfikuję podatności zanim zrobią to atakujący — od prostych XSS po złożone chain attacks.
Umów bezpłatną konsultację