Назад к обновлениям
New releaseAug 21, 2026

mcp-stdio-shellguard v0.1.2

Комплексная защита для MCP stdio серверов: готовые обёртки guardExec/guardSpawn, CLI для аудита AST, эталонный MCP сервер. Закрывает класс уязвимостей stdio-RCE в 200k серверах от Ox-Security (LiteLLM CVE-2025-69256). MIT, TypeScript, Node >= 20.

Поделиться

Часть StudioMeyer MCP Stack — Создано на Майорке 🌴 · ⭐ если используете

mcp-stdio-shellguard

npm version npm downloads License Last commit GitHub stars

Комплексная защита для MCP stdio серверов. Оборачивает `child_process.exec/spawn` с белым списком + песочницей + обнаружением повторов, а также CLI для аудита AST (`mcp-shellguard-audit`), который сканирует исходники MCP серверов на наличие несанитизированных shell-вызовов. Закрывает класс уязвимостей Ox-Security MCP stdio-RCE (200 тыс. уязвимых серверов, раскрытие май 2026).
  • Спецификация MCP: 2025-06-18
  • SDK: @modelcontextprotocol/sdk ^1.29.0
  • Node: >= 20
  • Лицензия: MIT
  • Автор: Matthias Meyer (StudioMeyer)

Установка

npm install mcp-stdio-shellguard

Или запустите CLI для аудита напрямую без установки:

npx -y -p mcp-stdio-shellguard mcp-shellguard-audit scan ./src

Что вы получаете

