Resumen

Antes de Langflow 1.10.3, el transporte MCP stdio lanzaba cualquier command y args que un usuario introdujera en la configuración de un servidor MCP, sin lista de comandos permitidos y, antes de 1.10.3, envuelto en bash -c "exec {command} ...". Cualquier usuario capaz de acceder a los ajustes del servidor MCP (ruta: Configuración, MCP Servers, Añadir MCP Server; endpoint: POST/PATCH /api/v2/mcp/servers/{server_name}) o de construir un flujo con el componente MCP Tools podía añadir un servidor cuyo comando fuera un comando OS arbitrario (touch, rm -rf, una reverse shell, etc.). El comando se ejecuta en el host de Langflow como el usuario del proceso Langflow en cuanto Langflow intenta conectarse al servidor (al listar servidores, cargar herramientas o ejecutar el flujo), incluso cuando la interfaz reporta que el servidor stdio no pudo iniciarse.

Con la configuración por defecto LANGFLOW_AUTO_LOGIN=true, el endpoint GET /api/v1/auto_login entrega un token sin credenciales, por lo que en una instancia expuesta con configuración predeterminada esta vulnerabilidad es alcanzable sin cuenta de usuario. AUTO_LOGIN está documentado como un ajuste exclusivo para desarrollo; con él desactivado, cualquier usuario autenticado (no administrador) puede explotarla.

El problema fue corregido en dos etapas y está completamente resuelto en Langflow 1.10.3 (y 1.11.0 en adelante):

  • 1.9.0: la PR #12290 añadió una lista de comandos permitidos y validación de argumentos y variables de entorno al modelo REST (MCPServerConfig), bloqueando el vector de ataque por la ruta de configuración de servidores.
  • 1.10.3: la PR #14036 aplicó la misma política en el punto de ejecución (lfx.base.mcp.util), incluyendo configuraciones embebidas en flujos y tweaks, así como la frontera final antes del spawn del proceso, y eliminó el wrapper bash -c (el proceso ahora se ejecuta directamente con exec, sin shell).

Versiones afectadas

