Přeskočit na obsah
Tech-Blog Chatujme.cz Chatujme.cz
Bezpečnost

Oživený sandbox vm2 vynechal child_process ze seznamu zakázaných modulů

Knihovna vm2 má spouštět cizí JavaScript tak, aby se nedostal k hostiteli. Záznam, který se tenhle týden objevil ve veřejné databázi GitHubu, popisuje opak: jediné zavolání require stačilo ke spuštění libovolného příkazu na stroji, kde sandbox běží. Oprava je přitom ve verzi 3.12.1 z 3. září.

· 15 zhlédnutí

Knihovna vm2 má jediný úkol. Spustit cizí JavaScript tak, aby se nedostal k hostiteli, na kterém běží. Záznam, který se tenhle týden objevil ve veřejné databázi bezpečnostních oznámení GitHubu, popisuje přesný opak: jediné zavolání require stačilo ke spuštění libovolného příkazu na stroji se sandboxem. Chyba CVE-2026-93605 dostala v obou verzích stupnice CVSS plný počet, deset bodů z deseti.

Záznam CVE-2026-93605 v databázi bezpečnostních oznámení GitHubu
Záznam CVE-2026-93605 v databázi bezpečnostních oznámení GitHubu. Jako dotčené vede všechny verze vm2 do 3.12.0 včetně, opravu klade do 3.12.1. Foto: vlastní snímek obrazovky, github.com (snímek obrazovky)

Seznam, ve kterém jedno jméno chybělo

Zajímavé je, kde díra byla. Oživená řada vm2 přidala do zavaděče modulů tvrdý seznam DANGEROUS_BUILTINS v souboru lib/builtin.js. Jsou v něm vestavěné moduly Node.js, které se k sandboxu nesmí dostat ani tehdy, když si o ně embedder výslovně řekne. Komentář nad seznamem to říká natvrdo: tyhle primitivy nesmí být ze sandboxu dosažitelné nikdy, ani přes hvězdičku, ani jmenovitě.

Jmen tam stálo šestnáct: module, worker_threads, cluster, vm, repl, inspector, process, trace_events, wasi, diagnostics_channel, async_hooks, perf_hooks, v8, os, dns a test. Chyběl child_process, tedy modul, kterým se příkaz na hostiteli spustí nejkratší možnou cestou.

Důsledek popisuje oznámení projektu i přiložená ukázka. Sandbox nastavený na builtin: ['*'] dostal skutečný hostitelský modul, ne náhradu, a jeden řádek z něj udělal spuštění příkazu pod právy hostitelského procesu.

const { NodeVM } = require('vm2');

const r = new NodeVM({ require: { builtin: ['*'] } }).run(`
  module.exports = require('child_process').execSync('id').toString();
`, 'plugin.js');

console.log(r);   // uid=1000(user) gid=1000(user) groups=...

Stejně dopadl i dokumentovaný zápis s odečítáním (['*', '-fs']), výslovná žádost ['child_process'] a zápis s předponou node:. Jediné, co modul nevydalo, byla konfigurace, která o něj vůbec nežádá.

Nešlo o jméno, na které by nikdo nepomyslel. Na seznamu je cluster a oznámení cituje odůvodnění, se kterým se tam dostal: „cluster.fork() spouští hostitelský podřízený proces, který běží s kódem pod kontrolou útočníka“ (přeloženo). Modul child_process dělá totéž přímočařeji.

Oprava je jméno navíc

Záplatou je jediná položka v tom seznamu. Commit d53e1c4459 z 2. září 2026 nese zprávu „fix(GHSA-pq68-rvw4-xp4r): add child_process to DANGEROUS_BUILTINS“ a o den později vyšla verze 3.12.1. Rozdíl mezi oběma soubory je vidět i bez čtení kódu: ve verzi 3.12.0 se řetězec child_process v lib/builtin.js vyskytuje jednou, a to v komentáři o něčem jiném, ve verzi 3.12.1 čtyřikrát.

