Language: TypeScript
Label: vulnerable
CWE: CWE-89 \u2014 Improper Neutralization of Special Elements used in an SQL Command ('SQL Injection')
The product constructs all or part of an SQL command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended SQL command when it is sent to a downstream component.

Code:
  update: async function (userId, updates = {}) {
    const user = await this.get(`id = ${userId}`);
    if (!user) return { success: false, error: "User does not exist." };
    const { username, password, role, suspended = 0 } = updates;
    const toUpdate = { suspended };

    if (user.username !== username && username?.length > 0) {
      const usedUsername = !!(await this.get(`username = '${username}'`));
      if (usedUsername)
        return { success: false, error: `${username} is already in use.` };
      toUpdate.username = username;
    }

    if (!!password) {
      const bcrypt = require("bcrypt");
      toUpdate.password = bcrypt.hashSync(password, 10);
    }

    if (user.role !== role && ["admin", "default"].includes(role)) {
      // If was existing admin and that has been changed
      // make sure at least one admin exists
      if (user.role === "admin") {
        const validAdminCount = (await this.count(`role = 'admin'`)) > 1;
        if (!validAdminCount)
          return {
            success: false,
            error: `There would be no admins if this action was completed. There must be at least one admin.`,
          };
      }

      toUpdate.role = role;
    }

    if (Object.keys(toUpdate).length !== 0) {
      const values = Object.values(toUpdate);
      const template = `UPDATE ${this.tablename} SET ${Object.keys(
        toUpdate
      ).map((key) => {
        return `${key}=?`;
      })} WHERE id = ?`;

      const db = await this.db();
      const { success, message } = await db
        .run(template, [...values, userId])
        .then(() => {
          return { success: true, message: null };
        })
        .catch((error) => {
          return { success: false, message: error.message };
        });

      db.close();
      if (!success) {
        console.error(message);
        return { success: false, error: message };
      }
    }

    return { success: true, error: null };
  },