
Solución directa para la vulnerabilidad de inyección de comandos sin parchear en MCP STDIO (familia CVE-2026-30623)
Un parche de integración directa para la vulnerabilidad sin parchear de inyección de comandos en MCP STDIO (la familia CVE-2026-30623, divulgada por OX Security en abril de 2026 como "por diseño" -- no llegará ningún parche del SDK). Importa una línea, y cada servidor MCP stdio que lance tu aplicación Python verá su command/args/env validado antes de que el SO llegue a crear un proceso.
Si eres nuevo aquí, lee primero Alcance, luego Instalación y Primeros pasos te protegerán en menos de dos minutos.
Pre-1.0, en desarrollo activo.
check/launch/rules) están
implementados y cubiertos por una suite de pruebas automatizada que se ejecuta contra los
binarios reales instalados en la máquina de pruebas (python, node, npx) --
no mocks -- incluyendo un auténtico handshake MCP de extremo a extremo a través de un
fixture real de servidor lanzado, y una prueba genuina a nivel de subproceso de launch.Dentro del alcance: validar el lanzamiento de un servidor MCP stdio (command + args + env) antes de que llegue a la capa de creación de procesos del SO, para cerrar concretamente la vía de inyección de comandos/argumentos descrita en SECURITY.md.
Explícitamente fuera del alcance: escanear las herramientas declaradas de un servidor en busca de capacidades riesgosas (eso es un problema distinto -- consulta AgentGuard), el sandboxing del proceso lanzado y los transportes MCP que no son stdio (SSE/HTTP).
git clone <this-repo>
cd mcpshield
pip install -e . # core CLI: click + rich only
pip install -e ".[mcp]" # if you also want the Python autopatch (needs the `mcp` SDK)
Comprueba que funciona:
mcpshield --version
mcpshield --help
Si tu aplicación está escrita en Python y construye StdioServerParameters /
llama a mcp.client.stdio.stdio_client por sí misma, añade un import al
principio de tu punto de entrada -- antes de que cualquier otra cosa importe mcp.client.stdio:
import mcpshield.autopatch # side-effect import; must come first
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
# ... use stdio_client exactly as before -- it's now validated
Un lanzamiento inseguro ahora lanza mcpshield.core.errors.UnsafeConfigurationError
(una subclase de ValueError) en lugar de llegar a crear un proceso.
Audita un archivo de configuración de estilo mcpServers sin ejecutar nada:
mcpshield check claude_desktop_config.json
+---------------------------------------------------------------+
| Server | Status | Command | Detail |
|------------------+---------+---------+------------------------|
| filesystem | OK | npx | - |
| evil-server | BLOCKED | npx | Argument '...' contains|
| | | | shell metacharacter |
+---------------------------------------------------------------+
1 ok, 0 warned, 1 blocked
Sale con código distinto de cero si algo está BLOCKED (añade --strict para que también falle
con WARN) -- puedes integrarlo directamente en tu CI.
Para un cliente MCP (Node, Java, Rust, ...) que no pueda usar el parche
automático de Python, apunta su configuración a mcpshield en lugar del comando real:
{
"command": "mcpshield",
"args": ["launch", "--", "npx", "-y", "some-mcp-server"]
}
launch valida y después ejecuta el comando real con el mismo stdio
que tu cliente MCP espera (paso transparente) -- o se niega con un
error claro si el lanzamiento no es seguro.
| Comprobación | Binario nativo (p. ej. python.exe) | Interpretable por shell (script .cmd/.bat/shebang) |
|---|---|---|
Metacaracteres de shell (&, |, ;, comilla invertida, $(...), ...) en un argumento | Permitido | Bloqueado |
| Byte NUL / salto de línea en un argumento | Bloqueado | Bloqueado |
El comando se resuelve mediante path traversal relativo (..) | Bloqueado | Bloqueado |
| El comando no se resuelve a un archivo real | Bloqueado | Bloqueado |
LD_PRELOAD / NODE_OPTIONS / etc. en env | Eliminado (advertencia) | Eliminado (advertencia) |
PYTHONPATH en env | Marcado (advertencia), no eliminado | Marcado (advertencia), no eliminado |
Los binarios nativos reciben comprobaciones de argumentos más laxas porque hacen exec directamente --
no hay shell que vuelva a interpretar la lista de argumentos. Los comandos interpretables por shell
(lo más habitual: npx.cmd/npx.bat en Windows) reciben comprobaciones estrictas
porque ese es exactamente el mecanismo que explota la CVE subyacente.
Ambas son opciones deliberadas de aceptación por valor -- nunca una bandera genérica de "desactivar comprobaciones":
allow_raw_args=["--some-value-with-a-pipe"] (librería) exime valores de argumento
específicos que hayas revisado y en los que confíes.allow_env=["SOME_VAR"] permite que una variable de entorno normalmente eliminada
pase sin modificaciones.| Comando | Qué hace |
|---|---|
mcpshield check <config> [--format table|json] [--strict] | Auditoría estática de una configuración mcpServers. Nunca ejecuta nada. Sale con código distinto de cero ante cualquier BLOCKED (o también WARN, con --strict). |
mcpshield launch -- <command> [args...] | Valida y después ejecuta el comando real con pass-through de stdio. |
mcpshield rules list | Muestra la lista negra activa de metacaracteres de shell, las listas de variables de entorno y los binarios lanzadores seguros conocidos. |
git clone.mcp.client.stdio.stdio_client tal como se busca
en el momento del parcheo. El código que ya tenga su propia referencia (mediante
from mcp.client.stdio import stdio_client ejecutado antes de
import mcpshield.autopatch) lo omitirá -- importa mcpshield.autopatch
primero, siempre.check resuelve los comandos usando la máquina en la que se ejecuta. Una configuración que
se resolvería de forma diferente en la máquina donde realmente se despliega (un PATH
distinto, herramientas instaladas diferentes) puede dar resultados distintos allí.mcpshield/
autopatch.py # one-line-import fix for Python MCP hosts
core/
validate.py # the validation engine (command/args/env checks)
rules.py # blocklist/allowlist data
errors.py # UnsafeConfigurationError
cli/
main.py
commands/ (check.py, launch.py, rules.py)
tests/
fixtures/ # real benign MCP server + sample/malicious configs
pip install -e ".[dev,mcp]"
pytest
La suite de pruebas valida contra los binarios reales python/node/npx
instalados en la máquina donde se ejecuta (resueltos de la misma forma en que el motor
los resuelve), e incluye un auténtico handshake MCP de extremo a extremo
a través de un fixture real de servidor lanzado -- no mocks.