Pickle in the Middle: atakujący podmienił model w 1,4 sekundy. Vertex AI czytał go po 2,5. Cała różnica między bezpieczeństwem a przejęciem zmieściła się w tej sekundzie.

cze 19, 2026 | Cyberflux

Unit 42 z Palo Alto Networks ujawnił podatność w SDK Pythona dla Google Cloud Vertex AI, która pozwalała atakującemu przejąć cudzy upload modelu uczenia maszynowego i wykonać kod wewnątrz infrastruktury serwującej Google — bez żadnego dostępu do projektu ofiary. Badacze nazwali metodę „Pickle in the Middle". Wymagała tylko jednej rzeczy: identyfikatora projektu ofiary, który często jest publiczny. Bez phishingu, bez haseł, bez dostępu do celu.

Google naprawił błąd przez program bug bounty, Unit 42 nie zaobserwował eksploatacji w praktyce, a podatność nie dostała numeru CVE. Ale mechanizm jest na tyle pouczający — i na tyle dobrze ilustruje, jak wygląda atak na infrastrukturę AI — że zasługuje na rozłożenie. Bo to nie jest jeden błąd. To są trzy znane słabości, które osobno są drobne, a razem dają cross-tenant RCE.

Trzy klocki, jeden atak

Vertex AI to platforma Google Cloud do trenowania i wdrażania modeli ML. Gdy deweloper uploaduje model przez SDK, artefakty są tymczasowo umieszczane w buckecie Google Cloud Storage, zanim trafią do wdrożenia. Cały atak rozgrywa się w tym momencie przejściowym — i składa się z trzech warstw.

Klocek pierwszy: przewidywalna nazwa bucketa. Jeśli użytkownik nie podał własnego bucketa, SDK generował nazwę w przewidywalny sposób — na podstawie identyfikatora projektu i regionu. To jest pozornie niewinna decyzja projektowa: wygodny, deterministyczny schemat nazewnictwa. Problem polega na tym, co opisywaliśmy już jako klasę ataku przy node-ipc i przejmowaniu wygasłych zasobów: jeśli nazwa jest przewidywalna, ktoś może ją zająć z wyprzedzeniem.

Klocek drugi: globalna unikalność i brak weryfikacji własności. I tu jest sedno. W Google Cloud żadne dwa buckety w całej platformie nie mogą mieć tej samej nazwy. Atakujący, który potrafi przewidzieć nazwę bucketa, może utworzyć go z wyprzedzeniem we własnym projekcie. Każda kolejna próba użycia bucketa o tej nazwie — nawet z zupełnie innego projektu — po cichu trafia do bucketa atakującego. SDK weryfikował tylko, czy bucket istnieje, nie czyj jest. Unit 42 nazwał tę klasę „Bucket Squatting" — zajmowaniem bucketów, wykorzystującym globalną unikalność nazw.

Efekt: SDK ofiary uploaduje pliki modelu do bucketa atakującego. Izolacja między najemcami — fundament bezpieczeństwa chmury — zostaje cicho złamana, bo SDK nie sprawdza, do kogo bucket należy.

Klocek trzeci: niebezpieczna deserializacja pickle. Wiele modeli ML w Pythonie zapisuje się formatem pickle lub joblib — które potrafią wykonać kod w momencie wczytania pliku. To jest znana, od lat ostrzegana właściwość formatu pickle: deserializacja to nie jest bierne odczytanie danych, to może być wykonanie kodu. Gdy Vertex AI później wczytywał podmieniony model z bucketa atakującego, kod atakującego wykonywał się wewnątrz kontenera serwującego.

Trzy klocki: przewidywalna nazwa pozwala zająć bucket, brak weryfikacji własności przekierowuje upload do atakującego, niebezpieczna deserializacja zamienia podmieniony plik w wykonanie kodu. Żaden z nich osobno nie jest spektakularny. Razem dają zdalne wykonanie kodu w infrastrukturze Google, bez dostępu do projektu ofiary.

