Přeskočit na obsah
Bezpečnost 4 min čtení

Opravu kritické díry v SGLangu zavřel správce spolu s dalšími návrhy téhož účtu

SGLang vyhodnocuje ladicí filtr funkcí eval() a přes ni jde v procesu scheduleru spustit cizí kód. Nahlásil to 14. října Jiapeng Li, o 48 minut později poslal někdo jiný opravu a téhož dne večer ji správce zavřel v jednom balíku s ostatními návrhy toho účtu, který zároveň zablokoval. Záznam CVE vyšel 16. října, volání eval() je v hlavní větvi dál.

Řady skříní výpočetního klastru v serverovém sále
Ladicí rozhraní inferenčního serveru běží ve stejném procesu, který rozvrhuje práci modelu. Foto: NASA Goddard Space Flight Center, Flickr (CC BY 2.0)

V ladicím nástroji serveru SGLang je jeden řádek, který zadaný text nevyhodnotí jako podmínku, ale jako program. Kdo se k němu dostane, spustí vlastní kód v procesu, který na serveru rozvrhuje práci modelu. Nahlásil to 14. října hlášení #44188 a 16. října k tomu vyšel záznam CVE-2026-111391. Volání, o které jde, je v hlavní větvi dál.

Prázdné builtins nejsou klec

SGLang umí při ladění vypisovat vnitřní tenzory a omezit výpis podmínkou, kterou obsluha zadá jako text. Tu podmínku vyhodnocuje funkce _evaluate_filter():

_FILTER_BUILTINS: dict[str, Any] = {"search": re.search, "match": re.match}

def _evaluate_filter(filter_expr: str, tags: dict[str, Any]) -> bool:
    namespace = _DefaultNoneDict(tags)
    namespace.update(_FILTER_BUILTINS)
    return bool(eval(filter_expr, {"__builtins__": {}}, namespace))

Zápis {"__builtins__": {}} má být ohrádka: vyprázdní seznam vestavěných funkcí, takže zadaný výraz nemá čím otevřít soubor ani načíst modul. Jenže o řádek výš se do jmenného prostoru vloží dvě funkce z modulu re, aby se ve filtru dalo hledat podle vzoru. A funkce v Pythonu si nese odkaz na modul, ve kterém vznikla, včetně jeho vestavěných funkcí. Prázdná ohrádka tedy platí jen pro výraz, který si přes ty dvě funkce nesáhne zpátky.

Autor hlášení to píše bez obalu: prázdné builtins nejsou bezpečnostní ohrádka, protože volatelné objekty si drží odkazy na své vlastní globální jmenné prostory. Citace je přeložená.

Filtr se nevyhodnocuje při zadání, ale až při výpočtu modelu. Zadaný kód se proto spustí ve scheduleru při nejbližším průchodu dopředu, tedy u prvního dalšího požadavku, který se k ladicímu bodu dostane. Server přitom odpoví normálně. Je to týž vzorec jako u Xinference, kde se jako kód spouštěla odpověď modelu; rozdíl je v tom, odkud ten text přijde.

Kdo se k tomu řádku dostane

Cesta /dumper/{method} se na rozhraní modelu zaregistruje jen tehdy, když se proměnná prostředí DUMPER_SERVER_PORT rovná přesně řetězci reuse. Popis v registru mluví obecněji – „když je DUMPER_SERVER_PORT nastavená“ –, což je širší než ta podmínka v kódu. Běžně spuštěný server tedy tu cestu nemá vůbec.

Když ji má, rozhoduje o přístupu úroveň ADMIN_OPTIONAL. Ze souboru auth.py plynou čtyři případy:

  • bez jakéhokoli klíče je cesta otevřená komukoli;
  • s nastaveným api_key stačí ten obyčejný uživatelský klíč;
  • s nastaveným admin_api_key je potřeba klíč správce;
  • když jsou nastavené oba, projde jedině klíč správce a obyčejný api_key se odmítne.

Záznam CVE označuje koncový bod za nechráněný. To platí pro první případ. Pro druhý, který v hlášení předvádí autor, platí něco jiného a horšího pro provozovatele: kdo komukoli vydá obyčejný klíč k modelu, vydal mu zároveň ladicí rozhraní. Poslední odrážka je přitom obrana, kterou SGLang má – nastavený admin_api_key ten koncový bod zamkne.

Oprava přišla za 48 minut a zůstala zavřená

Osmačtyřicet minut po hlášení poslal někdo třetí návrh #44205: tři soubory, 310 přidaných a 94 ubraných řádků, které eval() vymění za vyhodnocovač postavený nad syntaktickým stromem s povolovacím seznamem uzlů a zákazem přístupu k atributům se dvěma podtržítky. Kontrola stylu v CI nejprve spadla, autor ji odpoledne srovnal.

