
Комплексная защита для MCP stdio серверов: готовые обёртки guardExec/guardSpawn, CLI для аудита AST, эталонный MCP сервер. Закрывает класс уязвимостей stdio-RCE в 200k серверах от Ox-Security (LiteLLM CVE-2025-69256). MIT, TypeScript, Node >= 20.
Часть StudioMeyer MCP Stack — Создано на Майорке 🌴 · ⭐ если используете
@modelcontextprotocol/sdk ^1.29.0npm install mcp-stdio-shellguard
Или запустите CLI для аудита напрямую без установки:
npx -y -p mcp-stdio-shellguard mcp-shellguard-audit scan ./src
Три уровня, опционально включаемые по частям:
guardExec / guardSpawn, которые вы вызываете из своего MCP сервера. Белый список по умолчанию-запрет, профили песочницы, окно повторов.mcp-shellguard-audit scan <path> обходит AST, сообщает о 12 антипаттернах от LOW (нет таймаута) до CRITICAL (exec(\...${userInput}...`)`).mcp-stdio-shellguard-demo предоставляет 8 инструментов, чтобы MCP Inspector / Claude Desktop могли напрямую использовать пакет.Вызывающий может ужесточить через timeoutMs / fdBudget на каждый вызов. Вызывающий не может расширить за пределы профиля.
| Уровень | Условие |
|---|---|
| LOW | инструмент не зарегистрирован (запрет по умолчанию) |
| MEDIUM | зарегистрирован, но пусты (любые аргументы разрешены) |
Поднимите 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
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 ошибки парсинга/ввода-выводаСканер разрешает переименованные привязки 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.
HOOK_RECIPES.md — рецепты хуков Claude Code, автоматически блокирующих опасные вызовы инструментовCHANGELOG.md — история релизовMIT — Copyright (c) 2026 Matthias Meyer (StudioMeyer)
| Инструмент | Тип | Назначение |
|---|
guard_exec | destructive | Защищённый child_process.exec. Принудительно использует вектор args[], белый список + песочница + повтор. Возвращает stdout, stderr, exitCode, canonicalHash, isReplay, trustTier. |
guard_spawn | destructive | Защищённый child_process.spawn. Возвращает SHA-256 хеши stdout/stderr вместо полных тел. Жёстко отклоняет shell:true. |
register_allowlist | mutating | Зарегистрировать имя инструмента с исполняемым файлом + regex аргументов. Без регистрации применяется запрет по умолчанию. |
audit_source | read-only | Сканировать TS/JS путь на антипаттерны инъекций в shell. Возвращает AuditFinding[] + сводку. |
audit_report | read-only | Форматировать результат аудита как markdown / json / SARIF 2.1.0. |
replay_check | read-only | Вычислить канонический SHA-256 хеш для вызова и сообщить, находится ли он уже в окне повторов. |
sandbox_status | read-only | Сообщить активный профиль песочницы + конкретные лимиты + флаг активности cgroup-v2. |
trust_tier | read-only | Определить уровень LOW/MEDIUM/HIGH/CRITICAL для зарегистрированного инструмента плюс подсказки по улучшению. |
| Профиль | Таймаут | Макс. stdout | Макс. stderr | Лимит FD | cgroup-v2 |
|---|
strict | 5 с | 1 МБ | 256 КБ | 32 | да (cpu/memory) |
standard (по умолч.) | 30 с | 10 МБ | 1 МБ | 256 | да |
permissive | 5 мин | 100 МБ | 10 МБ | 1024 | нет |
argsPatterns| HIGH | argsPatterns заданы, но песочница или трекер повторов неактивны |
| CRITICAL | argsPatterns + песочница + повтор все активны |
| ИД | Серьёзность | Срабатывает на |
|---|
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 |