CVE-2024-0798: Least Privilege Violation (CWE-272)
value: A privilege escalation vulnerability exists in mintplex-labs/anything-llm, allowing users with 'default' role to delete documents uploaded by 'admin'. Despite the intended restriction that prevents 'default' role users from deleting admin-uploaded documents, an attacker can exploit this vulnerability by sending a crafted DELETE request to the /api/system/remove-document endpoint. This vulnerability is due to improper access control checks, enabling unauthorized document deletion and potentially leading to loss of data integrity.
CWE description: The elevated privilege level required to perform operations such as chroot() should be dropped immediately after the operation is performed.
Published: 2024-02-26T16:27Z
Repository: https://github.com/mintplex-labs/anything-llm
Language: JavaScript
Files changed: server/endpoints/system.js
Commit date: 2024-01-22 14:31:19 -0800
Commit message: Apply permissioning on document modification endpoints (#637)


Diff: diff --git a/server/endpoints/system.js b/server/endpoints/system.js
index 14aa22e04..4eb82fb0a 100644
--- a/server/endpoints/system.js
+++ b/server/endpoints/system.js
@@ -187,11 +187,11 @@ function systemEndpoints(app) {
     }
   });
 
   app.get(
     "/system/system-vectors",
-    [validatedRequest],
+    [validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])],
     async (request, response) => {
       try {
         const query = queryParams(request);
         const VectorDb = getVectorDbClass();
         const vectorCount = !!query.slug
@@ -205,11 +205,11 @@ function systemEndpoints(app) {
     }
   );
 
   app.delete(
     "/system/remove-document",
-    [validatedRequest],
+    [validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])],
     async (request, response) => {
       try {
         const { name } = reqBody(request);
         await purgeDocument(name);
         response.sendStatus(200).end();
@@ -220,11 +220,11 @@ function systemEndpoints(app) {
     }
   );
 
   app.delete(
     "/system/remove-folder",
-    [validatedRequest],
+    [validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])],
     async (request, response) => {
       try {
         const { name } = reqBody(request);
         await purgeFolder(name);
         response.sendStatus(200).end();
@@ -233,19 +233,23 @@ function systemEndpoints(app) {
         response.sendStatus(500).end();
       }
     }
   );
 
-  app.get("/system/local-files", [validatedRequest], async (_, response) => {
-    try {
-      const localFiles = await viewLocalFiles();
-      response.status(200).json({ localFiles });
-    } catch (e) {
-      console.log(e.message, e);
-      response.sendStatus(500).end();
+  app.get(
+    "/system/local-files",
+    [validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])],
+    async (_, response) => {
+      try {
+        const localFiles = await viewLocalFiles();
+        response.status(200).json({ localFiles });
+      } catch (e) {
+        console.log(e.message, e);
+        response.sendStatus(500).end();
+      }
     }
-  });
+  );
 
   app.get(
     "/system/document-processing-status",
     [validatedRequest],
     async (_, response) => {

Vulnerable code:     [validatedRequest],
    [validatedRequest],
    [validatedRequest],
  app.get("/system/local-files", [validatedRequest], async (_, response) => {
    try {
      const localFiles = await viewLocalFiles();
      response.status(200).json({ localFiles });
    } catch (e) {
      console.log(e.message, e);
      response.sendStatus(500).end();
  });
Fixed code:     [validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])],
    [validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])],
    [validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])],
  app.get(
    "/system/local-files",
    [validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])],
    async (_, response) => {
      try {
        const localFiles = await viewLocalFiles();
        response.status(200).json({ localFiles });
      } catch (e) {
        console.log(e.message, e);
        response.sendStatus(500).end();
      }
  );