
Безопасное самодостаточное воспроизведение CVE-2026-77521 (выполнение команд через внедрение промпта в MaxKB)
Автономная, безопасная лабораторная работа, воспроизводящая
GHSA-f36j-f34j-h3rx
/ CVE-2026-77521: в MaxKB (открытая
корпоративная платформа ИИ-ассистента / RAG) любой ассистент с инструментом,
MCP-инструментом, навыком или подприложением получает автоматически внедряемый
shell-инструмент execute, который не защищён шлюзом одобрения человеком —
поэтому внедрение промпта (из чата или из загруженного документа) достигает
оболочки. Песочница должна была это сдерживать, но строка с shell=True
позволила метасимволам вырваться из неё.
| Рекомендация | GHSA-f36j-f34j-h3rx |
| CVE | CVE-2026-77521 |
| Проект | 1Panel-dev/MaxKB |
| Затронуто | < 2.10.5-lts |
| Исправлено | 2.10.5-lts (коммит 594f50f) — частично, см. ниже |
| CVSS | 10.0 CRITICAL (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H) |
| Слабость | CWE-78 (внедрение команд ОС) · CWE-250 (избыточные привилегии) · CWE-749 (открытый опасный метод) |
Это воспроизводит исправленную, публично раскрытую уязвимость в образовательных и защитных целях. Всё выполняется полностью локально и безвредно:
id, запись
файла-маркера, который PoC затем удаляет). Настоящие gosu/песочница/root не
задействованы — обёртка сброса привилегий заменена инертным маркером env,
чтобы демонстрация работала где угодно.Ассистент MaxKB с любой подключённой возможностью строится на deepagents с
SandboxShellBackend. deepagents автоматически внедряет shell-инструмент
execute (плюс read_file/write_file/…), а MaxKB не использует
excluded_tools, поэтому execute присутствует всегда. Конфигурация
interrupt_on — которая определяет, что требует одобрения человеком — имеет
вид {"write_file": False, "read_file": False, "edit_file": False}:
execute в ней отсутствует, поэтому он выполняется без одобрения. Любой
текст, способный управлять моделью (сообщение в чате или отравленный документ,
поглощаемый конвейером RAG), может тем самым заставить агента выполнять
команды оболочки. При установке из исходников SANDBOX по умолчанию отключён,
поэтому команды выполняются от имени пользователя приложения; в официальном
(root) контейнере обёртка песочницы была строкой с shell=True, поэтому
;/>/$() выполнялись вне gosu, от имени root.
interrupt_on в MaxKB внедрённый вызов execute выполняется без одобрения;
добавление "execute": True закрывает его шлюзом. → poc/01_missing_hitl_gate.py;+перенаправление
вырывается из префикса gosu в виде единой строки; повторное
экранирование в _build_sandbox_command() из 2.10.5-lts нейтрализует это.
→ poc/02_sandbox_escape.pyexecute с командой атакующего (и не
делает этого на чистом документе). → poc/03_real_llm.pyВыпущенный патч 2.10.5-lts (коммит 594f50f)
укрепляет только побег из песочницы — он добавляет _build_sandbox_command(), который
разбивает по операторам оболочки, заново экранирует каждый токен с помощью shlex.quote и оборачивает
каждую простую команду в префикс gosu. При проверке по
исходному коду v2.10.5-lts,
ядро агентства не изменено: interrupt_on по-прежнему не включает execute,
бэкенд по-прежнему SandboxShellBackend, а SANDBOX по-прежнему по умолчанию равен 0. Таким образом,
после исправления внедрённый через промпт execute всё ещё выполняется без одобрения человека —
внутренняя стена была усилена, а ворота остались открытыми. PoC 1 демонстрирует
рекомендуемое смягчение (шлюз для execute), которое поставщик не выпустил.
Без зависимостей для PoC 1/2 (Python 3.9+):
./run.sh # all three (PoC 3 skips without an endpoint)
python3 poc/01_missing_hitl_gate.py # missing approval gate
python3 poc/02_sandbox_escape.py # metacharacter sandbox escape
Показываете это?
DEMO.md— это сценарий демонстрации, аdemo.shпроводит по нему нажатием одной клавиши за раз.
Любая конечная точка, совместимая с OpenAI (self-hosted или размещённая open-model). Пример (Groq):
export OPENAI_BASE_URL=https://api.groq.com/openai/v1
export OPENAI_API_KEY=$GROQ_API_KEY # read from env only; never logged
MODEL="openai/gpt-oss-20b" python3 poc/03_real_llm.py
За прокси-сервером с TLS-инспекцией он повторяет попытку без проверки с предупреждением
(INSECURE_SSL=1 для принудительного включения). Он чисто пропускается, если endpoint не задан.
| Путь | Что это |
|---|---|
sandbox_shell.py | Безопасная модель построения команды execute() в MaxKB — уязвимая строка против исправленной _build_sandbox_command() |
agent_sim.py | Минимальная модель шлюза человеческого одобрения interrupt_on в deepagents |
payloads/poisoned-document.md | Отравленный злоумышленником документ базы знаний (косвенная инъекция) |
poc/01_missing_hitl_gate.py | Внедрённый execute выполняется без одобрения; шлюз блокирует его |
poc/02_sandbox_escape.py | Метасимволы выходят за пределы префикса gosu; парсер 2.10.5 содержит их |
poc/03_real_llm.py | Реальная модель вызывает execute из отравленного документа (чистый против отравленного) |
DEMO.md / demo.sh | Сценарий для докладчика и размеренный драйвер демонстрации |
assets/attack-flow.{svg,png} | Диаграмма потока атаки (обложка блога) |
assets/poc3-groq-sample.txt | Записанный вывод PoC 3 (резервный вариант для демонстрации) |