CVE-2024-3033: Improper Authorization (CWE-285)
value: An improper authorization vulnerability exists in the mintplex-labs/anything-llm application, specifically within the '/api/v/' endpoint and its sub-routes. This flaw allows unauthenticated users to perform destructive actions on the VectorDB, including resetting the database and deleting specific namespaces, without requiring any authorization or permissions. The issue affects all versions up to and including the latest version, with a fix introduced in version 1.0.0. Exploitation of this vulnerability can lead to complete data loss of document embeddings across all workspaces, rendering workspace chats and embeddable chat widgets non-functional. Additionally, attackers can list all namespaces, potentially exposing private workspace names.
CWE description: The product does not perform or incorrectly performs an authorization check when an actor attempts to access a resource or perform an action.
Published: 2024-06-06T18:15Z
Repository: https://github.com/mintplex-labs/anything-llm
Language: JavaScript
Files changed: server/index.js
Commit date: 2024-03-27 13:19:28 -0700
Commit message: move vector db debug endpoint to dev only

Diff: diff --git a/server/index.js b/server/index.js
index 518df7fc8..5b63cafa2 100644
--- a/server/index.js
+++ b/server/index.js
@@ -49,38 +49,10 @@ documentEndpoints(apiRouter);
 developerEndpoints(app, apiRouter);
 
 // Externally facing embedder endpoints
 embeddedEndpoints(apiRouter);
 
-apiRouter.post("/v/:command", async (request, response) => {
-  try {
-    const VectorDb = getVectorDbClass();
-    const { command } = request.params;
-    if (!Object.getOwnPropertyNames(VectorDb).includes(command)) {
-      response.status(500).json({
-        message: "invalid interface command",
-        commands: Object.getOwnPropertyNames(VectorDb),
-      });
-      return;
-    }
-
-    try {
-      const body = reqBody(request);
-      const resBody = await VectorDb[command](body);
-      response.status(200).json({ ...resBody });
-    } catch (e) {
-      // console.error(e)
-      console.error(JSON.stringify(e));
-      response.status(500).json({ error: e.message });
-    }
-    return;
-  } catch (e) {
-    console.log(e.message, e);
-    response.sendStatus(500).end();
-  }
-});
-
 if (process.env.NODE_ENV !== "development") {
   app.use(
     express.static(path.resolve(__dirname, "public"), { extensions: ["js"] })
   );
 
@@ -90,10 +62,39 @@ if (process.env.NODE_ENV !== "development") {
 
   app.get("/robots.txt", function (_, response) {
     response.type("text/plain");
     response.send("User-agent: *\nDisallow: /").end();
   });
+} else {
+  // Debug route for development connections to vectorDBs
+  apiRouter.post("/v/:command", async (request, response) => {
+    try {
+      const VectorDb = getVectorDbClass();
+      const { command } = request.params;
+      if (!Object.getOwnPropertyNames(VectorDb).includes(command)) {
+        response.status(500).json({
+          message: "invalid interface command",
+          commands: Object.getOwnPropertyNames(VectorDb),
+        });
+        return;
+      }
+
+      try {
+        const body = reqBody(request);
+        const resBody = await VectorDb[command](body);
+        response.status(200).json({ ...resBody });
+      } catch (e) {
+        // console.error(e)
+        console.error(JSON.stringify(e));
+        response.status(500).json({ error: e.message });
+      }
+      return;
+    } catch (e) {
+      console.log(e.message, e);
+      response.sendStatus(500).end();
+    }
+  });
 }
 
 app.all("*", function (_, response) {
   response.sendStatus(404);
 });

Vulnerable code: apiRouter.post("/v/:command", async (request, response) => {
  try {
    const VectorDb = getVectorDbClass();
    const { command } = request.params;
    if (!Object.getOwnPropertyNames(VectorDb).includes(command)) {
      response.status(500).json({
        message: "invalid interface command",
        commands: Object.getOwnPropertyNames(VectorDb),
      });
      return;
    }

    try {
      const body = reqBody(request);
      const resBody = await VectorDb[command](body);
      response.status(200).json({ ...resBody });
    } catch (e) {
      // console.error(e)
      console.error(JSON.stringify(e));
      response.status(500).json({ error: e.message });
    }
    return;
  } catch (e) {
    console.log(e.message, e);
    response.sendStatus(500).end();
  }
});

Fixed code: } else {
  // Debug route for development connections to vectorDBs
  apiRouter.post("/v/:command", async (request, response) => {
    try {
      const VectorDb = getVectorDbClass();
      const { command } = request.params;
      if (!Object.getOwnPropertyNames(VectorDb).includes(command)) {
        response.status(500).json({
          message: "invalid interface command",
          commands: Object.getOwnPropertyNames(VectorDb),
        });
        return;
      }

      try {
        const body = reqBody(request);
        const resBody = await VectorDb[command](body);
        response.status(200).json({ ...resBody });
      } catch (e) {
        // console.error(e)
        console.error(JSON.stringify(e));
        response.status(500).json({ error: e.message });
      }
      return;
    } catch (e) {
      console.log(e.message, e);
      response.sendStatus(500).end();
    }
  });