Cybersec NewsНашите експерти

На един git push от това да притежаваш GitHub: какво всъщност означава CVE-2026-3854

И така. Със сигурност сте видели заглавията тази седмица. „Критична уязвимост в GitHub.“ „Един git push до RCE.“ „Милиони repo-та компрометирани.“ Това разбира се са обичайните фойерверки на cybersecurity пресата, само че в този случай пожарът е горе-долу пропорционален на фойерверките.

Премислям тази история от няколко дни, отчасти защото попада точно в зоната, в която стои ежедневната ми работа – Cyber Security и Code Review, Agentic платформи, но и отчасти защото начинът, по който този bug беше открит, според мен е по-голямата история от самия bug. Но ще стигнем и дотам.

Какво се случи, опитал съм се да го направя четимо, а не оформено като прес-съобщение, така че имайте търпение.

На 28 април 2026 г. Wiz Research публикуваха disclosure за CVE-2026-3854 – критична remote code execution уязвимост във вътрешната git инфраструктура на GitHub, засягаща github.com, GitHub Enterprise Cloud (във всичките му варианти, включително Data Residency и Enterprise Managed Users), както и GitHub Enterprise Server. CVSS 8.7. е открита от Sagi Tzadik и докладвана през bug bounty програмата на GitHub на 4 март. Следва Patch на github.com за по-малко от два часа от подаването на доклада и commit + deploy в GHES бранчовете до 10 март.

Механиката: всеки автентикиран потребител с push достъп до каквото и да е хранилище, включително прясно създадено, можеше да предизвика arbitrary command execution на GitHub сървър, обработващ неговия push, чрез “натъпкване” на специално конструирани options в една единствена git push команда. Крайния резултат върху github, code execution върху shared storage възли – тоест вашият push можеше да попадне на машина, на която също се съхраняват милиони чужди repo-та. Или иначе казано, пълно компрометаране на сървъра.

Forensic разследването на GitHub са показват, че няма exploitation от трети страни преди patch-а, и че няма достъп до клиентски данни. По-малко добрата новина обаче е, и причината да пиша това е, че когато Wiz направиха публичен проблема, около 88% от GitHub Enterprise Server инстанциите все още бяха на непачнати версии. Ако оперирате GHES, тези 88% вероятно включват и кутии, за които сте забравили, че въобще съществуват.

Какво всъщност е babeld – и защо този bug е толкова неудобен

Ако никога не сте се ровили в това как GitHub сервира git по мрежата, ето тридесетсекундната обиколка. Има парче вътрешна инфраструктура, наречено babeld. Това е proxy-то, което седи между git клиента (вие, на командния ред) и backend сървисите, които вършат истинската работа – repository storage, hooks, audit logging, access control. Всеки git fetch, всеки git clone, всеки git push минава първо през babeld. Това е входната врата към git.

Вътрешно сървисите на GitHub “не вярват” сляпо на каквото им подадете. Те си предават вътрешен metadata header между компонентите – наречен X-Stat. Това е semicolon-delimited блок и носи критичен за сигурността контекст, чрез който Rails средата обработва заявката, къде системата трябва да търси hooks, кой е автентикираният потребител. Обичайната купчинка от „нека верифицираме всичко на входната врата, така че downstream сървисите могат да са сигурни че оперират с проверен контекст.

Downstream сървисите третират X-Stat като евангелие. Защо? Защото е сетнат от babeld, който е вътрешен, което означава, че никой отвън не би трябвало да може да му влияе.

Точно това последно изречение е мястото, където всичко тръгва на криво.

Когато пуснете git push -o key=value, git протоколът праща тези -o push options към сървъра. Push options са допълнение и съществуват, за да позволят на CI системи, server-side hooks и подобни инструменти да предават малки парчета контекст с push-а. Напълно разумно. Проблемът е, че babeld взима тези контролирани от потребителя стрингове и ги залепва в X-Stat header-а буквално. Без escape. Без санитизация на semicolon символа – който е, ако си спомняте, същият символ, използван от X-Stat като разделител. Парсърът от своя страна надолу използва last-write-wins семантика: ако едно и също име на поле се появи два пъти, втората стойност печели.