Poznámky k vydání u toho přiznávají změnu chování. Holé builtin: ['child_process'] už modul nedá nikomu, takže kdo ho pro svůj případ potřebuje, musí sandboxu podstrčit vlastní náhradu přes require.mock. Číslo CVE k oznámení přidělila 18. září společnost VulnCheck; její záznam vede jako dotčené všechny verze nižší než 3.12.1.

Databáze GitHubu u toho záznamu uvádí dvě data a je dobré je nesplést. Na stránce stojí 3. září, tedy den, kdy oznámení vydal sám projekt ve svém repozitáři. Rozhraní databáze u téhož záznamu vrací jako datum zveřejnění 7. říjen. Mezi oznámením projektu a záznamem v databázi je tedy měsíc.

Projekt, který jednou skončil

Vm2 je zvláštní případ. Poslední verze staré řady, 3.9.19 ze 16. května 2023, nese v registru npm dodnes varování: „Knihovna obsahuje kritické bezpečnostní problémy a neměla by se používat v produkci! Údržba projektu byla ukončena. Zvažte přechod na isolated-vm“ (přeloženo). Tím to tehdy skončilo.

Po dvou a půl letech vyšla 24. října 2025 verze 3.10.0 a od té doby přibylo dalších sedmnáct vydání, naposledy 3.12.2 z 8. září 2026. Varování o ukončené údržbě u nich není.

Čím se oživení projevilo, ukazuje samotná databáze oznámení. U balíčku vm2 v ní leží 78 platných záznamů a dalších třicet je označeno jako duplicitní. Dvanáct z těch platných pochází z let 2021 až 2023. Zbylých 66 nese datum z roku 2026 a 41 z nich je kritických. Jen v říjnu 2026 jich přibylo třicet, devatenáct kritických: patnáct prvního, čtrnáct pátého a jeden sedmého.

Kdo si bere kterou verzi

Balíček se pořád stahuje ve velkém. Mezi 28. zářím a 4. říjnem 2026 si ho podle npm někdo vzal 1 308 038krát. Rozpad podle verzí vede npm zvlášť a jeho součet je vyšší (1 679 642), takže se obě čísla sčítat nedají; podíly z něj ale ukazují, kam stažení míří.

Skoro třetina, 31,2 %, připadá na 3.9.19, tedy na poslední verzi před ukončením. Celá řada 3.9 a starší dělá dohromady 52,2 %. Na opravené verze, tedy 3.12.1 a novější, jde 22,3 %. Většina stažení si tak bere kód, do kterého tahle oprava nikdy nedorazí, protože vznikl v době, kdy žádný takový seznam v knihovně nebyl.

Projekt sám říká, že další úniky přijdou

Za férové stojí uznat, že vm2 nic nezastírá. Jeho README má celý oddíl o tom, proč je těsný sandbox uvnitř jednoho procesu Node.js tak těžký, a píše: „Navzdory našemu nejlepšímu úsilí výzkumníci a bezpečnostní odborníci průběžně objevují nové způsoby, jak ze sandboxu vm2 uniknout“ (přeloženo). Z toho projekt vyvozuje tři věci: další obcházení nejspíš přijdou, knihovna se musí držet aktuální a nesmí být jedinou obranou.

Rovnou tam nabízí i alternativy s tvrdší izolací: isolated-vm s odděleným izolátem V8, oddělený proces nebo worker, kontejnery a mikroviruální stroje typu Docker, gVisor či Firecracker a spouštění kódu u cloudového poskytovatele. U kódu z úplně neznámých zdrojů doporučuje sáhnout právě po nich.

Ten řádek v seznamu zakázaných modulů je pro tenhle druh knihovny výstižný. Obrana postavená na výčtu toho, co se zakazuje, stojí a padá s úplností toho výčtu, a tady stačilo jedno chybějící jméno.

Zdroje

Bezpečnost

CVE vm2 Node.js npm sandbox

← zpět na výpis