Repository: Mintplex-Labs/anything-llm
File: server/endpoints/workspaces.js (JavaScript)

Code before:
  app.post(
    "/workspace/:slug/thread/fork",
    [validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceSlug],
    async (request, response) => {
      try {
        const user = await userFromSession(request, response);
        const workspace = response.locals.workspace;
        const { chatId, threadSlug } = reqBody(request);

        if (!chatId) {
          return response.status(400).json({ message: "chatId is required" });
        }
        const { thread: newThread, message: threadError } =
          await WorkspaceThread.new(workspace, user?.id);

        if (threadError) {
          return response.status(500).json({ error: threadError });
        }
        const chatsToFork = await WorkspaceChats.where(
          {
            workspaceId: workspace.id,
            user_id: user?.id,
            thread_id: threadSlug
              ? (
                  await WorkspaceThread.get({
                    slug: threadSlug,
                    workspace_id: workspace.id,
                  })
                )?.id
              : null,
            id: { lte: Number(chatId) },
          },
          null,
          { id: "asc" }
        );

        let lastMessageText = "";
        const chatsData = chatsToFork.map((chat) => {
          let response = chat.response;
          if (typeof response === "string") {
            response = safeJsonParse(response);
          }

          if (response && response.text) {
            lastMessageText = response.text;
          }

          return {
            workspaceId: workspace.id,
            prompt: chat.prompt,
            response: JSON.stringify(response),

Review comment (security):
This is user input, cast it to the expected type to prevent injection via JSON schema `String(threadSlug)`

Code after:
  app.post(
    "/workspace/:slug/thread/fork",
    [validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceSlug],
    async (request, response) => {
      try {
        const user = await userFromSession(request, response);
        const workspace = response.locals.workspace;
        const { chatId, threadSlug } = reqBody(request);
        if (!chatId)
          return response.status(400).json({ message: "chatId is required" });

        // Get threadId we are branching from if that request body is sent
        // and is a valid thread slug.
        const threadId = !!threadSlug
          ? (
              await WorkspaceThread.get({
                slug: String(threadSlug),
                workspace_id: workspace.id,
              })
            )?.id ?? null
          : null;
        const chatsToFork = await WorkspaceChats.where(
          {
            workspaceId: workspace.id,
            user_id: user?.id,
            include: true, // only duplicate visible chats
            thread_id: threadId,
            id: { lte: Number(chatId) },
          },
          null,
          { id: "asc" }
        );

        const { thread: newThread, message: threadError } =
          await WorkspaceThread.new(workspace, user?.id);
        if (threadError)
          return response.status(500).json({ error: threadError });

        let lastMessageText = "";
        const chatsData = chatsToFork.map((chat) => {
          const chatResponse = safeJsonParse(chat.response, {});
          if (chatResponse?.text) lastMessageText = chatResponse.text;

          return {
            workspaceId: workspace.id,
            prompt: chat.prompt,
            response: JSON.stringify(chatResponse),
            user_id: user?.id,
            thread_id: newThread.id,
          };
        });