Sekunda, która decydowała o wszystkim

Jest w tym ataku szczegół, który czyni go niemal filmowym — i pokazuje, jak wąskie bywają okna, w których rozgrywa się kompromitacja.

Atak zależał od szybkości. Unit 42 zmierzył około 2,5 sekundy między uploadem ofiary a momentem, gdy Vertex AI odczytywał plik. W swoim proof-of-concept atakujący użył Cloud Function, która uruchamiała się po uploadzie i podmieniała model w 1,4 sekundy — zanim Vertex AI zdążył go przeczytać. Cała różnica między „model ofiary trafia do wdrożenia" a „kod atakującego wykonuje się w infrastrukturze Google" rozegrała się w tej jednej sekundzie przewagi.

To jest race condition — wyścig, w którym atakujący musi podmienić plik w wąskim oknie między uploadem a odczytem. 1,4 sekundy kontra 2,5 sekundy. Automatyzacja po stronie atakującego (Cloud Function wyzwalana zdarzeniem) dała tę przewagę niezawodnie. To jest ta sama klasa, którą opisywaliśmy przy RoguePlanet w Defenderze — race condition jako mechanizm, gdzie liczy się trafienie w okno czasowe. Tutaj okno było mierzone w sekundach, a atakujący zmieścił się w nim z zapasem.

Blast radius: token, który nie był ograniczony do jednego wdrożenia

To, co stało się po wykonaniu kodu, jest najważniejsze dla zrozumienia, dlaczego atak na infrastrukturę AI jest groźniejszy niż na pojedynczą aplikację.

Ładunek wykradł token OAuth z serwera metadanych kontenera serwującego i wysłał go do atakującego. A w środowisku testowym Unit 42 ten token nie był ograniczony do skompromitowanego wdrożenia. Skradzione poświadczenia niosły szeroki zakres uprawnień do całej platformy chmurowej — co znacząco powiększało blast radius ataku.

W proof-of-concept atakujący byli w stanie: wyciągnąć tokeny konta serwisowego z serwera metadanych, uzyskać dostęp do innych modeli przechowywanych w tym samym środowisku najemcy, enumerować zbiory danych i uprawnienia BigQuery oraz zbierać szczegóły infrastruktury wewnętrznej z logów chmurowych. Innymi słowy: jeden podmieniony model nie dawał dostępu tylko do jednego wdrożenia. Dawał token, którym można było sięgnąć po inne modele, dane i konfigurację w środowisku ofiary.

To jest dokładnie ten wzorzec „skarbca", który opisywaliśmy przy Langflow i JetBrains: kompromitacja komponentu AI nie kończy się na tym komponencie, bo daje poświadczenia o szerokim zakresie. Token konta serwisowego z serwera metadanych to klucz nie do jednego pokoju, ale do całego piętra. Cel ataku przesuwa się z samego modelu na to, do czego model ma dostęp.

Dlaczego to jest temat dla cyberflux

Ta podatność jest dobrym przykładem tezy, którą prowadzimy od tygodni: bezpieczeństwo chmury rozciąga się teraz na toolchain dewelopera i cykl życia modelu ML. Unit 42 ujął to wprost — pokazali, że pozornie drobne błędy projektowe (przewidywalna nazwa, brak jednej weryfikacji) prowadzą do krytycznego problemu bezpieczeństwa.

Warto zauważyć, czego ten atak nie wymagał. Nie wymagał zero-daya w sensie klasycznym — pickle jest znany od lat, bucket squatting jest znaną klasą, przewidywalne nazwy zasobów to stary problem. Wymagał złożenia tych trzech znanych rzeczy w kontekście infrastruktury AI, gdzie upload modelu jest rutynową operacją, a format pickle jest standardem. To jest ta sama lekcja, co przy OWASP Agentic AI: nowe powierzchnie ataku w AI często nie są nowymi klasami błędów, tylko starymi klasami zastosowanymi do nowych przepływów, których nikt jeszcze nie przeskanował pod tym kątem.

