Contexto del incidente
El 19 de junio de 2026 los investigadores yzeirnials, LeftenantZero y Zwique publicaron en GitHub Security Advisories el reporte GHSA-qrpv-q767-xqq2 contra Langflow, el popular constructor visual low-code de agentes y workflows de IA basado en Python. El CNA de GitHub le asignó el identificador CVE-2026-55255 y lo clasificó con severidad Critical 9.9/10. Cuatro días después, el 23 de junio, salió la entrada en el NVD. Y dos semanas más tarde, el 7 de julio, CISA lo sumó a su catálogo KEV con date_added: 2026-07-07, due_date: 2026-07-10 y la columna de ransomware figura como Unknown, pero el flag E:A confirma que hay explotación activa en la naturaleza antes incluso de la fecha del parche.
El vector CVSS v3.1 que reporta el advisory es CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:L. En castellano: vector de red, complejidad baja, requiere únicamente un usuario válido de Langflow (privilegios Low), sin interacción del usuario, el alcance cambia porque el atacante ejecuta código con los permisos que tenga configurado el flow de la víctima, y el impacto es alto en confidencialidad e integridad (la disponibilidad queda en Low porque los flows de IA suelen estar limitados por rate limit del proveedor upstream). La categoría CWE es CWE-639 — Authorization Bypass Through User-Controlled Key, es decir un IDOR clásico.
El detalle técnico está en el helper get_flow_by_id_or_endpoint_name(), definido en src/backend/base/langflow/helpers/flow.py, líneas 399-414. La función tiene dos ramas: cuando se le pasa el UUID del flow usa session.get(Flow, flow_id) y consulta la base de datos sin filtrar por user_id. La otra rama, cuando se le pasa un endpoint_name legible (el slug), sí filtra por owner. El endpoint vulnerable es POST /api/v1/responses, definido en src/backend/base/langflow/api/v1/openai_responses.py:589, que hereda la ruta UUID-only sin chequeo de ownership. El resultado es que cualquier usuario autenticado puede enviar el UUID del flow de otro y Langflow lo ejecuta con sus credenciales.
El PoC es trivial y está en el advisory oficial. El atacante usa su propia API key de Langflow (x-api-key: sk-ATTACKER_API_KEY) y apunta el campo model al UUID de la víctima:
curl -X POST "http://<langflow-host>:7860/api/v1/responses" \
-H "x-api-key: sk-ATTACKER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "VICTIM_FLOW_UUID",
"input_value": "test",
"stream": false
}'
# Devuelve HTTP 200 con la corrida completa del flow de la víctima
Versiones vulnerables: cualquier Langflow anterior a 1.9.1, incluyendo todas las builds 1.x desde que la ruta /api/v1/responses quedó expuesta. Versión parchada: 1.9.1 (released junto al PR de fix #12832, mergeado el 22 de abril de 2026). El fix agrega chequeo de user_id en la rama UUID dentro de get_flow_by_id_or_endpoint_name y devuelve 404 —no 403— para no filtrar existencia del flow vía un oracle de status code. Además endurece /api/v1/run* moviéndolas a dependencias auth-aware y haciendo que un user_id mal formado falle cerrado (404 en vez de 500).
El impacto operativo para una organización típica es serio: Langflow es donde suelen correr pipelines internos con acceso a datos sensibles — RAG sobre bases de conocimientos, agentes que ejecutan queries SQL, integraciones con CRMs, generación de código con acceso a repos privados. Un atacante con una cuenta de bajos privilegios (a veces un becario, un proveedor externo, una cuenta de servicio olvidada) puede ejecutar los flows de mayor privilegio del sistema, exfiltrar todo lo que esos flows procesan y abusar de los rate limits o del budget de LLM de la víctima. Si además el flow víctima está conectado a una tool de ejecución arbitraria (bash, HTTP request, send_email, etc.), el atacante escala a RCE completo dentro del contexto del proceso de Langflow.
Un endpoint OpenAI-compatible es una API pública, sin importar que viva dentro de tu LAN. La autorización se valida contra el recurso que se está accediendo, no contra el modelo del request.
¿Cómo proteger tu infraestructura?
1. Upgrade inmediato a Langflow 1.9.1 o superior
Si tenés Langflow corriendo, hacé el upgrade hoy. Las imágenes Docker oficiales (langflowai/langflow:latest y tags :1.9.1) ya incluyen el fix; si corrés desde pip, el upgrade es pip install --upgrade langflow seguido de un reinicio del servicio. Verificá la versión entrando al panel de Langflow (/) y mirando el footer, o ejecutando python -c "import langflow; print(langflow.__version__)" dentro del container. Si tu deploy sigue en una rama vieja (:1.6, :1.7, :1.8), planeá el salto a 1.9.x esta misma semana: el PR #12832 no rompe compatibilidad hacia atrás según los regression tests publicados.
2. Auditar logs buscando ejecuciones cross-user en /api/v1/responses
Aunque ya parchées, es probable que alguien haya abusado el endpoint antes. El síntoma más claro es un response 200 a un request donde el flow_id ejecutado no coincide con el user_id del x-api-key presentado. Langflow loguea por defecto a stdout en formato JSON; si lo ingestás en Loki, Elastic o Splunk, esta query te arma el hunting:
# Logs de Langflow exportados a JSON
index=langflow OR source=langflow
| where path="/api/v1/responses" AND status=200
| eval attacker_key=x-api-key, victim_uuid=model
| stats count by attacker_key, victim_uuid, user_id_session
| where attacker_key != user_id_session
| sort -count
Si ves cualquier fila con atacante ≠ dueño del flow, tenés un compromiso confirmado: rotar el x-api-key del atacante, invalidar tokens, abrir incidente y revisar qué datos procesó ese flow.
3. Sacar Langflow de Internet y exponerlo solo por VPN o zero-trust
El default de Langflow es escuchar en 0.0.0.0:7860 con la API habilitada — esto es un靶 perfecto para escáneres de Internet (Shodan, Censys, Shadowserver) que ya lo están indexando. Si tu Langflow tiene que ser accesible desde otras máquinas de la LAN, atalo a 127.0.0.1 o a la IP interna del segmento correcto y exponelo vía reverse proxy con auth (oauth2-proxy, Cloudflare Tunnel, Tailscale). Para acceso externo, una opción muy limpia hoy es Cloudflare Tunnel con service auth: el cliente cloudflared corre como sidecar, no hay puerto abierto, y la autenticación se delega a Cloudflare Access. El endpoint /api/v1/responses deja de ser alcanzable salvo por usuarios autorizados vía tu IdP (Okta, Entra ID, Google Workspace, lo que tengas).
4. Rotar API keys existentes y deshabilitar cuentas dormidas
Si Langflow estuvo expuesto en algún momento (algo muy común en despliegues de demo, POC o dev), todas las API key generadas antes del upgrade deben considerarse potencialmente comprometidas y se rotan. Cada usuario puede regenerar la suya desde /settings → API keys. Mientras tanto, en la base de datos de Langflow (SQLite por defecto, en ~/.langflow/...; Postgres si lo configuraste así) corré SELECT id, username, last_login_at FROM user WHERE last_login_at < NOW() - INTERVAL '90 days' y deshabilitá lo que no se use — son cuentas de ataque baratas una vez que alguien tiene una sola válida.
Indicadores de compromiso (IoC)
Estos son los IoC específicos del CVE-2026-55255 que podés usar para detección, hunting y respuesta. Todos los datos están contrastados contra el advisory de GitHub, el NVD y el post de Sysdig.
- Endpoint vulnerable:
POST /api/v1/responsesen cualquier instancia de Langflow anterior a 1.9.1. Acepta JSON conmodelcomo UUID de flow. - Auth esperada vs. auth real: el endpoint pide
x-api-key(API key de Langflow del atacante). La API key queda asociada aluser_iddel atacante, pero el flow ejecutado es el del UUID recibido — ninguna verificación de ownership. - Función vulnerable:
get_flow_by_id_or_endpoint_name()ensrc/backend/base/langflow/helpers/flow.py, líneas 399-414. La rama UUID (flow_id = UUID(flow_id_or_name); flow = await session.get(Flow, flow_id)) no chequeauser_id. - Versiones afectadas: Langflow
< 1.9.1. Versión parchada: 1.9.1 — fix en PR #12832. Confirmá también si tenés instaladas versiones nightly entre 1.6 y 1.8, todas son vulnerables. - Vector de PoC:
curl -X POST -H "x-api-key: sk-..." -d '{"model":"<UUID>","input_value":"test","stream":false}' http://host:7860/api/v1/responses. Respuesta esperada del servidor vulnerable: HTTP 200 con el JSON de la corrida del flow ajeno. - Indicador de tráfico: requests a
/api/v1/responsesdonde elx-api-keypresentado tiene unuser_iddistinto deluser_iddueño del flowmodel. En logs de Langflow aparece como correlato entreapi_key_useryflow_owner. - Fuente de telemetría útil: el feed público de Shadowserver para puertos 7860 abiertos en Internet; cruzá con tu ASN para ver si tu Langflow quedó indexado. Greypeek de Censys
services.port:7860 AND services.software.vendor:langflowte lista instancias.
# Hunting rápido desde logs de Langflow (stdout JSON)
grep -F '"/api/v1/responses"' /var/log/langflow/langflow.log \
| jq -r 'select(.status==200) | "\(.x_api_key_user // "?") \(.model) \(.user_id // "?")"' \
| awk '$1 != $3 {print}' \
| sort | uniq -c | sort -rn | head -20
🛡️ ¿Tenés Langflow o alguna plataforma de agentes IA expuesta?
Si en tu organización corre Langflow, n8n, Flowise, Dify, LiteLLM o cualquier constructor visual de agentes IA — en producción, en un VPS de desarrollo, o en una POC que quedó olvidada — una auditoría rápida de los endpoints OpenAI-compatible y los handlers de tools te puede ahorrar un incidente serio. En IPSecureNetwork revisamos cada endpoint que toca el modelo, validamos autorización por recurso, segmentamos la red y dejamos monitoreo durable sobre los flows de mayor privilegio.
SOLICITAR AUDITORÍA →