CVE-2024-3153 (JavaScript, published 2024-06-06T19:16Z)
Description: value: mintplex-labs/anything-llm is affected by an uncontrolled resource consumption vulnerability in its upload file endpoint, leading to a denial of service (DOS) condition. Specifically, the server can be shut down by sending an invalid upload request. An attacker with the ability to upload documents can exploit this vulnerability to cause a DOS condition by manipulating the upload request.
Severity: nan (CVSS v3 base score: )
Weakness: CWE-400 \u2014 Uncontrolled Resource Consumption
The product does not properly control the allocation and maintenance of a limited resource, thereby enabling an actor to influence the amount of resources consumed, eventually leading to the exhaustion of available resources.
Repository: https://github.com/mintplex-labs/anything-llm
Files changed:
server/endpoints/api/document/index.js
server/endpoints/system.js
server/endpoints/workspaces.js
server/utils/files/multer.js
Commit message: Handle no-mutli-part form data error (#1004)



Vulnerable code:
const { setupMulter } = require("../../../utils/files/multer");
const { handleUploads } = setupMulter();
    [validApiKey],
    handleUploads.single("file"),
const { setupLogoUploads, setupPfpUploads } = require("../utils/files/multer");
const { handleLogoUploads } = setupLogoUploads();
const { handlePfpUploads } = setupPfpUploads();
    [validatedRequest, flexUserRoleValid([ROLES.all])],
    handlePfpUploads.single("file"),
    [validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])],
    handleLogoUploads.single("logo"),
      if (!request.file || !request.file.originalname) {
const { setupMulter } = require("../utils/files/multer");
const { handleUploads } = setupMulter();
const { setupPfpUploads } = require("../utils/files/multer");
const { normalizePath } = require("../utils/files");
const { handlePfpUploads } = setupPfpUploads();
const path = require("path");
const fs = require("fs");
    [validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])],
    handleUploads.single("file"),
    [validatedRequest, flexUserRoleValid([ROLES.admin, ROLES.manager])],
    handlePfpUploads.single("file"),
