Комплексная защита для MCP stdio серверов: готовые обёртки guardExec/guardSpawn, CLI для аудита AST, эталонный MCP сервер. Закрывает класс уязвимостей stdio-RCE в 200k серверах от Ox-Security (LiteLLM CVE-2025-69256). MIT, TypeScript, Node >= 20.
<!-- studiomeyer-mcp-stack-banner:start -->
> **Часть [StudioMeyer MCP Stack](https://studiomeyer.io)** — Создано на Майорке 🌴 · ⭐ если вы это используете
<!-- studiomeyer-mcp-stack-banner:end -->
# mcp-stdio-shellguard
<!-- badges -->
[](https://www.npmjs.com/package/mcp-stdio-shellguard)
[](https://www.npmjs.com/package/mcp-stdio-shellguard)



<!-- /badges -->Комплекс многоуровневой защиты для MCP stdio-серверов. Оборачивает `child_process.exec/spawn`
с помощью allowlist + sandbox + обнаружения повторов, а также включает CLI-аудит на основе AST (`mcp-shellguard-audit`),
который сканирует исходники MCP-серверов на наличие несанитизированных вызовов оболочки. Закрывает класс уязвимостей
MCP stdio-RCE, описанный Ox-Security (200 тыс. уязвимых серверов, раскрытие в мае 2026 г.).
- **Спецификация MCP**: 2025-06-18
- **SDK**: `@modelcontextprotocol/sdk` ^1.29.0
- **Node**: >= 20
- **Лицензия**: MIT
- **Автор**: Matthias Meyer (StudioMeyer)
## Установка
```bash
npm install mcp-stdio-shellguard
```
Или запустите CLI аудита напрямую без установки:
```bash
npx -y -p mcp-stdio-shellguard mcp-shellguard-audit scan ./src
```
## Что это даёт
Три уровня, подключаемые по частям:
1. **Library API** — готовые к использованию `guardExec` / `guardSpawn`, которые вы вызываете из
собственного MCP-сервера. Allowlist с запретом по умолчанию, профили песочницы, окно повтора.
2. **Audit CLI** — `mcp-shellguard-audit scan <path>` обходит AST и сообщает
о 12 антипаттернах от LOW (`no timeout`) до CRITICAL (`exec(\`...${userInput}...\`)`).
3. **Reference MCP server** — `mcp-stdio-shellguard-demo` предоставляет 8 инструментов,
чтобы MCP Inspector / Claude Desktop могли напрямую управлять набором.
## Инструменты (reference server)
| Инструмент | Тип | Назначение |
|------|------|---------|
| `guard_exec` | destructive | Защищённый `child_process.exec`. Принудительно использует вектор args[], allowlist + песочницу + повтор. Возвращает `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 | нет |
Вызывающая сторона может ужесточить через `timeoutMs` / `fdBudget` для каждого вызова. Вызывающая сторона не может расширить
за пределы профиля.
## Уровни доверия
| Уровень | Условие |
|------|-----------|
| LOW | инструмент не зарегистрирован (запрет по умолчанию) |
| MEDIUM | зарегистрирован, но `argsPatterns` пуст (разрешены любые аргументы) |
| HIGH | `argsPatterns` задан, но песочница или трекер повторов неактивны |
| CRITICAL | argsPatterns + песочница + повтор все активны |
Повышение LOW → CRITICAL достигается регистрацией инструмента + заданием argsPatterns + запуском
через `guardExec`/`guardSpawn` (которые всегда активируют песочницу + повтор).
## Быстрый старт с библиотекой
```ts
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
```
## Audit CLI
```bash
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` — ошибки разбора / ввода-вывода
Пользовательские `ignoreGlobs`, передаваемые в `scanPath` или в MCP-инструмент `audit_source`, принимают не более 128 строк. Каждая строка ограничена 1024 кодовыми единицами UTF-16 и 16 неэкранированными открывающими группирующими символами (`(`, `{`, `[`). Входные данные, превышающие эти лимиты, вызывают контролируемую ошибку до начала сопоставления.
## Библиотека антипаттернов (12 правил)
| ID | Уровень серьёзности | Срабатывает на |
|----|----------|-------------|
| `exec_template_literal_with_input` | CRITICAL | `child_process.exec(\`ls ${x}\`)` |
| `exec_dynamic_string` | CRITICAL | `child_process.exec(cmd)` |
| `exec_sync_dynamic_string` | CRITICAL | `child_process.execSync(cmd)` |
| `eval_near_child_process` | CRITICAL | `eval(...)` |
| `function_constructor_near_child_process` | CRITICAL | `new Function(...)` |
| `spawn_dynamic_file_args` | HIGH | `spawn(bin, userArgs)` |
| `exec_file_dynamic` | HIGH | `execFile(bin, ...)` |
| `shell_true_option` | HIGH | `{ shell: true }` |
| `os_system_equivalent` | HIGH | `Deno.run` / `Bun.spawn` |
| `spawn_literal_dynamic_args` | MEDIUM | `spawn('git', userArgs)` |
| `unbounded_buffer` | LOW | exec без `maxBuffer` |
| `missing_timeout` | LOW | 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-05), что более 200 тыс. MCP stdio-серверов оборачивают
`child_process.exec` в шаблонные литералы, несущие пользовательский ввод напрямую из
аргументов инструментов LLM. LiteLLM v1.83.6 был каноническим примером (CVE исправлена в 1.83.7).
Этот пакет — защитный аналог: готовый к использованию guard + сканер,
закрывающий этот класс уязвимостей. Вдохновлён уровнями `seccomp` в AWS Linux и песочницы Chromium.
## См. также
- `HOOK_RECIPES.md` — рецепты хуков Claude Code, автоматически блокирующих опасные вызовы инструментов
- `CHANGELOG.md` — история релизов
- Аудит MCP от Ox-Security: <https://venturebeat.com/security/200000-mcp-stdio-servers/>
- LiteLLM CVE-2026-XXXX: <https://github.com/BerriAI/litellm/security/advisories>
## Лицензия
MIT — Copyright (c) 2026 Matthias Meyer (StudioMeyer)