Paquete de defensa en profundidad para servidores MCP stdio: wrappers guardExec/guardSpawn de sustitución directa, CLI de auditoría AST, servidor MCP de referencia. Cierra la clase stdio-RCE de los 200 000 servidores de Ox-Security (LiteLLM CVE-2025-69256). MIT, TypeScript, Node >= 20.
<!-- studiomeyer-mcp-stack-banner:start -->
> **Parte del [StudioMeyer MCP Stack](https://studiomeyer.io)** — Creado en Mallorca 🌴 · ⭐ si lo usas
<!-- 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 -->Paquete de defensa en profundidad para servidores MCP stdio. Envuelve `child_process.exec/spawn`
con lista de permitidos + sandbox + detección de replay, además de una CLI de auditoría AST (`mcp-shellguard-audit`)
que escanea el código fuente de servidores MCP en busca de llamadas a shell sin sanear. Cierra la clase de RCE
por stdio en MCP de Ox-Security (200k servidores vulnerables, divulgación de mayo de 2026).
- **Especificación MCP**: 2025-06-18
- **SDK**: `@modelcontextprotocol/sdk` ^1.29.0
- **Node**: >= 20
- **Licencia**: MIT
- **Autor**: Matthias Meyer (StudioMeyer)
## Instalación
```bash
npm install mcp-stdio-shellguard
```
O ejecute la CLI de auditoría directamente sin instalarlo:
```bash
npx -y -p mcp-stdio-shellguard mcp-shellguard-audit scan ./src
```
## Qué te ofrece
Tres capas, opcionales por partes:
1. **API de biblioteca** — `guardExec` / `guardSpawn` listos para usar que llamas desde tu
propio servidor MCP. Lista de permitidos con denegación por defecto, perfiles de sandbox, ventana de replay.
2. **CLI de auditoría** — `mcp-shellguard-audit scan <path>` recorre el AST, informa
12 anti-patrones desde LOW (`no timeout`) hasta CRITICAL (`exec(\`...${userInput}...\`)`).
3. **Servidor MCP de referencia** — `mcp-stdio-shellguard-demo` expone 8 herramientas
para que MCP Inspector / Claude Desktop puedan manejar el paquete directamente.
## Herramientas (servidor de referencia)
| Herramienta | Tipo | Propósito |
|------|------|---------|
| `guard_exec` | destructiva | `child_process.exec` defendido. Fuerza el vector args[], lista de permitidos + sandbox + replay. Devuelve `stdout`, `stderr`, `exitCode`, `canonicalHash`, `isReplay`, `trustTier`. |
| `guard_spawn` | destructiva | `child_process.spawn` defendido. Devuelve hashes SHA-256 de stdout/stderr en lugar de los cuerpos completos. Rechaza de forma estricta `shell:true`. |
| `register_allowlist` | mutante | Registra un nombre de herramienta con ejecutable + regex de args. Sin registro se aplica la denegación por defecto. |
| `audit_source` | solo lectura | Escanea una ruta TS/JS en busca de anti-patrones de inyección de shell. Devuelve `AuditFinding[]` + resumen. |
| `audit_report` | solo lectura | Formatea un resultado de auditoría como markdown / json / SARIF 2.1.0. |
| `replay_check` | solo lectura | Calcula el hash SHA-256 canónico de una invocación e informa si ya está en la ventana de replay. |
| `sandbox_status` | solo lectura | Informa el perfil de sandbox activo + límites concretos + indicador de cgroup-v2 activo. |
| `trust_tier` | solo lectura | Deriva el nivel LOW/MEDIUM/HIGH/CRITICAL para una herramienta registrada más sugerencias de mejora. |
## Perfiles de sandbox
| Perfil | Tiempo de espera | stdout máx. | stderr máx. | Presupuesto de FD | cgroup-v2 |
|---------|---------|-----------|-----------|-----------|-----------|
| `strict` | 5 s | 1 MB | 256 KB | 32 | sí (cpu/memory) |
| `standard` (predeterminado) | 30 s | 10 MB | 1 MB | 256 | sí |
| `permissive` | 5 min | 100 MB | 10 MB | 1024 | no |
El llamador puede restringir mediante `timeoutMs` / `fdBudget` por llamada. El llamador no puede ampliar
más allá del perfil.
## Niveles de confianza
| Nivel | Condición |
|------|-----------|
| LOW | herramienta no registrada (denegación por defecto) |
| MEDIUM | registrada pero `argsPatterns` vacío (se permite cualquier args) |
| HIGH | `argsPatterns` establecido pero sandbox o rastreador de replay inactivos |
| CRITICAL | argsPatterns + sandbox + replay todos activos |
Eleva de LOW → CRITICAL registrando la herramienta + estableciendo argsPatterns + ejecutando
a través de `guardExec`/`guardSpawn` (que siempre activan sandbox + replay).
## Inicio rápido de la biblioteca
```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
```
## CLI de auditoría
```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
```
Códigos de salida:
- `0` limpio (sin hallazgos en o por encima del umbral)
- `1` hallazgos presentes
- `2` errores de análisis / E/S
Los `ignoreGlobs` personalizados pasados a `scanPath` o a la herramienta MCP `audit_source` aceptan
como máximo 128 cadenas. Cada cadena está limitada a 1024 unidades de código UTF-16 y 16
caracteres de apertura de agrupación sin escapar (`(`, `{`, `[`). Las entradas que superan estos
límites generan un error controlado antes de la coincidencia.
## Biblioteca de anti-patrones (12 reglas)
| ID | Severidad | Se activa con |
|----|----------|-------------|
| `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 sin `maxBuffer` |
| `missing_timeout` | LOW | exec/spawn sin `timeout` |
El escáner resuelve los enlaces de `child_process` *renombrados* antes de la coincidencia,
por lo que las formas peligrosas a continuación se detectan incluso cuando la llamada pasa por un
alias en lugar de un `child_process.exec` literal:
- `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(...)`
Las variantes síncronas (`spawnSync`, `execFileSync`) comparten sus reglas asíncronas,
y `shell_true_option` también se activa con un shell de cadena (`{ shell: "/bin/sh" }`)
o un valor de shell dinámico — no solo con el literal `{ shell: true }`. Un
`promisify` de una función que no es de child_process, una desestructuración de otro
módulo y `{ shell: false }` permanecen limpios (sin falsos positivos).
## Pragmas
- `// shellguard:ignore-next-line` — suprime un hallazgo
- `// shellguard:ignore-file` — suprime todo el archivo (raro; se prefiere por línea)
## Por qué existe esto
Ox-Security reveló (2026-05) que más de 200k servidores MCP stdio envuelven
`child_process.exec` con plantillas literales que llevan entrada de usuario directamente desde
los argumentos de herramientas del LLM. LiteLLM v1.83.6 fue el ejemplo canónico (CVE parcheado en 1.83.7).
Este paquete es la contraparte de seguridad defensiva: un guard + escáner listo para usar
que cierra esta clase de vulnerabilidad. Inspirado en los niveles de `seccomp` de AWS Linux + sandbox de Chromium.
## Véase también
- `HOOK_RECIPES.md` — recetas de hooks de Claude Code que bloquean automáticamente llamadas peligrosas a herramientas
- `CHANGELOG.md` — historial de versiones
- Auditoría MCP de Ox-Security: <https://venturebeat.com/security/200000-mcp-stdio-servers/>
- CVE-2026-XXXX de LiteLLM: <https://github.com/BerriAI/litellm/security/advisories>
## Licencia
MIT — Copyright (c) 2026 Matthias Meyer (StudioMeyer)