From 3c88aec034934bcbad30c5ef1cab62cbbdb98e64 Mon Sep 17 00:00:00 2001
From: Timothy Carambat <rambat1010@gmail.com>
Date: Mon, 11 Sep 2023 22:07:48 +0200
Subject: [PATCH] prevent exports path traversal (#233)

---
 .../Modals/MangeWorkspace/Documents/index.jsx |  5 +--
 server/endpoints/system.js                    | 31 +++++++++++++------
 2 files changed, 24 insertions(+), 12 deletions(-)

diff --git a/frontend/src/components/Modals/MangeWorkspace/Documents/index.jsx b/frontend/src/components/Modals/MangeWorkspace/Documents/index.jsx
index 3dcfd3374..628f22c51 100644
--- a/frontend/src/components/Modals/MangeWorkspace/Documents/index.jsx
+++ b/frontend/src/components/Modals/MangeWorkspace/Documents/index.jsx
@@ -177,8 +177,9 @@ export default function DocumentSettings({ workspace }) {
         </div>
       </div>
       <div
-        className={`flex items-center ${canDelete ? "justify-between" : "justify-end"
-          } p-4 md:p-6 space-x-2 border-t border-gray-200 rounded-b dark:border-gray-600`}
+        className={`flex items-center ${
+          canDelete ? "justify-between" : "justify-end"
+        } p-4 md:p-6 space-x-2 border-t border-gray-200 rounded-b dark:border-gray-600`}
       >
         <button
           hidden={!canDelete}
diff --git a/server/endpoints/system.js b/server/endpoints/system.js
index 736ab1418..d493a2c2a 100644
--- a/server/endpoints/system.js
+++ b/server/endpoints/system.js
@@ -24,6 +24,7 @@ const { User } = require("../models/user");
 const { validatedRequest } = require("../utils/middleware/validatedRequest");
 const { handleImports } = setupDataImports();
 const { handleLogoUploads } = setupLogoUploads();
+const fs = require("fs");
 const path = require("path");
 const {
   getDefaultFilename,
@@ -315,9 +316,21 @@ function systemEndpoints(app) {
     "/system/data-exports/:filename",
     [validatedRequest],
     (request, response) => {
-      const filePath =
-        __dirname + "/../storage/exports/" + request.params.filename;
-      response.download(filePath, request.params.filename, (err) => {
+      const exportLocation = __dirname + "/../storage/exports/";
+      const sanitized = path
+        .normalize(request.params.filename)
+        .replace(/^(\.\.(\/|\\|$))+/, "");
+      const finalDestination = path.join(exportLocation, sanitized);
+
+      if (!fs.existsSync(finalDestination)) {
+        response.status(404).json({
+          error: 404,
+          msg: `File ${request.params.filename} does not exist in exports.`,
+        });
+        return;
+      }
+
+      response.download(finalDestination, request.params.filename, (err) => {
         if (err) {
           response.send({
             error: err,
@@ -448,13 +461,11 @@ function systemEndpoints(app) {
         response.status(200).json({ canDelete });
       } catch (error) {
         console.error("Error fetching can delete workspaces:", error);
-        response
-          .status(500)
-          .json({
-            success: false,
-            message: "Internal server error",
-            canDelete: false,
-          });
+        response.status(500).json({
+          success: false,
+          message: "Internal server error",
+          canDelete: false,
+        });
       }
     }
   );
-- 
GitLab