
Une documentation de CVE-2025-68116
Auteur : @x0root
Vulnérabilité : Cross-Site Scripting (XSS) stocké via des téléversements interprétables par le navigateur (SVG / HTML)
Logiciel concerné : FileRise (< 2.7.1)
Version corrigée : 2.7.1
CVE officielle (demandée via GHSA) : CVE-2025-68116 (suivi/avis : GHSA-35pp-ggh6-c59c)
Avis connexe antérieur (atténuation originale contournée) : GHSA-qrcv-vjvf-fr29
Évaluation CVSS :
L’évaluation du signaleur évalue les Privilèges Requis (PR) au moment de l’exploitation, et non au moment du dépôt de la vulnérabilité.
L’exploitation se produit lorsqu’une victime accède à un lien de partage public généré, ce qui ne nécessite aucune authentification ni privilège (PR:N).
L’évaluation du CNA évalue PR en fonction de la capacité à téléverser un fichier malveillant. Cependant, CVSS v3.1 définit les Privilèges Requis (PR) comme les privilèges qu’un attaquant doit posséder au moment où la vulnérabilité est exploitée, et non les privilèges nécessaires pour placer ou préparer la condition vulnérable.
Par conséquent, PR:N reflète plus précisément les conditions d’exploitation réelles, ce qui donne une classification de sévérité Critique (9,6).
Note : GHSA-qrcv-vjvf-fr29 a introduit une atténuation qui empêchait le rendu des SVG dans l’interface web de FileRise (volet de prévisualisation). Ce rapport documente un contournement de cette atténuation — spécifiquement les points de terminaison backend de partage/téléchargement — qui est suivi sous GHSA-35pp-ggh6-c59c / CVE-2025-68116.
Ce document constitue un enregistrement technique complet de CVE-2025-68116 : un XSS stocké dans FileRise qui a persisté après une atténuation précédente et a finalement été corrigé dans la v2.7.1. Il comprend la découverte, les preuves de concept d’exploitation, les correctifs infructueux répétés, une analyse précise du flux de contrôle de la cause racine (avec preuves), la vérification finale du correctif, ainsi qu’une analyse des caractéristiques d’exploitabilité pertinentes pour l’évaluation CVSS. Tout le contenu ci-dessous est basé sur des tests reproduits, une inspection du contrôleur et le fil de discussion public de l’avis.
Un avis antérieur, GHSA-qrcv-vjvf-fr29, traitait du XSS stocké via les téléversements SVG en bloquant le rendu en ligne dans l’interface web de FileRise. Cette atténuation n’a pas traité la manière dont les fichiers SVG étaient servis par les points de terminaison backend tels que :
/api/file/download.php/api/file/share.phpCVE-2025-68116 (suivi sous GHSA-35pp-ggh6-c59c) documente un contournement de l’atténuation GHSA-qrcv-vjvf-fr29 : un attaquant peut stocker un SVG conçu et le livrer aux victimes via des liens de partage publics ou certains comportements de téléchargement, entraînant l’exécution de scripts dans l’origine FileRise.
Pour valider si le backend exposait encore les SVG de manière interprétable, j’ai téléversé un SVG PoC simple :
L’accès au fichier via :
/api/file/download.php?…/api/file/share.php?token=…a entraîné l’exécution de alert(). L’atténuation originale de GHSA-qrcv-vjvf-fr29 (blocage de la prévisualisation dans l’interface) a été contournée par un accès direct à ces points de terminaison.
Un alert() est une preuve de concept ; j’ai testé un impact significatif en faisant interagir la charge utile avec les API internes.
Charge utile de test utilisée :
<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>
Lorsqu’un administrateur connecté ouvrait un lien de partage contenant ce SVG, le script s’exécutait et effectuait des requêtes API authentifiées. Les effets observés comprenaient :
{"csrf_expired":true,"csrf_token":"..."})Classification de l’impact démontrée lors des tests :
J’ai signalé le problème de manière privée. Le mainteneur a publié plusieurs correctifs progressifs :
Tout au long des versions v2.6.0 → v2.7.0, le point de terminaison du lien de partage continuait de servir le SVG d’une manière permettant le rendu en ligne et l’exécution de scripts. L’analyse de la cause racine ci-dessous explique pourquoi les correctifs précédents n’ont pas réussi à fermer complètement la vecteur.
La cause sous-jacente n’était pas un seul en-tête manquant mais l’ordre du flux de contrôle et de la sortie dans shareFile() (contrôleur), ce qui empêchait l’application des en-têtes de sécurité dans de nombreux chemins d’exécution. Deux classes de problèmes étaient présentes :
exit; précoces qui court-circuitaient la fonction avant que les en-têtes de sécurité ne soient définis.J’ai utilisé un scan awk pour lister les occurrences de header() et exit; dans shareFile() jusqu’à l’appel readfile() :
Commande : awk '/function shareFile(/ {flag=1} /readfile(/ {flag=0} flag && /(header|exit;)/ {printf "%4d | %s\n", NR, $0}' src/controllers/FileController.php
Sortie observée (abrégée de mon exécution) :
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;
Les en-têtes de sécurité (la logique de durcissement) commencent vers la ligne ~1743 :
1743 | header('X-Content-Type-Options: nosniff'); ... 1770 | header("Content-Disposition: attachment; ...");
Parce que la fonction émet des en-têtes + exit; plus tôt dans de nombreux chemins, ces requêtes n’atteignaient jamais le code de durcissement qui définit Content-Disposition, nosniff ou le type restrictif.