Три уровня, опционально включаемые по частям:

  1. Библиотечный API — заменяемые функции guardExec / guardSpawn, которые вы вызываете из своего MCP сервера. Белый список по умолчанию-запрет, профили песочницы, окно повторов.
  2. CLI аудитаmcp-shellguard-audit scan <path> обходит AST, сообщает о 12 антипаттернах от LOW (нет таймаута) до CRITICAL (exec(\...${userInput}...`)`).
  3. Эталонный MCP серверmcp-stdio-shellguard-demo предоставляет 8 инструментов, чтобы MCP Inspector / Claude Desktop могли напрямую использовать пакет.

Инструменты (эталонный сервер)

ИнструментТипНазначение
guard_execdestructiveЗащищённый child_process.exec. Принудительно использует вектор args[], белый список + песочница + повтор. Возвращает stdout, stderr, exitCode, canonicalHash, isReplay, trustTier.
guard_spawndestructiveЗащищённый child_process.spawn. Возвращает SHA-256 хеши stdout/stderr вместо полных тел. Жёстко отклоняет shell:true.
register_allowlistmutatingЗарегистрировать имя инструмента с исполняемым файлом + regex аргументов. Без регистрации применяется запрет по умолчанию.
audit_sourceread-onlyСканировать TS/JS путь на антипаттерны инъекций в shell. Возвращает AuditFinding[] + сводку.
audit_reportread-onlyФорматировать результат аудита как markdown / json / SARIF 2.1.0.
replay_checkread-onlyВычислить канонический SHA-256 хеш для вызова и сообщить, находится ли он уже в окне повторов.
sandbox_statusread-onlyСообщить активный профиль песочницы + конкретные лимиты + флаг активности cgroup-v2.
trust_tierread-onlyОпределить уровень LOW/MEDIUM/HIGH/CRITICAL для зарегистрированного инструмента плюс подсказки по улучшению.

Профили песочницы

ПрофильТаймаутМакс. stdoutМакс. stderrЛимит FDcgroup-v2
strict5 с1 МБ256 КБ32да (cpu/memory)
standard (по умолч.)30 с10 МБ1 МБ256да
permissive5 мин100 МБ10 МБ1024нет

Вызывающий может ужесточить через timeoutMs / fdBudget на каждый вызов. Вызывающий не может расширить за пределы профиля.

Уровни доверия

УровеньУсловие
LOWинструмент не зарегистрирован (запрет по умолчанию)
MEDIUMзарегистрирован, но argsPatterns пусты (любые аргументы разрешены)
HIGHargsPatterns заданы, но песочница или трекер повторов неактивны
CRITICALargsPatterns + песочница + повтор все активны

Поднимите LOW → CRITICAL, зарегистрировав инструмент + задав argsPatterns + запуская через guardExec/guardSpawn (которые всегда активируют песочницу и повтор).

Быстрый старт библиотеки

import {
  AllowlistRegistry,
  ReplayWindow,
  guardExec,
} from "mcp-stdio-shellguard";

const registry = new AllowlistRegistry();
const replay = new ReplayWindow();

registry.register({
  toolName: "git-log",
  executable: "/usr/bin/git",
  argsPatterns: ["^log$", "^--oneline$", "^-n$", "^\\d+$"],
  sandboxProfile: "strict",
});

const result = await guardExec(
  {
    toolName: "git-log",
    command: "/usr/bin/git",
    args: ["log", "--oneline", "-n", "10"],
  },
  { registry, replay },
);

console.log(result.stdout); // → commit lines
console.log(result.trustTier); // → "CRITICAL"
console.log(result.canonicalHash); // → 64-char SHA-256

CLI аудита

mcp-shellguard-audit scan ./src
mcp-shellguard-audit scan ./src --format sarif --output audit.sarif
mcp-shellguard-audit scan ./src --severity-floor HIGH    # CI gate

Коды выхода:

  • 0 чисто (нет результатов на уровне или выше порога)
  • 1 есть результаты
  • 2 ошибки парсинга/ввода-вывода

Библиотека антипаттернов (12 правил)

ИДСерьёзностьСрабатывает на
exec_template_literal_with_inputКРИТИЧЕСКИЙchild_process.exec(\ls ${x}`)`
exec_dynamic_stringКРИТИЧЕСКИЙchild_process.exec(cmd)
exec_sync_dynamic_stringКРИТИЧЕСКИЙchild_process.execSync(cmd)
eval_near_child_processКРИТИЧЕСКИЙeval(...)
function_constructor_near_child_processКРИТИЧЕСКИЙnew Function(...)
spawn_dynamic_file_argsВЫСОКИЙspawn(bin, userArgs)
exec_file_dynamicВЫСОКИЙexecFile(bin, ...)
shell_true_optionВЫСОКИЙ{ shell: true }
os_system_equivalentВЫСОКИЙDeno.run / Bun.spawn
spawn_literal_dynamic_argsСРЕДНИЙspawn('git', userArgs)
unbounded_bufferНИЗКИЙexec без maxBuffer
missing_timeoutНИЗКИЙexec/spawn без timeout

Сканер разрешает переименованные привязки child_process перед сопоставлением, поэтому опасные формы ниже обнаруживаются, даже если вызов идёт через псевдоним, а не буквальный child_process.exec:

  • const execAsync = promisify(exec); execAsync(...${x})
  • import cp from "node:child_process"; cp.exec(...${x})
  • const { exec: sh } = require("child_process"); sh(...${x})
  • import { exec as run } from "node:child_process"; run(...)

Синхронные варианты (spawnSync, execFileSync) используют те же правила, что и асинхронные, а shell_true_option также срабатывает на строковый shell ({ shell: "/bin/sh" }) или динамическое значение shell — не только на буквальный { shell: true }. promisify от не-child_process функции, деструктуризация из другого модуля и { shell: false } остаются чистыми (без ложных срабатываний).

Прагмы

  • // shellguard:ignore-next-line — подавить одно обнаружение
  • // shellguard:ignore-file — подавить весь файл (редко; предпочитайте построчное)

Почему это существует

Ox-Security раскрыла (май 2026), что 200k+ MCP stdio серверов оборачивают child_process.exec с шаблонными литералами, несущими пользовательский ввод прямо из аргументов инструментов LLM. LiteLLM v1.83.6 был каноническим примером (CVE исправлен в 1.83.7). Этот пакет является оборонительным аналогом безопасности: готовая защита + сканер, закрывающие этот класс уязвимостей. Вдохновлено seccomp из AWS Linux и уровнями песочницы Chromium.

Смотрите также

Лицензия

MIT — Copyright (c) 2026 Matthias Meyer (StudioMeyer)

Категории