Strona główna / Blog / Excelize: spinCount CPU DoS

Blog · case study

Excelize: 3 KB pliku może zająć rdzeń na minutę, a timeout HTTP nie zatrzyma goroutine. Kiedy biblioteka plikowa staje się zdalnym CPU DoS

GHSA-jrfj-fhj2-jjvm w bibliotece Excelize łączy trzy problemy, które SCA zwykle spłaszcza do jednego findingu: biblioteka ma podatny kod, exploitability zależy od pochodzenia plików, a popularny „compensating control” w postaci timeoutu HTTP może zakończyć odpowiedź klientowi, ale nie zakończyć kosztownej pracy CPU po stronie serwera.

GHSA-jrfj-fhj2-jjvm (CVSS 7.5, Availability): nieograniczony, kontrolowany przez atakującego spinCount w ścieżce agile decryption (github.com/xuri/excelize/v2).
PoC: ~3072-bajtowy plik z spinCount=100000000OpenFile pracuje ~58,65 s (Excelize 2.11.0) i i tak kończy błędem invalid zip; koszt ~0,6 µs/iterację (liniowo).

Jak mały plik pali CPU

Excelize rozpoznaje kontener OLE po pierwszych ośmiu bajtach. Jeśli wejście wygląda jak zaszyfrowany dokument Office, OpenFile wchodzi w ścieżkę deszyfrowania — niezależnie od tego, czy aplikacja świadomie oferuje pracę z zaszyfrowanymi workbookami. Atakujący kontroluje spinCount, a kosztowny convertPasswdToKey wykonuje się przed weryfikacją, czy dane to poprawny workbook. Pamięć pozostaje stabilna — zasobem jest czas CPU, nie heap, więc klasyczne memory limits nie zatrzymają ataku.

Dlaczego HTTP timeout nie wystarcza

To najważniejszy detal dla VE. Kosztowna operacja nie ma context.Context, którym caller mógłby anulować pracę. Serwer HTTP może przekroczyć write timeout i zamknąć odpowiedź po kilku sekundach, ale goroutine wykonująca KDF nadal działa:

klient dostał timeout reverse proxy zamknęło połączenie dashboard latency przestał mierzyć request CPU nadal jest konsumowane

proxy_read_timeout 5s nie jest dowodem mitigacji — ogranicza czas życia połączenia, nie czas życia obliczenia.

Package affected ≠ application exploitable

Biblioteka nie nasłuchuje na sieci — network attack vector pojawia się, gdy aplikacja przyjmuje workbook od użytkownika i przekazuje go do OpenFile. Narzędzie otwierające wyłącznie pliki generowane wewnętrznie nie ma tego samego attack surface co publiczny SaaS analizujący pliki klientów. To dobry przykład dla VEX: ustal input trust, call-path reachability i runtime resource controls, zanim nadasz identyczne SLA każdej aplikacji z Excelize 2.11.0.

Brak patcha — inny workflow

W momencie publikacji advisory upstream nie wskazywał patched version. Nie wymyślaj numeru i nie przesuwaj findingu do Risk accepted tylko dlatego, że nie ma patcha. Lepszy model stanu: exploitable / no vendor fix → temporary mitigation applied → mitigation verified → awaiting upstream remediation.

Które compensating controls działają

Najsilniejsze odcinają lub ograniczają kosztowną ścieżkę, nie tylko kończą połączenie: odrzucanie plików OLE/encrypted przed Excelize (jeśli to nie funkcja biznesowa), uruchamianie parsera w osobnym procesie/jobie z twardym limitem CPU i deadline egzekwowanym przez supervisora, który może zabić proces, ograniczenie równoległości na tenant, kolejka z backpressure. Jeśli proces nie może zostać przerwany, sam timeout aplikacyjny jest control present, ale nie control effective.

Wniosek

Najważniejsze pytanie nie brzmi „czy mamy Excelize?”, tylko: czy niezaufany plik może uruchomić nieograniczoną pracę, której nasz system nie potrafi rzeczywiście przerwać? Jeśli tak, 504 to nie sukces. To dobry wzorzec do zapamiętania: timeout połączenia, deadline requestu i limit życia obliczenia to trzy różne kontrole.

Powiązane na blogu

Źródła

  • qax-os/excelize — Security Advisory GHSA-jrfj-fhj2-jjvm (06.09.2026) — github.com/qax-os

Nota redakcyjna: stan informacji 7 września 2026. GHSA-jrfj-fhj2-jjvm (excelize/v2, CVSS 7.5 Availability): nieograniczony spinCount w agile decryption; kosztowny KDF biegnie przed walidacją i bez możliwości anulowania. W chwili publikacji brak patched version. Artykuł koncentruje się na różnicy między timeoutem połączenia a limitem życia obliczenia i na reachability niezaufanego pliku.

Zapamiętaj jedno

Timeout połączenia, deadline requestu i limit życia obliczenia to trzy różne kontrole. Jeśli niezaufany plik może uruchomić nieograniczoną, nieanulowalną pracę, 504 Gateway Timeout nie jest sukcesem — to tylko informacja, że klient przestał czekać, podczas gdy rdzeń dalej liczy.