Vulnerability: Cross-site Scripting in FacturaScripts Cross-site Scripting (XSS) - Stored in GitHub repository neorazorx/facturascripts prior to 2022.06.
Vulnerability ID: GHSA-fp76-f299-v3hj
CWE: CWE-79
Severity score: 5.4
Project: https://github.com/neorazorx/facturascripts
Published: 2022-06-14
File: Core/App/AppRouter.php
Commit message: Force to download SVG files to prevent security problems.
------
Forzamos a descargar los archivos SVG para evitar problemas de seguridad.
Commit author: Carlos Garcia Gomez

Vulnerable version (before fix):
 public function getFile(): bool         $allowedFolders = ['node_modules', 'vendor', 'Dinamic', 'Core', 'Plugins', 'MyFiles/Public'];         foreach ($allowedFolders as $folder) {             if ('/' . $folder === substr($uri, 0, 1 + strlen($folder))) {                 header('Content-Type: ' . $this->getMime($filePath));                 readfile($filePath);                 return true;             }         } public function getFile(): bool         $token = filter_input(INPUT_GET, 'myft');         $fixedFilePath = substr(urldecode($uri), 1);         if ('/MyFiles/' === substr($uri, 0, 9) && $token && MyFilesToken::validate($fixedFilePath, $token)) {             header('Content-Type: ' . $this->getMime($filePath));              // disable the buffer if enabled             if (ob_get_contents()) {                 ob_end_flush();             }              readfile($filePath);             return true;         }  private function deploy()         }     }      /**      * Return the mime type from given file.      *

Fixed version (after fix):
 public function getFile(): bool         $allowedFolders = ['node_modules', 'vendor', 'Dinamic', 'Core', 'Plugins', 'MyFiles/Public'];         foreach ($allowedFolders as $folder) {             if ('/' . $folder === substr($uri, 0, 1 + strlen($folder))) {                 $this->download($filePath);                 return true;             }         } public function getFile(): bool         $token = filter_input(INPUT_GET, 'myft');         $fixedFilePath = substr(urldecode($uri), 1);         if ('/MyFiles/' === substr($uri, 0, 9) && $token && MyFilesToken::validate($fixedFilePath, $token)) {             $this->download($filePath);             return true;         }  private function deploy()         }     }      private function download(string $filePath)     {         header('Content-Type: ' . $this->getMime($filePath));          // disable the buffer if enabled         if (ob_get_contents()) {             ob_end_flush();         }          // force to download svg files to prevent XSS attacks         if (strpos($filePath, '.svg') !== false) {             header('Content-Disposition: attachment; filename="' . basename($filePath) . '"');         }          readfile($filePath);     }      /**      * Return the mime type from given file.      *

Patch:
patch: @@ -127,8 +127,7 @@ public function getFile(): bool
         $allowedFolders = ['node_modules', 'vendor', 'Dinamic', 'Core', 'Plugins', 'MyFiles/Public'];
         foreach ($allowedFolders as $folder) {
             if ('/' . $folder === substr($uri, 0, 1 + strlen($folder))) {
-                header('Content-Type: ' . $this->getMime($filePath));
-                readfile($filePath);
+                $this->download($filePath);
                 return true;
             }
         }
@@ -137,14 +136,7 @@ public function getFile(): bool
         $token = filter_input(INPUT_GET, 'myft');
         $fixedFilePath = substr(urldecode($uri), 1);
         if ('/MyFiles/' === substr($uri, 0, 9) && $token && MyFilesToken::validate($fixedFilePath, $token)) {
-            header('Content-Type: ' . $this->getMime($filePath));
-
-            // disable the buffer if enabled
-            if (ob_get_contents()) {
-                ob_end_flush();
-            }
-
-            readfile($filePath);
+            $this->download($filePath);
             return true;
         }
 
@@ -205,6 +197,23 @@ private function deploy()
         }
     }
 
+    private function download(string $filePath)
+    {
+        header('Content-Type: ' . $this->getMime($filePath));
+
+        // disable the buffer if enabled
+        if (ob_get_contents()) {
+            ob_end_flush();
+        }
+
+        // force to download svg files to prevent XSS attacks
+        if (strpos($filePath, '.svg') !== false) {
+            header('Content-Disposition: attachment; filename="' . basename($filePath) . '"');
+        }
+
+        readfile($filePath);
+    }
+
     /**
      * Return the mime type from given file.
      *
path: Core/App/AppRouter.php