CVE-2026-50195 w containerd: zatrucie cache obrazów w klastrach Kubernetes

18 czerwca 2026 r. projekt containerd opublikował advisory GHSA-cvxm-645q-p574 dla podatności CVE-2026-50195. 1 lipca 2026 r. luka trafiła również do NVD. Problem dotyczy procesu importu checkpointów w warstwie CRI i został oceniony jako krytyczny. Dla administratorów Linuksa i platform Kubernetes najważniejszy jest nie sam fakt istnienia kolejnego CVE w runtime kontenerowym, ale mechanizm ataku: możliwość zatrucia lokalnego cache obrazów na węźle i uruchomienia złośliwego obrazu pod tożsamością innego poda.

Diagram pokazujący spreparowany checkpoint, containerd, lokalny cache obrazów i pod uruchamiany z zatrutego taga
CVE-2026-50195 dotyka zaufania do lokalnego cache obrazów na węźle Kubernetes.

Podatne są wersje containerd od 2.1.0 do wcześniejszych niż 2.1.9, od 2.2.0 do wcześniejszych niż 2.2.5 oraz od 2.3.0 do wcześniejszych niż 2.3.2. Poprawki wydano w containerd 2.1.9, 2.2.5 i 2.3.2. W praktyce oznacza to, że problem może dotyczyć zarówno świeżych instalacji testujących linię 2.3, jak i środowisk, które niedawno przeszły z gałęzi 1.7 lub 2.0 na nowsze wydania.

Na czym polega luka

containerd jest jednym z najczęściej spotykanych runtime’ów kontenerowych w środowiskach Kubernetes na Linuksie. Kubelet komunikuje się z runtime’em przez CRI, a runtime odpowiada między innymi za pobieranie obrazów, zarządzanie snapshotami, uruchamianie kontenerów i lokalny cache obrazów na węźle. CVE-2026-50195 dotyczy ścieżki importu checkpointów CRI. Według advisory containerd nie walidował poprawnie referencji obrazów zapisanych w konfiguracji obrazu checkpointu.

Atakujący, który ma uprawnienie do tworzenia podów, może przygotować spreparowany obraz checkpointu. Następnie containerd może zostać zmuszony do pobrania złośliwego obrazu i przypisania mu dowolnego lokalnego taga. To właśnie ten element jest szczególnie groźny: z perspektywy późniejszego poda uruchamianego na tym samym węźle tag może wyglądać jak znany, poprawny obraz, ale lokalny cache wskazuje już na zawartość podstawioną przez atakującego.

Jeżeli inny pod na tym samym węźle korzysta z tej samej nazwy obrazu i ma ustawione imagePullPolicy: IfNotPresent albo imagePullPolicy: Never, kubelet może użyć lokalnej kopii zamiast wymusić ponowne pobranie z rejestru. W efekcie ofiara uruchamia kod atakującego, lecz w swoim kontekście: z własnym ServiceAccount, własnymi sekretami montowanymi do poda, dostępem sieciowym i uprawnieniami RBAC wynikającymi z konfiguracji workloadu.

Dlaczego to jest ważne dla administratora Linuksa

Techniczna grafika z checklistą audytu wersji containerd, imagePullPolicy i RBAC w Kubernetes
Szybki audyt powinien objąć runtime, polityki pullowania obrazów i uprawnienia do tworzenia podów.

Ten błąd dobrze pokazuje, że w Kubernetes granica bezpieczeństwa nie kończy się na API serverze, RBAC i politykach admission. Węzeł linuksowy pozostaje miejscem, gdzie spotykają się: lokalny cache obrazów, credentiale do rejestrów, kubelet, containerd, snapshotter, CNI, mounty i sekrety aplikacji. Jeśli atakujący potrafi wpłynąć na stan lokalny runtime’u na węźle, może ominąć część założeń, które zespół operacyjny zwykle przypisuje do centralnego rejestru obrazów.

