Moduły ładowania obrazów wieloklatkowych Pillow mogą ponownie wykorzystać nieaktualną pamięć natywną po zmianie trybu
Podsumowanie
Moduły ładowania obrazów wieloklatkowych w bibliotece Pillow mogą zachowywać pamięć natywną ImagingCore przydzieloną dla jednej klatki, podczas gdy po stronie Pythona następuje zmiana trybu obrazu mode oraz kafelków dekodera dla kolejnej klatki.
Jeśli klatka 0 alokuje pamięć dla węższego trybu, takiego jak L, a kolejna klatka o tych samych wymiarach przełącza się na szerszy tryb, taki jak RGB lub CMYK, Pillow może zdekodować szersze piksele do nieaktualnego, węższego bufora natywnego. Prowadzi to do natywnego zapisu poza zakresem i awarii procesu. Na ścieżce MPO/JPEG wykazano również możliwość wykonania poleceń w pasujących środowiskach wykonawczych Python/Pillow za pośrednictwem udokumentowanej ścieżki ImageSequence.Iterator + frame.load().
Szczegóły
Przyczyną problemu jest fakt, że ImageFile.load_prepare() ponownie alokuje pamięć natywną tylko wtedy, gdy _im is None. Nie sprawdza, czy zachowana pamięć natywna ImagingCore nadal odpowiada właściwościom self.mode i self.size.
Wiele ścieżek wieloklatkowych seek() / _open() może aktualizować self._mode i kafelki dekodera dla późniejszej klatki bez unieważniania _im. Dekoder zapisuje lub odczytuje dane zgodnie z nowym trybem klatki, podczas gdy pamięć natywna nadal odpowiada trybowi poprzedniej klatki.
Zweryfikowane podatne komponenty:
-
PSD
PsdImageFile.seek()może przełączyć się ze skali szarości / natywnego buforaLna dekodowanie warstwy RGB przy jednoczesnym zachowaniu_im. Powoduje to kontrolowany przez atakującego natywny zapis poza dozwolonym zakresem i powtarzalną awarię procesu. -
MPO/JPEG Odpowiednio spreparowany plik MPO z dwiema klatkami może spowodować alokację pamięci
Lprzez klatkę 0, a następnie dekodowanie danychCMYK/RGBdla klatki 1 do zachowanej pamięciL. Udokumentowana ścieżkaImageSequence.Iteratorwywołuje ten stan poprzezframe.load(). Zweryfikowano uszkodzenie pamięci natywnej, awarię, odczyt poza zakresem oraz demonstracyjne wykonanie niegroźnego polecenia znacznika w środowisku Pillow 12.3.0. -
DCX
DcxImageFile.seek()wywołujePcxImageFile._open(), co modyfikuje stan trybu/kafelków bez weryfikacji trybu pamięci natywnej. Spreparowany plik DCX z klatkami PCXL, a następnieRGBprowadzi do niezgodności zachowanej pamięci i awarii. -
MIC Format MIC może wywołać
TiffImageFile._open()bezpośrednio i pominąć standardowe zabezpieczone zachowanie formatu TIFF wseek(). W przypadku osiągalnego przejścia między klatkami opartego naNextIFDskutkuje to niezgodnością pamięci i awarią.
Format TIFF stanowi przydatny punkt odniesienia, ponieważ ścieżka seek() weryfikuje zarówno rozmiar, jak i tryb przed ponownym użyciem pamięci.
Wpływ
- Awaria procesu / odmowa usługi (DoS)
- Natywny zapis poza zakresem (out-of-bounds write)
- Natywny odczyt poza zakresem w ścieżce MPO
- Wykonanie poleceń w pasujących środowiskach uruchomieniowych Python/Pillow za pośrednictwem ścieżki MPO/JPEG
Wpływ na wdrożenia serwerowe:
- W lokalnej, podatnej usłudze przesyłania plików, która przyjmuje nieuwierzytelnione pliki MPO i automatycznie przetwarza je przy użyciu Pillow, atak wymaga pojedynczego żądania HTTP i nie wymaga interakcji użytkownika po przesłaniu pliku.
- Znacznik wykonania nieszkodliwego polecenia powiódł się w 10/10 prób.
- Przebieg kontrolny
_im=Nonezakończył się poprawnie w 10/10 przypadków.
Dowody reprodukcji
Testowana wersja:
Pillow 12.3.0
Środowiska testowe w terminalu dla MPO:
Python 3.12.3 + Pillow 12.3.0, clean PyPI environment:
marker 10/10, control 0/10
Python 3.13.14 + Pillow 12.3.0, prepared profile:
marker 10/10, control 0/10
Dowód koncepcji w usłudze przesyłania plików na serwerze:
control 1..10: MARKER_MISSING
control_summary ok 0 missing 10 /10
vulnerable 1..10: MARKER_OK marker_output <server-user>
vulnerable_summary ok 10 missing 0 /10
Test w terminalu używa wyłącznie predefiniowanego, nieszkodliwego polecenia-znacznika. Nie korzysta z reverse shella, mechanizmów trwałości, eksfiltracji danych ani dowolnych poleceń zdefiniowanych przez atakującego.
Następujące artefakty mogą zostać udostępnione opiekunom projektu:
- Minimalne pliki wywołujące awarię dla formatów PSD, MPO, DCX oraz MIC
- Niezbrojny dowód koncepcji ze znacznikiem MPO
- Lokalna demonstracja podatnej usługi przesyłania plików
- Zrzuty geometrii z gdb/GEF
- Dzienniki przebiegów kontrolnych
- Proponowany szablon testu regresyjnego
Minimalny schemat reprodukcji
Dla ścieżki MPO podatny kod przyjmuje postać:
from io import BytesIO
from PIL import Image, ImageSequence
source = BytesIO(open(path, "rb").read())
image = Image.open(source)
iterator = ImageSequence.Iterator(image)
next(iterator).load()
next(iterator).load()
Struktura spreparowanego obrazu:
frame 0: mode L, dimensions W x H
frame 1: same W x H, wider mode such as CMYK
Klatka 0 alokuje natywną pamięć L. Klatka 1 zmienia tryb logiczny i stan dekodera, lecz może ponownie wykorzystać poprzednią pamięć natywną. Dekoder klatki 1 zapisuje dane w szerszym trybie do węższej pamięci.
Sugerowany kierunek naprawy
Przed ponownym użyciem natywnej pamięci ImagingCore Pillow powinien sprawdzić, czy zachowany bufor jest kompatybilny z bieżącym logicznym trybem i rozmiarem obrazu.
Centralne zabezpieczenie w ImageFile.load_prepare() mogłoby porównywać tryb/rozmiar pamięci natywnej z self.mode / self.size i alokować nową pamięć w przypadku różnic. Alternatywnie każda ścieżka zmieniająca tryb w seek() / _open() powinna jawnie unieważniać _im przed rozpoczęciem dekodowania.
Uwaga: Format TIFF posiada specyficzne zachowanie dotyczące rozmiarów kafelków oraz ma już zabezpieczenie trybu/rozmiaru, dlatego globalna poprawka nie powinna zaburzać obsługi bufora kafelków TIFF.
Podziękowania
Rotem Kama
Uwagi metodologiczne
Do wykrycia i weryfikacji problemu wykorzystano analizę wspomaganą przez sztuczną inteligencję. Wnioski w tym raporcie ograniczają się do lokalnych artefaktów, prób kontrolnych i wyników poleceń opisanych powyżej.
Co trzeba zrobić
Zaktualizuj bibliotekę Pillow do wersji 13.0.0 lub nowszej.
Czego dotyczy
Kliknij technologię, aby zobaczyć wszystkie dotyczące jej podatności.
| Platforma | Paczka | Podatne wersje | Poprawka w wersji |
|---|---|---|---|
| Python (PyPI) | pillow | >= 11.0.0, < 13.0.0 | 13.0.0 |
Odnośniki
- https://github.com/python-pillow/Pillow/security/advisories/GHSA-v9pv-5gc8-w2m6
- https://nvd.nist.gov/vuln/detail/CVE-2026-96639
- https://github.com/python-pillow/Pillow/pull/10105
- https://github.com/python-pillow/Pillow/commit/78d97d994579aef81aafe123773d525f40f2522a
- https://github.com/python-pillow/Pillow
- https://github.com/python-pillow/Pillow/releases/tag/13.0.0
- Wektor CVSS
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H- Słabość (CWE)
CWE-125, CWE-787- Platforma
- Python (PyPI)
- Paczka
pillow- Ujawniono
- 22.10.2026
- Aktualizacja
- 23.10.2026 00:03
Źródła i licencje · Redakcja lub tłumaczenie: DockRay. Zachowano prawa źródeł i obowiązujące licencje.
OSV / GitHub Advisory Database - GHSA-v9pv-5gc8-w2m6 - CC BY 4.0
Historia podatności: pillow
Wszystkie opisane podatności tej paczki (Python (PyPI)), od najnowszej. Widać, czy to jednorazowa wpadka, czy paczka, której trzeba pilnować.
- Wszystkich wpisów
- 100
- Pierwsza → ostatnia
- 04.2014 10.2026
- Bez poprawki
- 0
- Wykorzystywana w atakach
- 1
Rozkład istotności
- Krytyczna 13
- Wysoka 58
- Średnia 27
- Niska 1
- Nieoceniona 1
Ujawnienia w latach
- 2017: 1
- 2018: 0
- 2019: 1
- 2020: 10
- 2021: 20
- 2022: 8
- 2023: 3
- 2024: 2
- 2025: 1
- 2026: 42
wcześniej: 12
-
Moduły ładowania obrazów wieloklatkowych Pillow mogą ponownie wykorzystać nieaktualną pamięć natywną po zmianie trybu ten wpis
Dowiedz się, które podatności dotyczą Twojej aplikacji
Po podłączeniu integracji DockRay i włączeniu raportowania oprogramowania DockRay porównuje zgłoszone wersje komponentów ze znanymi podatnościami i powiadamia o potwierdzonych dopasowaniach. Zakres zależy od obsługiwanej technologii i dostępnych biuletynów.