CVE-2024-4286 (JavaScript, published 2024-05-26T23:15Z)
Description: value: Mintplex-Labs' anything-llm application is vulnerable to improper neutralization of special elements used in an expression language statement, identified in the commit id `57984fa85c31988b2eff429adfc654c46e0c342a`. The vulnerability arises from the application's handling of user modifications by managers or admins, allowing for the modification of all existing attributes of the `user` database entity without proper checks or sanitization. This flaw can be exploited to delete user threads, denying users access to their previously submitted data, or to inject fake threads and/or chat history for social engineering attacks.
Severity: nan (CVSS v3 base score: )
Weakness: CWE-917 \u2014 Improper Neutralization of Special Elements used in an Expression Language Statement ('Expression Language Injection')
The product constructs all or part of an expression language (EL) statement in a framework such as a Java Server Page (JSP) using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended EL statement before it is executed.
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, {