
Wprowadzenie do problemu / definicja luki
vm2 to popularna biblioteka do uruchamiania niezaufanego JavaScriptu w „piaskownicy” (sandboxie) w środowisku Node.js. Jej typowy cel to umożliwienie wykonywania kodu użytkownika bez dostępu do systemu plików czy API hosta.
W praktyce okazało się, iż w vm2 wykryto krytyczną podatność typu sandbox escape oznaczoną jako CVE-2026-22709. Pozwala ona napastnikowi uciec z izolacji i wykonać dowolny kod na hoście (RCE) – czyli dokładnie złamać fundamentalne założenie „bezpiecznej piaskownicy”.
W skrócie
- Identyfikator: CVE-2026-22709
- Wektor: obejście mechanizmu sanitizacji callbacków dla Promise.then() / Promise.catch()
- Skutek: sandbox escape → RCE na hoście
- Wersje podatne: vm2 przed 3.10.2
- Naprawa: aktualizacja do ≥ 3.10.2 (w praktyce najlepiej do najnowszej wersji z gałęzi 3.10.x)
- Ocena ryzyka: CVSS 9.8 (Critical) wg CNA (GitHub)
Kontekst / historia / powiązania
vm2 jest szeroko używane m.in. w platformach SaaS pozwalających użytkownikom uruchamiać własne skrypty, runnerach kodu online czy botach/czatbotach. BleepingComputer podaje skalę użycia rzędu 200k+ projektów na GitHub oraz około ~1 mln pobrań tygodniowo w npm.
Jednocześnie vm2 ma historię kolejnych ucieczek z sandboxa. W 2023 r. głośne były m.in. CVE-2023-29017 oraz CVE-2023-30547 – obie klasy „sandbox escape”.
Według BleepingComputer projekt był choćby wstrzymany w 2023 r. z powodu powtarzających się problemów, a później „wskrzeszony” (powrót rozwoju i wersji 3.10.x).
Analiza techniczna / szczegóły luki
Sedno problemu to niekonsekwentna sanitizacja callbacków przypinanych do obietnic (Promises):
- vm2 sanitizuje callbacki dla swojej „lokalnej” implementacji obietnic (w uproszczeniu: localPromise.prototype.then),
- ale nie obejmuje tym samym mechanizmem „globalnych” Promise (tj. globalPromise.prototype.then),
- a ponieważ wartości zwracane z async funkcji są oparte o globalny Promise, atakujący może doprowadzić do wykonania callbacka w sposób umożliwiający wyrwanie się do kontekstu hosta.
W praktyce publicznie pokazano PoC, w którym poprzez manipulację obsługą błędu i uzyskanie dostępu do konstruktorów (np. Function) da się finalnie doprowadzić do uruchomienia polecenia systemowego na hoście (np. przez child_process).
Status poprawek (ważne operacyjnie):
- wg maintenera podatność była częściowo zaadresowana w 3.10.1,
- a 3.10.2 „domknęło” fix tak, aby uniknąć możliwego obejścia.
Praktyczne konsekwencje / ryzyko
Jeśli Twoja aplikacja używa vm2 do uruchamiania jakiegokolwiek kodu pochodzącego od użytkownika lub z nie w pełni zaufanego źródła, konsekwencje mogą obejmować:
- przejęcie serwera/aplikacji (RCE),
- kradzież sekretów (zmienne środowiskowe, tokeny CI/CD, klucze API),
- pivot do sieci wewnętrznej,
- modyfikację danych i łańcuchy ataków supply chain (np. modyfikacja artefaktów build).
Co istotne: wektor CVSS wskazuje m.in. AV:N oraz brak wymogu uprawnień i interakcji użytkownika (wg CNA/GitHub), co w praktyce oznacza, iż scenariusze zdalne są realne w wielu wdrożeniach.
Rekomendacje operacyjne / co zrobić teraz
- Zrób szybki inventory zależności
- Sprawdź, czy vm2 jest zależnością bezpośrednią lub transytywną (np. npm ls vm2, SBOM, skan SCA).
- Zaktualizuj vm2 do wersji bezpiecznej
- Minimum ≥ 3.10.2 (a najlepiej do najnowszej wersji w 3.10.x).
- Jeśli nie możesz zaktualizować „tu i teraz” – załóż, iż sandbox jest zawodny
- Uruchamiaj niezaufany kod w oddzielnym procesie/serwisie z twardą izolacją (kontener/VM), bez dostępu do sekretów i z minimalnymi uprawnieniami.
- Ogranicz egress (firewall), włącz profile typu AppArmor/SELinux/seccomp tam, gdzie to możliwe.
- Wdróż detekcję i kontrolę ryzyka
- Monitoruj anomalie procesów (uruchomienia node, sh, bash, child_process), nietypowe połączenia sieciowe, zmiany plików.
- Rozważ alternatywę architektoniczną
- Jeśli Twoim wymaganiem jest uruchamianie niezaufanego kodu, traktuj vm2 jako element wysokiego ryzyka i preferuj podejścia „defense-in-depth” (izolacja na poziomie OS, osobny worker pool, sandboxing poza jednym procesem Node). Kontekst „wracających ucieczek” w vm2 jest dobrze udokumentowany.
Różnice / porównania z innymi przypadkami
- CVE-2026-22709 dotyczy wprost Promises i sanitizacji callbacków (then/catch) oraz różnicy między promise „lokalnym” a „globalnym” w kontekście async.
- Wcześniejsze głośne podatności (np. CVE-2023-29017, CVE-2023-30547) również prowadziły do sandbox escape, ale wynikały z innych mechanizmów (np. obsługa wyjątków / sanitizacja wyjątków).
Wniosek praktyczny: choćby jeżeli „załataliście” jedną klasę bypassu, model zagrożeń dla vm2 powinien zakładać kolejne obejścia, dlatego izolacja warstwowa (process/container/VM) jest kluczowa.
Podsumowanie / najważniejsze wnioski
- CVE-2026-22709 to krytyczny sandbox escape w vm2, umożliwiający RCE na hoście.
- Podatne są wersje przed 3.10.2; fix został domknięty w 3.10.2.
- Jeśli vm2 obsługuje kod użytkownika lub dane, które mogą zostać „przemycone” do wykonywanego JS, priorytetem jest natychmiastowy upgrade i izolacja defense-in-depth.
Źródła / bibliografia
- BleepingComputer – opis podatności, kontekst popularności i historia vm2 (BleepingComputer)
- NVD (NIST) – rekord CVE-2026-22709 i opis mechanizmu podatności (NVD)
- GitHub Advisory Database – GHSA-99p7-6v5w-7xg8, metryki i techniczne detale/PoC (GitHub)
- Semgrep Blog – omówienie ryzyka i rekomendacja aktualizacji do 3.10.2 (semgrep.dev)
- Snyk Vulnerability Database – widok wersji i statusu podatności w najnowszych wydaniach (VulnInfo Guide)



