
Una documentación de CVE-2025-68116
Autor: @x0root
Vulnerabilidad: Cross-Site Scripting (XSS) Almacenado mediante subidas renderizables por el navegador (SVG / HTML)
Software afectado: FileRise (< 2.7.1)
Versión parcheada: 2.7.1
CVE oficial (solicitado vía GHSA): CVE-2025-68116 (seguimiento/aviso: GHSA-35pp-ggh6-c59c)
Aviso relacionado previo (mitigación original que fue eludida): GHSA-qrcv-vjvf-fr29
Evaluación CVSS:
La evaluación del informante valora los Privilegios Requeridos (PR) en el punto de explotación, no en el punto de introducción de la vulnerabilidad.
La explotación ocurre cuando una víctima accede a un enlace de compartición pública generado, lo que no requiere autenticación ni privilegios (PR:N).
La evaluación del CNA valora PR basándose en la capacidad de subir un archivo malicioso. Sin embargo, CVSS v3.1 define los Privilegios Requeridos (PR) como los privilegios que un atacante debe poseer en el momento en que la vulnerabilidad es explotada, no los privilegios necesarios para colocar o preparar la condición vulnerable.
Como tal, PR:N refleja con mayor precisión las condiciones reales de explotación, lo que resulta en una clasificación de severidad Crítica (9.6).
Nota: GHSA-qrcv-vjvf-fr29 introdujo una mitigación que impedía que los SVG se renderizaran dentro de la interfaz web de FileRise (panel de vista previa). Este informe documenta una elusión de esa mitigación —específicamente los endpoints backend de compartición/descarga—, que se rastrea como GHSA-35pp-ggh6-c59c / CVE-2025-68116.
Este documento es un registro técnico completo de CVE-2025-68116: un XSS almacenado en FileRise que persistió después de una mitigación anterior y finalmente se corrigió en v2.7.1. Incluye el descubrimiento, pruebas de concepto de explotación, múltiples correcciones fallidas, un análisis preciso del flujo de control de causa raíz (con evidencia), la verificación final del parche y un análisis de las características de explotabilidad relevantes para la evaluación CVSS. Todo el contenido a continuación se basa en pruebas reproducidas, inspección del controlador y el hilo del aviso público.
Un aviso previo, GHSA-qrcv-vjvf-fr29, abordó el XSS almacenado mediante subidas de SVG bloqueando la renderización en línea en la interfaz web de FileRise. Esa mitigación no abordó cómo los archivos SVG eran servidos por endpoints backend como:
/api/file/download.php/api/file/share.phpCVE-2025-68116 (rastreado como GHSA-35pp-ggh6-c59c) documenta una elusión de la mitigación de GHSA-qrcv-vjvf-fr29: un atacante puede almacenar un SVG manipulado y entregarlo a las víctimas mediante enlaces de compartición pública o ciertos comportamientos de descarga, lo que lleva a la ejecución de scripts en el origen de FileRise.
Para validar si el backend todavía exponía los SVG de forma que pudieran renderizarse, subí un SVG PoC simple:
El acceso al archivo mediante:
/api/file/download.php?…/api/file/share.php?token=…resultó en la ejecución de alert(). La mitigación original de GHSA-qrcv-vjvf-fr29 (bloqueo de vista previa en la interfaz) fue eludida mediante acceso directo a estos endpoints.
Un alert() es una prueba de concepto; probé el impacto real haciendo que el payload interactuara con las APIs internas.
Payload de prueba utilizado:
<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
<script type="text/javascript">
fetch('/api/upload/upload.php')
.then(response => response.text())
.then(data => alert('API Response: ' + data));
</script>
</svg>
Cuando un administrador con sesión iniciada abría un enlace de compartición que contenía este SVG, el script se ejecutaba y realizaba solicitudes API autenticadas. Los efectos observados incluyeron:
{"csrf_expired":true,"csrf_token":"..."})Clasificación de impacto demostrada durante las pruebas:
Informé del problema de forma privada. El mantenedor publicó varias correcciones incrementales:
Desde v2.6.0 → v2.7.0, el endpoint de enlaces de compartición continuó sirviendo el SVG de una manera que permitía la renderización en línea y la ejecución de scripts. El análisis de causa raíz a continuación explica por qué las correcciones anteriores no lograron cerrar por completo el vector.
La causa subyacente no era una única cabecera faltante, sino el flujo de control y el orden de la salida dentro de shareFile() (controlador), que impedía que las cabeceras de seguridad se aplicaran en muchas rutas de ejecución. Había dos clases de problemas:
exit; tempranos que cortocircuitaban la función antes de que se establecieran las cabeceras de seguridad.Utilicé un escaneo con awk para listar las apariciones de header() y exit; dentro de shareFile() hasta la llamada a readfile():
Comando: awk '/function shareFile(/ {flag=1} /readfile(/ {flag=0} flag && /(header|exit;)/ {printf "%4d | %s\n", NR, $0}' src/controllers/FileController.php
Salida observada (abreviada de mi ejecución):
1649 | header('Content-Type: application/json; charset=utf-8'); 1651 | exit; 1657 | header('Content-Type: application/json; charset=utf-8'); 1659 | exit; 1664 | header('Content-Type: application/json; charset=utf-8'); 1666 | exit; 1670 | header("Content-Type: text/html; charset=utf-8"); 1693 | exit; 1699 | header('Content-Type: application/json; charset=utf-8'); 1701 | exit; 1719 | header('Content-Type: application/json; charset=utf-8'); 1721 | exit; 1725 | header('Content-Type: application/json; charset=utf-8'); 1727 | exit;
Las cabeceras de seguridad (la lógica de endurecimiento) comienzan en la línea ~1743:
1743 | header('X-Content-Type-Options: nosniff'); ... 1770 | header("Content-Disposition: attachment; ...");
Debido a que la función emite cabeceras + exit; antes en muchas rutas, esas solicitudes nunca llegaban al código de endurecimiento que establece Content-Disposition, nosniff o el tipo restrictivo.
En el flujo de compartición protegida por contraseña, la función emitía temprano el HTML de solicitud de contraseña: