
Документирует CVE-2026-52618 с PoC для инъекции команд ОС в @webfer/mcp-ansible-drupal через extraVars в executeDeployment, а также рекомендации по обнаружению и меры по смягчению последствий.
executeDeploymentspawn(cmd[0], cmd.slice(1), { shell: true }) повторно объединяет массив аргументов
в одну строку /bin/sh -c без экранирования, поэтому метасимвол оболочки в
значении extraVars, переданном MCP-инструменту executeDeployment, выполняется
на хосте, где запущен сервер.
Проблема устранена. Обновитесь до версии 2.0.3 или новее.
Аргументы MCP-инструментов подвержены влиянию атакующего. Они формируются LLM
из контента, который обрабатывает агент, — документов, веб-страниц, вывода
инструментов, — поэтому непрямая prompt-инъекция даёт атакующему контроль над
значениями, которые получает обработчик инструмента. Обработчик, передающий
любое из этих значений в оболочку, превращает это влияние в выполнение кода на
хосте, где запущен MCP-сервер. Это та же модель, что и в прецедентном случае
aws-mcp-server / CVE-2026-5058.
Следствие: утверждение «вызывающая сторона — доверенная LLM» не является смягчением. Аргументы инструментов — это недоверенный ввод.
src/helpers/runAnsible.ts в версии 2.0.0 собирал массив аргументов и затем
запускал его с включённой оболочкой:
const proc = spawn(ansibleCmd[0], ansibleCmd.slice(1), { shell: true });
При shell: true Node не выполняет ansibleCmd[0] с остальными элементами
в качестве argv. Он объединяет весь массив в одну строку и передаёт её
/bin/sh -c, не применяя к элементам кавычки или экранирование. Поэтому любой
элемент, содержащий ;, &&, |, обратные кавычки или $(), выходит за
пределы предполагаемой команды.
Достижимый путь — MCP-инструмент executeDeployment
(src/tools/executeDeployment.ts), который передаёт предоставленные вызывающей
стороной extraVars в массив в виде --extra-vars key=value. Значение
; touch /tmp/marker ; даёт:
/bin/sh -c "ansible-playbook -i inv.ini play.yml ... --extra-vars deploy_env=; touch /tmp/marker ; echo INJECTED"
Второй sink в той же версии подставлял projectRoot в
execSync('ansible-vault encrypt ' + vaultPath).
poc/driver.mjs вызывает runAnsible напрямую со специально
сформированным значением extraVars и проверяет наличие файла-маркера.
ansible-playbook устанавливать не требуется — внедрённая команда выполняется
в той же строке /bin/sh -c независимо от того, найден ли указанный бинарник.
npm pack @webfer/[email protected] && tar xf webfer-mcp-ansible-drupal-2.0.0.tgz
node poc/driver.mjs
Ожидаемый результат на уязвимой версии:
{"target":"@webfer/mcp-ansible-drupal 2.0.0","sink":"runAnsible -> spawn(cmd[0], cmd.slice(1), {shell:true})","vector":"executeDeployment extraVars value","marker":"/tmp/PWNED_ansible","created":true,"verdict":"CONFIRMED - command injection executed"}
Проверено 2026-06-01 в изолированном контейнере и повторно проверено 2026-06-13
с безвредным маркером touch. Запускайте только против инфраструктуры, которую
вам разрешено тестировать.
--extra-vars, попадающее в ansible-playbook, которое
содержит ;, &&, ||, |, обратную кавычку или $(. Легитимные
значения переменных Ansible практически никогда этого не содержат.sh -c, чья командная строка содержит ansible-playbook и
вторую команду после разделителя, — сигнал в дереве процессов (auditd,
eBPF, Falco, EDR), который не зависит от журналирования приложения.ansible-playbook,
git и ansible-vault; оболочка, интерпретатор или сетевой клиент — нет.executeDeployment
содержат метасимволы оболочки. Журналируйте аргументы инструментов —
большинство MCP-развёртываний этого не делают, и это единственное место,
где внедрённое значение видно на уровне приложения.MITRE ATT&CK: T1059.004 «Командный и скриптовый интерпретатор: Unix Shell».
Обновитесь до @webfer/mcp-ansible-drupal 2.0.3 или новее. Текущий
исходный код вызывает spawn(ansibleCmd[0], ansibleCmd.slice(1), { … }) без
опции shell, поэтому массив передаётся как argv, и метасимволы теряют
своё значение.
Общее правило для обработчиков MCP-инструментов, применённое в этом исправлении:
shell: true, когда уже доступен массив аргументов.
Форма массива существует именно для того, чтобы избежать оболочки.execFile/spawn с явным вектором аргументов.z.string() доказывает лишь,
что значение является строкой, и ничего не говорит о том, что в ней.
Используйте белый список там, где множество значений известно; отклоняйте
метасимволы оболочки там, где оно неизвестно.NIST SP 800-53r5 SI-10; OWASP ASVS v4 §5.3.8; меры M1 и M2 для CWE-78.
| Дата | Событие |
|---|
aws-mcp-server)Сопутствующие уведомления из того же цикла исследования: CVE-2026-52616, CVE-2026-52617.
MIT — см. LICENSE.
| CVE | CVE-2026-52618 |
| CWE | CWE-78 (Некорректная нейтрализация специальных элементов, используемых в команде ОС) |
| Пакет | @webfer/mcp-ansible-drupal (npm) |
| Затронутая версия | 2.0.0 |
| Исправлено в | 2.0.3 (опубликовано 2026-06-01) |
| CVSS v3.1 | AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H = 7.8 Высокий (транспорт stdio). AV:N → 9.8 Критический, если сервер обёрнут в сетевой транспорт. |
| Сообщил | s1ko (github.com/s1ko, [email protected]) |
| CVE присвоен | 2026-07-13, MITRE CNA-LR |
| 2026-06-01 | Уязвимость динамически проверена на версии 2.0.0 |
| 2026-06-01 | В npm опубликована версия 2.0.3 с удалённым shell: true |
| 2026-06-13 | Повторно проверена на втором хосте |
| 2026-07-13 | MITRE CNA-LR присваивает CVE-2026-52618, s1ko указан как первооткрыватель |
| 2026-08-22 | Опубликован этот отчёт |