Ve 20.40 téhož dne návrh zavřel správce projektu, nesloučený, a důvod napsal rovnou do něj: zavírá ho spolu s ostatními otevřenými návrhy toho účtu a účet blokuje. Za dva dny z něj podle správce přišlo 37 návrhů, žádný sloučený – skoro shodné obměny téže změny, znovu poslané věci zavřené den předtím, zkušební návrhy a zásahy do chování bez testu, postupu k zopakování i čísel. „Každý návrh tady stojí správce čas na revizi a běh CI,“ napsal (přeloženo).

Ten důvod se opravy netýká, týká se účtu. Jiný návrh k tomu hlášení ale nikdo nepodal – je to jediný – a hlášení zůstává otevřené. V hlavní větvi stojí volání eval() s prázdnými builtins dál, na řádku 1320.

Záznam mají tři registry a hlídač nehlásí nic

Číslo přidělil VulnCheck a zařadil chybu pod CWE-95, tedy vyhodnocení cizích direktiv. Známku dal dvakrát a vyšla jinak: podle CVSS 3.1 je to 8,1 a vysoká závažnost, podle CVSS 4.0 je to 9,2 a kritická. Rozdíl dělá hlavně obtížnost útoku, kterou starší metodika hodnotí jako vysokou a novější jako nízkou s podmínkou souběhu. Slovo „kritická“ tedy pochází z novější stupnice téhož zadavatele.

Co se z registrů naopak nedozví žádný hlídač závislostí: databáze NVD vede záznam ve stavu Deferred, což znamená, že ho nikdo z NVD analyzovat nebude, a nemá u něj ani jeden strojově čitelný údaj o dotčeném produktu. Databáze GitHubu ho vede jako nekontrolovaný a seznam dotčených balíčků má u něj prázdný. Dependabot proto na SGLang kvůli téhle chybě nikoho neupozorní, i když záznam v jeho vlastní databázi je.

Které verze to mají

Zadavatel uvádí rozsah od 0.5.10 do 0.5.22 včetně. Sedí: ve značce v0.5.9 soubor dumper.py ani seznam _FILTER_BUILTINS, ani vyhodnocení s prázdnými builtins neobsahuje, kdežto ve v0.5.10, v0.5.11, v0.5.21 i v0.5.22 obsahuje obojí. Značka v0.5.10 nese datum 5. dubna 2026, takže ten řádek v kódu stojí přes půl roku.

Horní hranice je ale značka, pod kterou žádné vydání nevyšlo. Nejnovější zveřejněné vydání je v0.5.21 z 2. října; značku v0.5.22 někdo založil 15. října ve 23.39 na vydávací větvi se zprávou „Release v0.5.22“, vydání k ní ale v repozitáři není. Kdo tedy běží na poslední vydané verzi, má ten řádek v kódu stejně jako ti před ním.

Zdroje: hlášení #44188 a návrh opravy #44205 v repozitáři SGLangu, zdrojové soubory dumper.py, http_server.py a auth.py ve značce v0.5.22, hlášení VulnChecku a záznam GHSA-vfgj-p7f7-r3v8.

Diskuse

Zatím tu nikdo nediskutuje. Můžete být první.

Napsat příspěvek

Diskutovat můžete i bez účtu. S registrací se ale příspěvek zveřejní hned a nemusíte pokaždé vyplňovat jméno. Účet už máte? Přihlaste se.

Nezveřejňujeme ho, slouží jen redakci.

Podporuje zápis Texy: **tučně**, *kurzíva*, odrážky, odkazy.

Dál k tématu

  1. Bezpečnost

    Anthropic rozběhl model na patnácti televizních krabičkách

    Výzkumníci Anthropicu spustili model Gemma na patnácti levných krabičkách s Androidem. V odděleném pokusu zvládl GLM-5.2 připravit běh jiného modelu na všech osmi…

  2. Bezpečnost

    Continue CLI po trvalém schválení příkazu spustí bez ptaní i to, co stojí za středníkem

    Kdo v Continue CLI u příkazu shellu zvolí „Continue + don't ask again“, povolí natrvalo každý příkaz, který začíná stejným slovem, i s tím, co za ním stojí po středníku,…

  3. Bezpečnost

    Ruská operace Dark Clark je první, které OpenAI dala pátý stupeň dosahu ze šesti

    OpenAI 8. října zablokovala účty dvou vlivových operací, ruské Dark Clark a íránské Bogus Bylines. Ruskou jako první ze třiceti popsaných zařadila do páté kategorie…

  4. Bezpečnost

    Anthropic nabídl open source projektům hlášení zranitelností bez lidské kontroly

    Anthropic otevřel 8. října službu OSS Scanner, která vybraným open source projektům zdarma a opakovaně prohledává kód a jejich správcům posílá nálezy rovnou od modelu,…