W wielu organizacjach IfNotPresent jest używane domyślnie dla obrazów z wersjonowanymi tagami, na przykład backend:1.42.7. Taki wzorzec jest wygodny i ogranicza liczbę pobrań z registry, ale zakłada, że lokalny cache na węźle jest zaufany. CVE-2026-50195 podważa dokładnie to założenie. Nie chodzi o klasyczne przejęcie całego hosta ani o bezpośrednią ucieczkę z kontenera do roota na węźle. Chodzi o atak na łańcuch uruchamiania workloadu: od referencji obrazu, przez lokalny cache, po faktyczny proces w kontenerze.

Kogo powinno to zainteresować w pierwszej kolejności

Priorytet weryfikacji powinny mieć środowiska, w których wielu użytkowników lub wiele zespołów może tworzyć pody w tych samych klastrach. Szczególnie istotne są klastry developerskie, platformowe i CI/CD, gdzie uprawnienie create pods bywa szerokie, a separacja między namespace’ami jest traktowana jako wystarczająca granica. W tym scenariuszu atakujący nie musi od razu łamać kontenera ofiary. Wystarczy, że spowoduje przygotowanie skażonego lokalnego taga na węźle, na którym później zostanie zaplanowany podatny workload.

  • Najwyższe ryzyko: klastry wielodzierżawne, środowiska CI, namespace’y dla wielu zespołów oraz workloady z imagePullPolicy: IfNotPresent lub Never.
  • Ryzyko umiarkowane: klastry jednego zespołu, ale z automatyzacją tworzącą pody z różnych pipeline’ów i repozytoriów.
  • Ryzyko niższe: klastry z aktualnym containerd, wymuszonym pullowaniem obrazów i ścisłą kontrolą tego, kto może tworzyć pody.

Jak sprawdzić wersję containerd w Kubernetes

Pierwszy krok to inwentaryzacja runtime’u na węzłach. Kubernetes pokazuje wersję runtime’u w statusie noda. To szybki sposób, żeby wykryć, czy w klastrze występują wersje z podatnych zakresów.

kubectl get nodes -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.nodeInfo.containerRuntimeVersion}{"\n"}{end}'

# Przykładowy wynik:
# worker-01  containerd://2.3.1
# worker-02  containerd://2.2.4
# worker-03  containerd://2.3.2

Jeżeli zobaczysz containerd://2.3.0, containerd://2.3.1, containerd://2.2.02.2.4 albo containerd://2.1.02.1.8, węzeł powinien trafić na listę pilnej aktualizacji. Warto pamiętać, że w środowiskach zarządzanych wersja runtime’u może zależeć od obrazu node poola, a nie od pakietu instalowanego ręcznie przez administratora. W takim przypadku aktualizacja oznacza zwykle upgrade node poola, rotację węzłów albo przejście na nowszy obraz systemowy dostawcy.

Sprawdź, gdzie używasz IfNotPresent i Never

Drugi krok to sprawdzenie workloadów, które mogą korzystać z lokalnego cache. Kubernetes ustawia IfNotPresent między innymi wtedy, gdy obraz ma tag inny niż :latest i pole imagePullPolicy nie zostało jawnie podane przy tworzeniu obiektu. Dlatego brak tego pola w manifeście nie zawsze oznacza neutralny stan. W działającym obiekcie warto sprawdzić realną wartość zapisaną w specyfikacji poda.

kubectl get pods -A -o json \
  | jq -r '.items[] as $pod
    | $pod.spec.containers[]
    | select(.imagePullPolicy == "IfNotPresent" or .imagePullPolicy == "Never")
    | [$pod.metadata.namespace, $pod.metadata.name, .name, .image, .imagePullPolicy]
    | @tsv'

# Kolumny: namespace, pod, container, image, imagePullPolicy

Ten raport nie mówi, że dany pod został zaatakowany. Pokazuje natomiast powierzchnię ryzyka: miejsca, w których lokalny cache obrazu ma znaczenie dla decyzji o uruchomieniu kontenera. Szczególną uwagę warto zwrócić na workloady z szerokimi uprawnieniami, dostępem do sekretów produkcyjnych, tokenami deployowymi, dostępem do baz danych lub możliwością wykonywania operacji administracyjnych przez Kubernetes API.

Co zrobić praktycznie

