CVE-2024-4284 (JavaScript, published 2024-05-19T23:15Z)
Description: value: A vulnerability in mintplex-labs/anything-llm allows for a denial of service (DoS) condition through the modification of a user's `id` attribute to a value of 0. This issue affects the current version of the software, with the latest commit id `57984fa85c31988b2eff429adfc654c46e0c342a`. By exploiting this vulnerability, an attacker, with manager or admin privileges, can render a chosen account completely inaccessible. The application's mechanism for suspending accounts does not provide a means to reverse this condition through the UI, leading to uncontrolled resource consumption. The vulnerability is introduced due to the lack of input validation and sanitization in the user modification endpoint and the middleware's token validation logic. This issue has been addressed in version 1.0.0 of the software.
Severity: nan (CVSS v3 base score: )
Weakness: NVD-CWE-noinfo \u2014 Insufficient Information
There is insufficient information about the issue to classify it; details are unkown or unspecified.
Repository: https://github.com/mintplex-labs/anything-llm
Files changed:
server/models/user.js
server/utils/AiProviders/openRouter/index.js
server/utils/PasswordRecovery/index.js
Commit message: Strengthen field validations on user Updates (#1201)

* Strengthen field validations on user Updates

* update writables

Vulnerable code:
      if (!currentUser) {
        return { success: false, error: "User not found" };
      }
          } catch { }
  const { success } = await User.update(userId, {

Fixed code:
  writable: [
    // Used for generic updates so we can validate keys in request body
    "username",
    "password",
    "pfpFilename",
    "role",
    "suspended",
  ],
  // validations for the above writable fields.
  castColumnValue: function (key, value) {
    switch (key) {
      case "suspended":
        return Number(Boolean(value));
      default:
        return String(value);
    }
  },
      if (!userId) throw new Error("No user id provided for update");
      if (!currentUser) return { success: false, error: "User not found" };

      // Removes non-writable fields for generic updates
      // and force-casts to the proper type;
      Object.entries(updates).forEach(([key, value]) => {
        if (this.writable.includes(key)) {
          updates[key] = this.castColumnValue(key, value);
          return;
        }
        delete updates[key];
      });

      if (Object.keys(updates).length === 0)
        return { success: false, error: "No valid updates applied." };
      // Handle password specific updates
  // Explicit direct update of user object.
  // Only use this method when directly setting a key value
  // that takes no user input for the keys being modified.
  _update: async function (id = null, data = {}) {
    if (!id) throw new Error("No user id provided for update");

    try {
      const user = await prisma.users.update({
        where: { id },
        data,
      });
      return { user, message: null };
    } catch (error) {
      console.error(error.message);
      return { user: null, message: error.message };
    }
  },

          } catch {}
  const { user: success } = await User._update(userId, {
  });

  // seen_recovery_codes is not publicly writable
  // so we have to do direct update here
  await User._update(resetToken.user_id, {