Paquete (PyPI)VulnerableParcheado
langflow>= 1.1.2, < 1.10.31.10.3
langflow-base>= 0.1.2, < 0.10.30.10.3
lfx< 1.10.31.10.3
ReleaseEstado
1.1.2 a 1.4.xEl componente MCP Stdio (añadido en #5148) ejecuta StdioServerParameters(command=..., args=...) desde el campo command del componente sin ninguna validación.
1.5.0 a 1.8.xSe añade la página de configuración de servidores MCP y la API /api/v2/mcp/servers (PR #8388). Las configuraciones stdio almacenadas se lanzan mediante bash -c "exec {command_str} ..." sin validación. El PoC descrito funciona tal cual.
1.9.0 a 1.10.2PR #12290: POST/PATCH /api/v2/mcp/servers rechaza comandos fuera de la lista permitida. El punto de ejecución sigue sin validación y sigue usando bash -c, por lo que configuraciones que no pasan por MCPServerConfig (por ejemplo, un valor del componente MCP Tools embebido en un flujo o pasado como tweak) aún pueden ejecutar comandos arbitrarios.
1.10.3 en adelantePR #14036: una política compartida (lfx.base.mcp.security.validate_mcp_stdio_config) se aplica en la API, en la ejecución de flujos y justo antes del spawn del proceso; no se usa shell. Corregido.

Detalles técnicos

El punto vulnerable (src/lfx/src/lfx/base/mcp/util.py, método MCPStdioClient._connect_to_server, antes de 1.10.3) era el siguiente:

python
server_params = StdioServerParameters(
    command="bash",
    args=["-c", f"exec {command_str} || echo 'Command failed with exit code $?' >&2"],
    env=env_data,
)

command_str se construye a partir del command y args proporcionados por el usuario. La única validación antes de 1.9.0 era _validate_node_installation, que únicamente comprueba si Node.js está instalado cuando el comando contiene npx. El SDK de MCP inicia el proceso con anyio.open_process, de modo que el comando se ejecuta antes de cualquier handshake MCP, razón por la cual se ejecuta incluso si la interfaz muestra un error de inicio.

Prueba de concepto (Langflow 1.5.0 a 1.8.x)

En la interfaz, en Añadir MCP Server, sección STDIO:

code
Nombre    - Test
Comando   - touch
Argumentos - /tmp/pwn

O mediante la API, usando un token obtenido de auto_login (configuración por defecto):

bash
TOKEN=$(curl -s http://127.0.0.1:7860/api/v1/auto_login | python3 -c 'import sys,json;print(json.load(sys.stdin)["access_token"])')

curl -s -X POST 'http://127.0.0.1:7860/api/v2/mcp/servers/testing' \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  --data-raw '{"command":"touch","args":["/tmp/pwned_langflow"]}'

El archivo /tmp/pwned_langflow se crea en el servidor. En 1.10.3 en adelante, la petición es rechazada con el mensaje: Command 'touch' is not allowed for security reasons. Allowed commands: bash, cmd, docker, node, npx, python, python3, uvx, y el mismo payload falla en el punto de ejecución (MCPStdioClient.connect_to_server("touch /tmp/pwned_langflow") lanza MCPStdioSecurityError y no se crea ningún archivo). Wrappers como bash -c "touch ...", sh -c ..., python3 -c ... y node -e ... también son rechazados.

Corrección aplicada

PR #12290 (1.9.0): validadores en MCPServerConfig: lista de comandos permitidos (node, python, python3, npx, uvx, docker, y cmd/sh/bash solo para envolver uno de los anteriores), comprobación de metacaracteres de shell y palabras clave peligrosas en argumentos, lista de variables de entorno bloqueadas (LD_PRELOAD, NODE_OPTIONS, PYTHONPATH, BASH_ENV, etc.) y comprobaciones de aislamiento Docker.

PR #14036 (1.10.3): mueve la política a lfx.base.mcp.security.validate_mcp_stdio_config y la aplica en todos los puntos de entrada (API, configuraciones embebidas en flujos y tweaks, el componente MCP Stdio obsoleto y justo antes del spawn). Además, lanza el proceso sin shell:

python
command_parts = shlex.split(command_str)
command, args = command_parts[0], command_parts[1:]
validate_mcp_stdio_config(command, args, env)   # aplicación final antes del spawn
server_params = StdioServerParameters(command=command, args=final_args, env=env_data)

El endurecimiento posterior en 1.11.0 (PR #13530) añade modos más estrictos opcionales para despliegues multi-tenant.

Mitigaciones si no es posible actualizar

  • Establecer LANGFLOW_AUTO_LOGIN=false y no exponer Langflow directamente a redes no confiables.
  • Conceder cuentas de Langflow únicamente a usuarios de confianza.

Recomendaciones de endurecimiento para 1.10.3 en adelante

La lista de comandos permitidos aún permite que npx y uvx ejecuten cualquier paquete por defecto, que es el modo habitual de distribución de servidores MCP. En despliegues multi-tenant, los operadores deben configurar adicionalmente:

  • LANGFLOW_MCP_SERVER_ALLOWED_PACKAGES: los paquetes exactos que npx y uvx pueden ejecutar.
  • LANGFLOW_MCP_SERVER_INTERPRETER_HARDENING=true y LANGFLOW_MCP_SERVER_DOCKER_HARDENING=true.
  • En 1.11.1 en adelante (PR #14150), restringir el código personalizado mediante LANGFLOW_ALLOW_CUSTOM_COMPONENTS=false, LANGFLOW_CUSTOM_COMPONENT_ADMIN_ONLY=true o LANGFLOW_BLOCK_CODE_INTERPRETER_COMPONENTS=true también limita los servidores MCP stdio a superusuarios.

Impacto

Ejecución remota de código (RCE) en el host de Langflow como el usuario del proceso Langflow (CWE-78). Cualquier instancia expuesta en una versión vulnerable se ve afectada, tanto si el atacante dispone de cuenta como si utiliza el AUTO_LOGIN por defecto. El investigador que reportó la vulnerabilidad encontró varios servidores Langflow accesibles desde internet que eran vulnerables.