CVE-2024-3283 (JavaScript, published 2024-04-10T17:15Z)
Description: value: A vulnerability in mintplex-labs/anything-llm allows users with manager roles to escalate their privileges to admin roles through a mass assignment issue. The '/admin/system-preferences' API endpoint improperly authorizes manager-level users to modify the 'multi_user_mode' system variable, enabling them to access the '/api/system/enable-multi-user' endpoint and create a new admin user. This issue results from the endpoint accepting a full JSON object in the request body without proper validation of modifiable fields, leading to unauthorized modification of system settings and subsequent privilege escalation.
Severity: nan (CVSS v3 base score: )
Weakness: CWE-915 \u2014 Improperly Controlled Modification of Dynamically-Determined Object Attributes
The product receives input from an upstream component that specifies multiple attributes, properties, or fields that are to be initialized or updated in an object, but it does not properly control which attributes can be modified.
Repository: https://github.com/mintplex-labs/anything-llm
Files changed:
server/endpoints/system.js
server/models/systemSettings.js
server/models/telemetry.js
Commit message: Patch ability to update multi-user-flag once set (#993)

* Patch ability to update multi-user-flag once set

* update logo function to safe update key values

Vulnerable code:
        await SystemSettings.updateSettings({
        await SystemSettings.updateSettings({
        const { success, error } = await SystemSettings.updateSettings({
        const { success, error } = await SystemSettings.updateSettings({
    "multi_user_mode",
      const updatePromises = Object.keys(updates)
        .filter((key) => this.supportedFields.includes(key))
        .map((key) => {
          const validatedValue = this.validations.hasOwnProperty(key)
            ? this.validations[key](updates[key])
            : updates[key];

          return prisma.system_settings.upsert({
            where: { label: key },
            update: {
              value: validatedValue === null ? null : String(validatedValue),
            },
            create: {
              label: key,
              value: validatedValue === null ? null : String(validatedValue),
            },
          });
    await SystemSettings.updateSettings({ [this.label]: newId });

Fixed code:
        await SystemSettings._updateSettings({
        await SystemSettings._updateSettings({
        const { success, error } = await SystemSettings._updateSettings({
        const { success, error } = await SystemSettings._updateSettings({
  protectedFields: ["multi_user_mode"],
  // Can take generic keys and will pre-filter invalid keys
  // from the set before sending to the explicit update function
  // that will then enforce validations as well.
    const validFields = Object.keys(updates).filter((key) =>
      this.supportedFields.includes(key)
    );

    Object.entries(updates).forEach(([key]) => {
      if (validFields.includes(key)) return;
      delete updates[key];
    });

    return this._updateSettings(updates);
  },

  // Explicit update of settings + key validations.
  // Only use this method when directly setting a key value
  // that takes no user input for the keys being modified.
  _updateSettings: async function (updates = {}) {
      const updatePromises = Object.keys(updates).map((key) => {
        const validatedValue = this.validations.hasOwnProperty(key)
          ? this.validations[key](updates[key])
          : updates[key];

        return prisma.system_settings.upsert({
          where: { label: key },
          update: {
            value: validatedValue === null ? null : String(validatedValue),
          },
          create: {
            label: key,
            value: validatedValue === null ? null : String(validatedValue),
          },
      });
    await SystemSettings._updateSettings({ [this.label]: newId });