
Pacchetto di difesa in profondità per server MCP stdio: wrapper guardExec/guardSpawn sostitutivi, CLI di audit AST, server MCP di riferimento. Risolve la vulnerabilità di classe stdio-RCE che ha colpito 200k server (Ox-Security) (LiteLLM CVE-2025-69256). MIT, TypeScript, Node >= 20.
<!-- studiomeyer-mcp-stack-banner:start -->
> **Parte dello [StudioMeyer MCP Stack](https://studiomeyer.io)** — Realizzato a Maiorca 🌴 · ⭐ se lo usi
<!-- 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 -->Bundle di difesa in profondità per i server MCP stdio. Avvolge `child_process.exec/spawn`
con allowlist + sandbox + rilevamento di replay, più una CLI di audit AST (`mcp-shellguard-audit`)
che analizza i sorgenti dei server MCP alla ricerca di chiamate shell non sanificate. Chiude la classe
di vulnerabilità MCP stdio-RCE di Ox-Security (200k server vulnerabili, divulgazione di maggio 2026).
- **MCP spec**: 2025-06-18
- **SDK**: `@modelcontextprotocol/sdk` ^1.29.0
- **Node**: >= 20
- **License**: MIT
- **Author**: Matthias Meyer (StudioMeyer)
## Install
```bash
npm install mcp-stdio-shellguard
```
Oppure esegui direttamente la CLI di audit senza installarla:
```bash
npx -y -p mcp-stdio-shellguard mcp-shellguard-audit scan ./src
```
## Cosa ti offre
Tre livelli, attivabili singolarmente:
1. **API della libreria** — `guardExec` / `guardSpawn` pronti all'uso, che chiami dal tuo
server MCP. Allowlist con default-deny, profili sandbox, finestra di replay.
2. **CLI di audit** — `mcp-shellguard-audit scan <path>` percorre l'AST e segnala
12 anti-pattern da LOW (`no timeout`) a CRITICAL (`exec(\`...${userInput}...\`)`).
3. **Server MCP di riferimento** — `mcp-stdio-shellguard-demo` espone 8 strumenti
così che MCP Inspector / Claude Desktop possano pilotare direttamente il bundle.
## Strumenti (server di riferimento)
| Strumento | Tipo | Scopo |
|------|------|---------|
| `guard_exec` | distruttivo | `child_process.exec` protetto. Impone il vettore args[], allowlist + sandbox + replay. Restituisce `stdout`, `stderr`, `exitCode`, `canonicalHash`, `isReplay`, `trustTier`. |
| `guard_spawn` | distruttivo | `child_process.spawn` protetto. Restituisce hash SHA-256 di stdout/stderr invece dei corpi completi. Rifiuta categoricamente `shell:true`. |
| `register_allowlist` | mutante | Registra un nome di strumento con eseguibile + regex degli argomenti. Senza registrazione si applica il default-deny. |
| `audit_source` | sola lettura | Analizza un percorso TS/JS alla ricerca di anti-pattern di shell-injection. Restituisce `AuditFinding[]` + riepilogo. |
| `audit_report` | sola lettura | Formatta un risultato di audit come markdown / json / SARIF 2.1.0. |
| `replay_check` | sola lettura | Calcola l'hash canonico SHA-256 per un'invocazione e segnala se è già nella finestra di replay. |
| `sandbox_status` | sola lettura | Segnala il profilo sandbox attivo + i limiti concreti + il flag cgroup-v2 attivo. |
| `trust_tier` | sola lettura | Deriva il livello LOW/MEDIUM/HIGH/CRITICAL per uno strumento registrato, più suggerimenti di miglioramento. |
## Profili sandbox
| Profilo | Timeout | Stdout max | Stderr max | Budget FD | cgroup-v2 |
|---------|---------|-----------|-----------|-----------|-----------|
| `strict` | 5 s | 1 MB | 256 KB | 32 | sì (cpu/memory) |
| `standard` (predefinito) | 30 s | 10 MB | 1 MB | 256 | sì |
| `permissive` | 5 min | 100 MB | 10 MB | 1024 | no |
Il chiamante può restringere tramite `timeoutMs` / `fdBudget` per singola chiamata. Il chiamante non può ampliare
oltre il profilo.
## Livelli di fiducia
| Livello | Condizione |
|------|-----------|
| LOW | strumento non registrato (default-deny) |
| MEDIUM | registrato ma `argsPatterns` vuoto (qualsiasi argomento consentito) |
| HIGH | `argsPatterns` impostato ma sandbox o tracker di replay inattivo |
| CRITICAL | argsPatterns + sandbox + replay tutti attivi |
Passa da LOW → CRITICAL registrando lo strumento + impostando argsPatterns + eseguendo
tramite `guardExec`/`guardSpawn` (che attivano sempre sandbox + replay).
## Avvio rapido della libreria
```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
```
Codici di uscita:
- `0` pulito (nessun rilevamento al livello minimo o superiore)
- `1` rilevamenti presenti
- `2` errori di parsing / IO
Gli `ignoreGlobs` personalizzati passati a `scanPath` o allo strumento MCP `audit_source` accettano al massimo 128 stringhe. Ogni stringa è limitata a 1024 unità di codice UTF-16 e 16 caratteri di raggruppamento di apertura non escapati (`(`, `{`, `[`). Input che superano questi limiti generano un errore controllato prima del matching.
## Libreria di anti-pattern (12 regole)
| ID | Gravità | Si attiva su |
|----|----------|-------------|
| `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 senza `maxBuffer` |
| `missing_timeout` | LOW | exec/spawn senza `timeout` |
Lo scanner risolve i binding *rinominati* di `child_process` prima del matching, quindi le forme pericolose riportate sotto vengono rilevate anche quando la chiamata passa attraverso un alias anziché un `child_process.exec` letterale:
- `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(...)`
Le varianti sincrone (`spawnSync`, `execFileSync`) condividono le rispettive regole asincrone, e `shell_true_option` si attiva anche su una shell stringa (`{ shell: "/bin/sh" }`) o su un valore di shell dinamico — non solo sul letterale `{ shell: true }`. Un `promisify` di una funzione non-child_process, un destructuring da un altro modulo e `{ shell: false }` restano puliti (nessun falso positivo).
## Pragma
- `// shellguard:ignore-next-line` — sopprime un rilevamento
- `// shellguard:ignore-file` — sopprime l'intero file (raro; preferire per riga)
## Perché esiste
Ox-Security ha divulgato (2026-05) che oltre 200k server MCP stdio avvolgono `child_process.exec` con template literal che trasportano input utente direttamente dagli argomenti degli strumenti LLM. LiteLLM v1.83.6 è stato l'esempio canonico (CVE corretto nella 1.83.7). Questo bundle è la controparte di sicurezza difensiva: una guardia + scanner drop-in che chiude questa classe di vulnerabilità. Ispirato ai livelli `seccomp` di AWS Linux + sandbox di Chromium.
## Vedi anche
- `HOOK_RECIPES.md` — ricette di hook per Claude Code che bloccano automaticamente le chiamate pericolose agli strumenti
- `CHANGELOG.md` — cronologia delle release
- Audit MCP di Ox-Security: <https://venturebeat.com/security/200000-mcp-stdio-servers/>
- CVE-2026-XXXX di LiteLLM: <https://github.com/BerriAI/litellm/security/advisories>
## Licenza
MIT — Copyright (c) 2026 Matthias Meyer (StudioMeyer)