Комбинирайте тези две неща и получавате header injection като по учебник. Потребителят контролира стринг, който влиза в delimited вътрешен header без санитизация, а консуматорът на този header третира инжектираните полетата като проверени, защото, доколкото може да прецени, babeld вече ги е сетнал.

Bug-ове с тази форма съществуват практически във всяка голяма вътрешна платформа – винаги има някакъв вътрешен протокол, в който доверени upstream сървиси залепват стрингове в delimited формат, а някъде надолу нещо ги обработва. Лошото в случая е, че babeld е бил толкова критичен толкова много години и никой извън GitHub не го е разглеждал или проверявал достатъчно усърдно, за да открие това.

Exploit chain-ът на човешки език

Tzadik премина от „мога да презапиша едно поле в X-Stat“ до „пускам мой двоичен код като git service потребител“ чрез навързване на три injected полета. Накратко:

Стъпка 1 – Излез от production sandbox-а. Ruby кодът на GitHub работи в production Rails среда по подразбиране с доста стегнати правила. С инжектиране на rails_env заявката се прехвърля в по-малко сигурна среда, и вижда пътища които нормално не са достъпни.

Стъпка 2 – Пренасочи откъде идват hooks-овете. Git сървърът на GitHub изпълнява pre-receive hooks по време на push, за да наложи политиките за опазване на съответния branch. Директорията, в която живеят тези hooks, нормално е фиксирана, заключена и доверена. Инжектиране на custom_hooks_dir казва на системата „не, гледай тук за hooks“ и я насочва към директория, върху която атакуващият има влияние.

Стъпка 3 – Спусни arbitrary code чрез path traversal. Последното поле, repo_pre_receive_hooks, пък се инжектира път, в стойността на който атакуващият насочва изпълнението към произволен двоичен код на сървъра. Pre-receive hook машинарията, вършейки си работата, изпълняваше този двоичен код като git service потребителя.

Три инжектирани разделителя. Един git push. Code execution на сървъра.

Как Wiz всъщност откриха това – и защо това е частта, която трябва да ви държи будни

Две неща се открояват в discovery историята, и второто, по мое мнение, е истинското заглавие.

Първо, babeld не е open source. Това е компилиран вътрешен GitHub двоичен код. Исторически, намирането на bug-ове с такава дълбочина в closed-source server изисква или внимателен ръчен reverse-engineering с месеци търпелива работа, или insider leak. Нито едното не scale-ва. Затова уязвимостите в код като babeld обикновено излизат или чрез fuzzing на протокола отвън, или защото някой отвътре го забелязва.

Wiz не направиха нито едното. Те използваха AI-augmented reverse engineering, конкретно tooling, изградено върху Model Context Protocol който прехвърля в IDA Pro – това, което хората сега наричат „IDA MCP“. Това им даде възможност да насочат LLM към компилирани двоични кодове, да го помолят да реконструира вътрешни протоколи и trust boundaries, и да проследи къде user input пресича тези граници, със скорост, която просто не беше възможна за човешки екип преди година-две.

Сега, ето защо мисля, че това е по-голямата история, защото все още милиони ако не и милиарди редове код, писани и забравени остават са все още уезвими и въпроса е не дали и кога, а колко скорострелно ще бъдат открити от AI augmented debugging и кой стои зад него.

IDA MCP инструментариума е един от няколко подобни подхода, които се изграждат точно сега. Кривата на разходите за „намери сериозен bug в затворен двоичен код, който никога не си виждал“ пада. Не е на нула и няма да бъде на нула, но е забележимо под нивото от преди осемнадесет месеца. И продължава да пада.