Jest też pozytywny wymiar tej historii, wart odnotowania w kontekście naszej serii o disclosure. Proces zadziałał wzorcowo. Unit 42 zgłosił błąd 5 marca, Google nadał mu najwyższy priorytet 9 marca, pierwszą poprawkę wdrożył 31 marca (dodając losowy uuid4 do nazwy bucketa), a pełną naprawę 15 kwietnia (dodając weryfikację własności bucketa, by zablokować bucket squatting). Bez sporu, bez publicznej awantury, bez wycieku PoC przed łatką. To jest kontrast wobec Chaotic Eclipse i ChatGPhish — pokazuje, że odpowiedzialne ujawnienie wciąż potrafi działać, gdy obie strony współpracują.

Co zrobić

Zaktualizuj SDK google-cloud-aiplatform do wersji 1.148.0 lub nowszej. To jest wersja z aktywną weryfikacją własności bucketa — wcześniejsze (1.139.0 i 1.140.0 potwierdzone jako podatne) pozwalają na bucket squatting. To jest pierwszy i najważniejszy krok.

Ustawiaj jawny staging_bucket na lokalizację Cloud Storage, którą kontrolujesz, przy uploadzie modeli. To eliminuje cały wektor niezależnie od wersji SDK — jeśli wskazujesz własny bucket, SDK nie generuje przewidywalnej nazwy, którą ktoś mógłby zająć z wyprzedzeniem. Nie polegaj na domyślnym zachowaniu nazewnictwa.

Traktuj format pickle/joblib jako wektor wykonania kodu, nie tylko format danych. To jest szersza lekcja wykraczająca poza Vertex AI: wczytanie modelu zapisanego w pickle z niezaufanego źródła to potencjalne wykonanie kodu. Tam, gdzie to możliwe, używaj bezpieczniejszych formatów serializacji (jak safetensors) i waliduj pochodzenie artefaktów modelu przed wczytaniem.

Ogranicz zakres tokenów kont serwisowych w środowiskach serwujących AI. Najgroźniejsza część tego ataku to nie samo RCE, ale token o szerokim zakresie, który dało się z niego wyciągnąć. Zasada najmniejszych uprawnień dla kont serwisowych przypisanych do wdrożeń modeli ogranicza blast radius, gdyby kontener serwujący został przejęty.

Zinwentaryzuj, gdzie w twoim cyklu życia ML artefakty są umieszczane przejściowo i kto może do tych lokalizacji pisać. Ten atak rozegrał się w przejściowym, łatwym do przeoczenia kroku stagingu. Miejsca tymczasowego składowania artefaktów modeli zasługują na tę samą uwagę co repozytoria produkcyjne.

Źródła

Unit 42 (Palo Alto Networks) — oryginalny research „Pickle in the Middle" z pełną analizą łańcucha i osią czasu disclosure: https://unit42.paloaltonetworks.com/hijacking-vertex-ai-model/

The Hacker News — szczegóły wyścigu czasowego (1,4s vs 2,5s) i kradzieży tokenu OAuth: https://thehackernews.com/2026/06/google-vertex-ai-sdk-flaw-let-attackers.html

CSO Online — analiza mechanizmu bucket squatting i globalnej unikalności nazw: https://www.csoonline.com/article/4186193/googles-vertex-ai-sdk-could-allow-rce-through-bucket-squatting.html

Cryptika — szczegóły blast radius: tokeny konta serwisowego, BigQuery, logi infrastruktury: https://www.cryptika.com/google-cloud-vertex-ai-allows-attacker-to-hijack-victims-model-and-poison-it/

GBHackers — analiza trzech złożonych słabości i kontekst Model Registry: https://gbhackers.com/google-cloud-vertex-ai-vulnerability/