function setupMulter() {
  // Handle File uploads for auto-uploading.
  const storage = multer.diskStorage({
    destination: function (_, __, cb) {
      const uploadOutput =
        process.env.NODE_ENV === "development"
          ? path.resolve(__dirname, `../../../collector/hotdir`)
          : path.resolve(process.env.STORAGE_DIR, `../../collector/hotdir`);
      cb(null, uploadOutput);
    },
    filename: function (_, file, cb) {
      file.originalname = Buffer.from(file.originalname, "latin1").toString(
        "utf8"
      );
      cb(null, file.originalname);
    },
  });
  return { handleUploads: multer({ storage }) };
}
function setupLogoUploads() {
  // Handle Logo uploads.
  const storage = multer.diskStorage({
    destination: function (_, __, cb) {
      const uploadOutput =
        process.env.NODE_ENV === "development"
          ? path.resolve(__dirname, `../../storage/assets`)
          : path.resolve(process.env.STORAGE_DIR, "assets");
      fs.mkdirSync(uploadOutput, { recursive: true });
      return cb(null, uploadOutput);
    },
    filename: function (_, file, cb) {
      file.originalname = Buffer.from(file.originalname, "latin1").toString(
        "utf8"
      );
      cb(null, file.originalname);
    },
  });
  return { handleLogoUploads: multer({ storage }) };
function setupPfpUploads() {
  const storage = multer.diskStorage({
    destination: function (_, __, cb) {
      const uploadOutput =
        process.env.NODE_ENV === "development"
          ? path.resolve(__dirname, `../../storage/assets/pfp`)
          : path.resolve(process.env.STORAGE_DIR, "assets/pfp");
      fs.mkdirSync(uploadOutput, { recursive: true });
      return cb(null, uploadOutput);
    },
    filename: function (req, file, cb) {
      const randomFileName = `${v4()}${path.extname(file.originalname)}`;
      req.randomFileName = randomFileName;
      cb(null, randomFileName);
    },
  return { handlePfpUploads: multer({ storage }) };
  setupMulter,
  setupLogoUploads,
  setupPfpUploads,

Fixed code:
const { handleFileUpload } = require("../../../utils/files/multer");
    [validApiKey, handleFileUpload],
const { handleAssetUpload, handlePfpUpload } = require("../utils/files/multer");
    [validatedRequest, flexUserRoleValid([ROLES.all]), handlePfpUpload],
    [
      validatedRequest,
      flexUserRoleValid([ROLES.admin, ROLES.manager]),
      handleAssetUpload,
    ],
      if (!request?.file || !request?.file.originalname) {
const path = require("path");
const fs = require("fs");
const { normalizePath } = require("../utils/files");
const { handleFileUpload, handlePfpUpload } = require("../utils/files/multer");
    [
      validatedRequest,
      flexUserRoleValid([ROLES.admin, ROLES.manager]),
      handleFileUpload,
    ],
    [
      validatedRequest,
      flexUserRoleValid([ROLES.admin, ROLES.manager]),
      handlePfpUpload,
    ],
// Handle File uploads for auto-uploading.
const fileUploadStorage = multer.diskStorage({
  destination: function (_, __, cb) {
    const uploadOutput =
      process.env.NODE_ENV === "development"
        ? path.resolve(__dirname, `../../../collector/hotdir`)
        : path.resolve(process.env.STORAGE_DIR, `../../collector/hotdir`);
    cb(null, uploadOutput);
  },
  filename: function (_, file, cb) {
    file.originalname = Buffer.from(file.originalname, "latin1").toString(
      "utf8"
    );
    cb(null, file.originalname);
  },
});
// Asset storage for logos
const assetUploadStorage = multer.diskStorage({
  destination: function (_, __, cb) {
    const uploadOutput =
      process.env.NODE_ENV === "development"
        ? path.resolve(__dirname, `../../storage/assets`)
        : path.resolve(process.env.STORAGE_DIR, "assets");
    fs.mkdirSync(uploadOutput, { recursive: true });
    return cb(null, uploadOutput);
  },
  filename: function (_, file, cb) {
    file.originalname = Buffer.from(file.originalname, "latin1").toString(
      "utf8"
    );
    cb(null, file.originalname);
  },
});
// Asset sub-storage manager for pfp icons.
const pfpUploadStorage = multer.diskStorage({
  destination: function (_, __, cb) {
    const uploadOutput =
      process.env.NODE_ENV === "development"
        ? path.resolve(__dirname, `../../storage/assets/pfp`)
        : path.resolve(process.env.STORAGE_DIR, "assets/pfp");
    fs.mkdirSync(uploadOutput, { recursive: true });
    return cb(null, uploadOutput);
  },
  filename: function (req, file, cb) {
    const randomFileName = `${v4()}${path.extname(file.originalname)}`;
    req.randomFileName = randomFileName;
    cb(null, randomFileName);
  },
});
// Handle Generic file upload as documents
function handleFileUpload(request, response, next) {
  const upload = multer({ storage: fileUploadStorage }).single("file");
  upload(request, response, function (err) {
    if (err) {
      response
        .status(500)
        .json({
          success: false,
          error: `Invalid file upload. ${err.message}`,
        })
        .end();
      return;
    }
    next();
  });
// Handle logo asset uploads
function handleAssetUpload(request, response, next) {
  const upload = multer({ storage: assetUploadStorage }).single("logo");
  upload(request, response, function (err) {
    if (err) {
      response
        .status(500)
        .json({
          success: false,
          error: `Invalid file upload. ${err.message}`,
        })
        .end();
      return;
    }
    next();
}
// Handle PFP file upload as logos
function handlePfpUpload(request, response, next) {
  const upload = multer({ storage: pfpUploadStorage }).single("file");
  upload(request, response, function (err) {
    if (err) {
      response
        .status(500)
        .json({
          success: false,
          error: `Invalid file upload. ${err.message}`,
        })
        .end();
      return;
    }
    next();
  });
  handleFileUpload,
  handleAssetUpload,
  handlePfpUpload,