Najważniejsza rekomendacja jest prosta: zaktualizować containerd do wersji zawierającej poprawkę. Dla linii 2.3 jest to 2.3.2, dla 2.2 jest to 2.2.5, a dla 2.1 jest to 2.1.9. Jednocześnie linia 2.1 osiągnęła koniec życia 3 lipca 2026 r., więc w środowiskach, które nadal na niej pracują, lepszym planem będzie migracja na wspieraną gałąź zamiast traktowania 2.1.9 jako długoterminowego rozwiązania.

Po aktualizacji runtime’u nie kończ pracy na samym pakiecie. Węzły powinny zostać zrotowane albo przynajmniej zrestartowane w kontrolowany sposób, tak aby kubelet i containerd faktycznie działały w poprawionej wersji. Jeżeli podejrzewasz możliwość nadużycia, rozważ wyczyszczenie lokalnego cache obrazów na węzłach po wcześniejszym cordon/drain i upewnieniu się, że krytyczne workloady zostaną odtworzone z zaufanego registry.

Warto też wprowadzić kilka zmian konfiguracyjnych i organizacyjnych:

  1. Ogranicz uprawnienie create pods do minimalnej liczby ról i namespace’ów.
  2. Dla workloadów o wysokiej wrażliwości rozważ imagePullPolicy: Always oraz odwołania do obrazów przez digest, np. repo/app@sha256:....
  3. Włącz lub dopracuj polityki admission, które blokują imagePullPolicy: Never poza wyjątkowymi namespace’ami technicznymi.
  4. Monitoruj tworzenie podów korzystających z nietypowych obrazów checkpointów i anomalii w lokalnym cache runtime’u.
  5. Utrzymuj osobne node poole dla mniej zaufanych workloadów CI, testów i sandboxów.

Nie tylko patch: lekcja dla polityki obrazów

CVE-2026-50195 jest dobrym momentem, żeby przejrzeć politykę obrazów kontenerowych. W wielu zespołach nadal funkcjonuje skrót myślowy: „skoro obraz pochodzi z naszego registry, to jest bezpieczny”. W Kubernetes ta deklaracja musi być doprecyzowana: czy kubelet rzeczywiście pobierze obraz z registry, czy użyje lokalnego cache? Czy tag jest mutowalny? Czy admission kontroluje digest? Czy węzły są współdzielone przez workloady o różnym poziomie zaufania?

Najbardziej odporne podejście to połączenie kilku warstw: aktualny runtime, ograniczony RBAC, podpisywanie lub weryfikacja obrazów, preferowanie digestów, twarde polityki admission oraz segmentacja node pooli. Żadna z tych warstw osobno nie jest idealna, ale razem zmniejszają prawdopodobieństwo, że błąd w jednym komponencie runtime’u stanie się incydentem obejmującym aplikacje innych zespołów.

Podsumowanie praktyczne

Do 19 lipca 2026 r. najważniejsze działania dla zespołów Linux/Kubernetes są jasne: sprawdź wersje containerd na wszystkich węzłach, zaktualizuj do 2.3.2, 2.2.5 albo 2.1.9, przejrzyj użycie IfNotPresent i Never, a następnie ogranicz możliwość tworzenia podów przez mniej zaufane role. CVE-2026-50195 nie jest tylko błędem w niszowej funkcji checkpointów. To przypomnienie, że lokalny stan runtime’u na linuksowym węźle jest częścią łańcucha zaufania całej platformy kontenerowej.

Duża grafika podsumowująca plan mitygacji: aktualizacja containerd, rotacja węzłów, admission policy i segmentacja node pooli
Najlepsza ochrona to połączenie aktualizacji runtime’u z kontrolą obrazów i separacją workloadów.

Źródła i dalsza lektura

LinuxAdmin Online
Przegląd prywatności

Ta strona korzysta z ciasteczek, aby zapewnić Ci najlepszą możliwą obsługę. Informacje o ciasteczkach są przechowywane w przeglądarce i wykonują funkcje takie jak rozpoznawanie Cię po powrocie na naszą stronę internetową i pomaganie naszemu zespołowi w zrozumieniu, które sekcje witryny są dla Ciebie najbardziej interesujące i przydatne.