Полный доступ к облачной инфраструктуре дала злоумышленнику уязвимость в marimo - среде для работы с интерактивными блокнотами кода. Проход от открытия веб-соединения до входа по ключу на промежуточный сервер занял восемь секунд. Скрипты атакующий написал сам, без помощи больших языковых моделей, и не отреагировал на текстовую приманку, оставленную для ИИ-агентов.
Описание
Речь о CVE-2026-39987 - уязвимости удалённого выполнения кода. Она срабатывает до проверки подлинности пользователя. Затронуты все версии marimo вплоть до 0.20.4, исправление вышло в 0.23.0. Отдельный маршрут веб-сокета открывает интерактивную командную оболочку, но не требует ни пароля, ни ключа, тогда как остальные веб-сокеты того же приложения проверку проходят. Любой, кто может подключиться к этому адресу, получает оболочку с правами служебного пользователя marimo. Никакой нагрузки и кодирования не нужно - достаточно самого соединения.
Блокноты marimo часто разворачивают рядом с конвейерами машинного обучения: на машинах с графическими ускорителями, большими наборами данных и правами доступа к облачным аккаунтам Amazon Web Services, Google Cloud и сторонним поставщикам моделей. По данным Sysdig Threat Research Team, одно скомпрометированное развёртывание блокнота превращается в ключ ко всему облачному аккаунту жертвы.
Сначала злоумышленник проверил две пары облачных учётных данных. Первую он достал из переменных окружения и файлов на самом сервере, вторую - из внутреннего хранилища приложения, куда та попадала по запросу. Обе пары принадлежали разным пользователям. Между первой проверкой и первым видимым действием в терминале прошло почти 28 часов, поэтому сама кража осталась за пределами наблюдения. Затем атакующий почти четыре часа писал и отлаживал собственный набор скриптов. За это время он выполнил первую интерактивную команду, а первое обращение к облачному хранилищу секретов состоялось лишь спустя несколько часов. Разрыв показывает, чем он занимался: собирал инструмент под конкретную задачу.
Готовые скрипты он складывал во временный каталог в закодированном текстовом виде. Приём решает две задачи: избавляет от проблем с кавычками в многострочном коде и оставляет в истории команд одну короткую строку, за которой не видно содержимого. Один из сценариев обращался к хранилищу секретов Amazon: если нужный регион не отвечал, он перебирал ещё четыре по очереди. Другой забирал найденный закрытый ключ, сохранял его с ограниченными правами доступа и подключался этим ключом к промежуточному серверу. Третий поднимал обратное подключение к подконтрольной злоумышленнику виртуальной машине.
Когда набор заработал, повторные проходы стали занимать секунды. Свежее веб-соединение открывалось в 18:57:22, вход на промежуточный сервер зафиксирован в 18:57:30. Между этими событиями уместились и запрос ключа, и обращение к облачному хранилищу. Всё выполняла одна фоновая команда, запускающая самодостаточный сценарий на Python, а не агентская платформа.
Параллельно работал второй, независимый сценарий. Он пытался перечислить виртуальные машины в облаке, чтобы затем загрузить туда собственный открытый ключ и получить доступ в обход хранилища секретов. Все три попытки перечисления облако отклонило. Тогда скрипт всё равно отправил запрос на загрузку ключа, подставив вместо реального идентификатора машины заглушку - значение, которого у настоящей виртуальной машины быть не может. Запрос отклонили сразу в облаке. Это узнаваемая ошибка: обработку отказа в загрузке ключа автор предусмотрел, а пустой результат перечисления - нет. Такая последовательность служит поведенческим признаком автоматизации без проверки на пустой ответ.
Отдельного внимания заслуживает реакция на приманку. В контейнере оставили текстовую инструкцию, рассчитанную на ИИ-агента: файл предписывал любому, кто прочтёт его как команду, вернуть в своём выводе скрытую метку. Ранее изученные операторы на основе моделей попадались на это надёжно. Нынешний атакующий просматривал файл дважды и метку не вернул ни разу. Вместе с ручным темпом работы, постепенной отладкой и разными вариантами кавычек в командах это дало наиболее ясное свидетельство человеческой работы.
Инфраструктура тоже показательная. Адрес, с которого шли все сессии, и сервер для обратных подключений принадлежат одному и тому же облачному поставщику. Для злоумышленников с небольшим бюджетом это обычная практика: несколько машин у одного провайдера про запас. Совпадение адресов внутри одной сети даёт защитникам полезный признак для объединения разных эпизодов в одну кампанию.
Машинная скорость появилась раньше ИИ. Ещё в начале 2023 года группировка SCARLETEEL вынесла данные меньше чем за три минуты. Языковые модели снижают порог входа и упрощают достижение такой скорости, но не заменяют атакующего, который умеет писать инструменты с нуля. Обе категории работают по одним и тем же уязвимостям и приходят к одному результату.
Практические выводы для организаций сводятся к нескольким шагам. Нужно обновить marimo до версии 0.23.0 или более новой: уязвимость давно внесли в федеральный каталог эксплуатируемых уязвимостей США, срок устранения для госструктур истёк 7 мая 2026 года. Стоит закрыть доступ к терминальному веб-сокету проверкой подлинности на обратном прокси или отключить терминал совсем. Полезно проверить, где на машинах с блокнотами лежат облачные ключи, и ограничить права этих учётных данных: доступ к ключу промежуточного сервера им не нужен. Разумно запретить исходящие подключения из контейнеров блокнотов на все порты, кроме необходимых для работы. Отдельно стоит просмотреть временные каталоги на машинах с блокнотами: оставленный злоумышленником набор сценариев пригоден для повторного использования в новых сессиях.
Разница между ручным и машинным темпом стирается. Восемь секунд от веб-соединения до чужого сервера - та скорость, к которой стоит готовиться независимо от того, кто сидит за клавиатурой.