Другото нещо, което си струва да отбележим: AI не намери нова категория bug тук. Намери много стара категория – header injection чрез delimiter mishandling – на място, на което хората не се бяха сетили да погледнат. Което е реалният pattern, който очаквам, че ще виждаме през следващите няколко години. Не екзотични нови bug класове. Познати bug класове, намирани по-бързо, на повече места, от по-малки екипи.

Но нека се върнем обратно към конкретния проблем и какво трябва да направите, ако сте на GHES. Проверете първо с коя версията сте, сигурните версии, които ви интересуват, са 3.14.24, 3.15.19, 3.16.15, 3.17.12, 3.18.6 и 3.19.3. GitHub също имат последващи releases (3.14.25, 3.15.20, 3.16.16, 3.17.13, 3.18.8, 3.19.4, 3.20.0 и нагоре), които включват този и други fix-ове. Каквото и да е по-старо от патчнатата версия на вашия branch, може да го считате за компрометирано. (въпреки че вероятно не е)

Сега, нещо, за което искам да съм честен: exploit-ът изисква push достъп до някое repo на target инстанцията. На типичен GHES deployment тази летва е толкова ниска, че е почти декоративна. Това са всички с разработчици. Това са контракторите. Това е онзи един външен фрийленсър, на когото сте дали write до едно repo преди три години сте го забравили. Това е всеки service account, чийто token е бил тихомълком разширен отвъд read-only, защото CI се е счупил и най-бързият fix е бил „дай му write“.

Одитирайте кой има push достъп до хранилищата на GHES. ДА, всичките.

Извадете GHES git server log-овете за exposure прозореца и потърсете git push -o активност от акаунти, от които не очаквате да използват push options, особено с option стрингове, съдържащи semicolons или странни символи.

Подновете всички secrets, signing keys, deploy keys или webhook secrets, които са лежали на GHES сървърите по време на exposure прозореца.

Стегнете blast radius-а за следващия път. GHES стои в много архитектури с прекалено широк достъп към продукционни CI, secret stores и artifact регистри. Третирайте го като high-value asset, какъвто е.

Ако сте само на github.com и не оперирате GHES, оперативната ви работа е горе-долу свършена – GitHub патчнаха за два часа, forensic заключението е успокояващо, а и без друго не сте можели да направите много в момента. Това, което все пак си струва да се направи, е да прегледате дали GitHub access tokens, OAuth apps и CI интеграциите имат повече привилегии, отколкото им трябва. Защото blast radius-ът от следващия github.com bug – а ще има следващ – ще се определя от това до какво вашите tokens имат право да докосват.

Повечето англоезични заглавия третират CVE-2026-3854 като US-сентрик: патчнете GHES, подновете tokens-ите… Всичко това е полезно, но не е цялата история,за тези които оперира в EU. От гледна точка на Брюксел този инцидент удря в поне четири регулаторни режима, които са влезли в сила или са се изострили през последните 24 месеца. Релевантният въпрос не е просто „бяхме ли експлоатирани?“ – той е „можем ли да демонстрираме на регулатор, че сме забелязали, реагирали и докладвали в срок?“

Сроковете за транспониране минаха, националните надзорни органи са активни и ясно дават да се разбере, че търпението им е свършило. Под NIS2 трябва да се докладват значими инциденти в рамките на 24 до 72 часа и финален доклад в рамките на месец. Релевантният въпрос за CVE-2026-3854 не е дали сте били експлоатирани, а дали можете да покажете, че сте оценили “проблема” и/или сте изключили възможността за експлоатиране с доказателства.

Но, нека се върнем отново стъпка назад от спецификите за момент. Формата на този инцидент е формата на модерния software-supply-chain риск в концентриран вид.

Все още има хиляди организации, чийто security model имплицитно приема, че „GitHub няма да го пробият“, и които на практика нямат готов отговор на „OK, но ако го пробият?“

Бъдете нащрек.

Покажи още
Back to top button