Carga sin restricciones de archivos de tipo peligroso en la foto de producto de Prospero Flow CRM permite cross-site scripting almacenado
Descripción
Carga sin restricciones de archivos de tipo peligroso (CWE-434) que deriva en cross-site scripting almacenado (CWE-79) en ProductSaveController::save() (app/Http/Controllers/Product/ProductSaveController.php), expuesto en POST /product/save, en Prospero Flow CRM anteriores a 5.16.0, que permite a cualquier usuario autenticado con el permiso create product —el rol rutinario Seller, no uno administrativo— ejecutar JavaScript arbitrario en el origen de la aplicación, mediante la subida de un archivo cuyo contenido comienza con una cabecera de imagen válida y cuyo nombre declarado por el cliente lleva la extensión .html, debido a que la regla photo de ProductRequest (nullable|image|mimes:jpeg,png,jpg,gif|max:3072) clasifica el archivo únicamente por su contenido mediante UploadedFile::guessExtension() y la lista negra de Laravel solo rechaza los sufijos php, php3, php4, php5, php7, php8, phtml y phar, mientras el controlador construye el nombre del archivo almacenado con $photoFile->getClientOriginalExtension() —la extensión declarada por el cliente, no el tipo de contenido ya validado— y lo copia con copy() dentro de la raíz web pública en public_path("asset/upload/product/$product->id"), a diferencia de ProfileSaveController::save(), que sobre el mismo tipo de recurso deriva la extensión del contenido con extension(). El archivo se guarda como <uuid>.html y nginx lo sirve como contenido estático con Content-Type: text/html sin exigir sesión, ya que su configuración solo enruta /index.php a PHP-FPM. Esto resulta en la ejecución de JavaScript de origen propio en el navegador de cualquier usuario que abra la URL de la foto, incluido un CompanyAdmin o un SuperAdmin que siga un enlace compartido en un correo o un ticket interno, con la confianza de primera parte del dominio del CRM.
Tipo de vulnerabilidad (CWE)
CWE-434: Unrestricted Upload of File with Dangerous Type
CWE-79: Improper Neutralization of Input During Web Page Generation
Versiones afectadas
Prospero Flow CRM en todas las versiones anteriores a 5.16.0. La línea vulnerable se introdujo en el commit c028795f (2021-10-01), anterior a que el proyecto adoptara versionado; la primera versión formal que ya la contenía es la 2.0.0, fijada en el commit dd54ad70 (2023-03-03), el primero que incorpora version.php. Las cinco etiquetas publicadas del repositorio se publicaron vulnerables: v1.0.0 (3.9.8), v2.0.1 (4.0.0), v4.6.0 (4.6.0), v5.5.3 (5.5.3) y v5.14.0 (5.14.0). La versión corregida 5.16.0 no está etiquetada y ninguna release publicada incorpora la corrección. Estado por defecto: no afectado.
Puntuación (CVSS 4.0)
Media (4.8)
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:A/VC:N/VI:L/VA:N/SC:N/SI:L/SA:N
Solución
Actualizar a la versión 5.16.0 o superior desplegando desde la rama principal: la corrección no se ha etiquetado y la última release disponible, v5.14.0, no la incorpora. La corrección sustituye getClientOriginalExtension() por extension() en el controlador e introduce la regla ExtensionMatchesContent, que rechaza en validación cualquier discrepancia entre la extensión declarada y el contenido real, pero no elimina los archivos ya almacenados, por lo que conviene revisar public/asset/upload/product/ en busca de archivos cuya extensión no sea jpeg, jpg, png o gif y eliminarlos.
Parche
Commit 71b20e1a
Créditos
- Adrián García López - finder (descubridor)
- Darío Rivas Quero - analyst (analista)
- Secur0 CNA - coordinator (coordinador)
- Gustavo Novaro - remediation developer (desarrollador de la corrección)
Origen del descubrimiento: Externo
Registro oficial: CVE-2026-81931