All vulnerabilities
CRITICALSupply chain

CVE-2026-69254

npm · flowise

Summary

Flowise: RCE via NodeVM Sandbox Escape in executeJavaScriptCode() nodeVMOptions Override

Advisory details

Summary

A sandbox escape vulnerability in executeJavaScriptCode() allows any authenticated user to execute arbitrary system commands as root on the Flowise server. The function accepts caller-provided nodeVMOptions that override the default sandbox security settings via JavaScript's spread operator, allowing an attacker to re-enable blocked modules like child_process and fs.

Details

The vulnerability is in packages/components/src/utils.ts at line 1755:

const finalNodeVMOptions = { ...defaultNodeVMOptions, ...nodeVMOptions }

The executeJavaScriptCode() function (line 1569) creates a NodeVM sandbox with secure defaults that restrict which Node.js built-in modules can be required:

async (code, sandbox, options = {}) => {
    const { nodeVMOptions = {} } = options;
    // ...
    const defaultNodeVMOptions = {
        require: {
            builtin: builtinDeps,  // restricted allowlist — blocks child_process, fs, os, etc.
            mock: secureWrappers
        },
        eval: false,
        wasm: false
    }
    const finalNodeVMOptions = { ...defaultNodeVMOptions, ...nodeVMOptions }  // ← VULN: caller overrides security settings
    const vm = new NodeVM(finalNodeVMOptions)
}

The spread operator allows any caller to override require.builtin with ["*"], which permits all Node.js built-in modules including child_process.

Taint 01: Route Registration
packages/server/src/routes/node-custom-functions/index.ts (line 8)

Taint 02: Controller
executeCustomFunction() passes req.body to service — packages/server/src/controllers/nodes/index.ts (line 90)

Taint 03: Service executeCustomNodeFunction() loads the customFunction node and calls init() with user-provided javascriptFunctionpackages/server/src/utils/executeCustomNodeFunction.ts (line 49)

Taint 04: Sandbox Entry
Code runs inside NodeVM via executeJavaScriptCode()packages/components/src/utils.ts (line 1760)

Taint 05: Escape Inside the sandbox, the attacker requires flowise-components/dist/src/utils.js by absolute path (bypassing the module allowlist), obtaining a reference to executeJavaScriptCode() itself

Taint 06: Override The attacker calls executeJavaScriptCode() with nodeVMOptions: { require: { builtin: ["*"] } }, which overrides the security defaults at line 1755: { ...defaultNodeVMOptions, ...nodeVMOptions }

Taint 07: RCE
Inside the nested VM, require("child_process") succeeds. Arbitrary commands execute as root.

PoC

Step 1: Start Flowise

docker run -d --name flowise-poc -p 3000:3000 \
  -e PORT=3000 -e DISABLE_FLOWISE_TELEMETRY=true \                                                                                                                                                                                         
  flowiseai/flowise:latest                                                                                                                                                                                                                 
                                                                                                                                                                                                                                           
# Wait ~30s for startup                                                                                                                                                                                                                    
curl http://localhost:3000/api/v1/version
# {"version":"3.1.1"}                                                                                                                                                                                                                      

Step 2: Obtain Bearer Token

Register an account, then create an API key:

# Register      
curl -s -X POST http://localhost:3000/api/v1/account/register \
  -H "Content-Type: application/json" \
  -d '{"user":{"email":"attacker@test.com","password":"Attack12345","name":"Attacker"}}'   

References