Résumé

Flowise Sandbox Escape to RCE

Détails de l’avis

============================================================================= Security Advisory elttam

Topic: Flowise JavaScript Sandbox Escape

Module: FlowiseAI/Flowise, FlowiseAI/nodevm Disclosed: 11-Apr-2026 Credits: Luke Jahnke and Alex Brown Affects: FlowiseAI/Flowise 3.1.1, FlowiseAI/nodevm 3.9.25

I. Background

Flowise AI is an open-source, low-code platform for building AI applications—such as chatbots, workflows, and autonomous agents—through an intuitive drag-and-drop interface, minimising the need for extensive coding.

The platform also enables execution of custom JavaScript within a sandboxed environment via the Custom Function Agent Flow node or Custom Tool. By default, this sandbox is powered by patriksimek/vm2, a fork of the patriksimek/vm2 package.

II. Problem Description

NOTE: This vulnerability still impacts commit dddfb3c90eec900d747790a439bd362a764039cd (the latest commit on the main branch at the time of writing). The original report was incorrectly closed, due to a misunderstanding that the report was about the use of an outdated and vulnerable version of the patriksimek/vm2 sandbox. The sandbox escape that this report documents is an issue with Flowise, and patching the vm2 sandbox would not resolve it.

The patriksimek/vm2 sandbox executes JavaScript within the same Node.js process, which introduces significant security limitations and makes safely isolating untrusted code inherently difficult. Due to these concerns, the maintainers had deprecated the project and previously issued the following warning:

https://github.com/n8n-io/vm2

The library contains critical security issues and should not be used in production. Maintenance has been discontinued. Consider migrating to isolated-vm.

To demonstrate the risks associated with the use of the vm2 sandbox, a sandbox escape specific to Flowise was investigated. The code snippet below shows the allowed modules that could be used within custom JavaScript code on Flowise.

https://github.com/FlowiseAI/Flowise/blob/flowise%403.1.1/packages/components/src/utils.ts#L124

const defaultAllowExternalDependencies = ['axios', 'moment', 'node-fetch'] <1>

<1> Allows custom JavaScript code to use the axios, moment and node-fetch dependencies.

Notably, the moment dependency had a previously reported path traversal vulnerability (CVE-2022-24785) that could lead to RCE when user input is passed to the locale function. The patch for CVE-2022-24785 was implementing regex check to disallow / or \ characters within a locale name, as shown in the code snippet below.

Patch for CVE-2022-24785 in moment (https://github.com/moment/moment/commit/4211bfc8f15746be4019bba557e29a7ba83d54c5)

function isLocaleNameSane(name) {
    // Prevent names that look like filesystem paths, i.e contain '/' or '\'
    return name.match('^[^/\\\\]*
#39;) != null; <1> } function loadLocale(name) { var oldLocale = null, aliasedRequire; // TODO: Find a better way to register and load all the locales in Node if ( locales[name] === undefined && typeof module !== 'undefined' && module && module.exports && isLocaleNameSane(name) <1> ) { try { oldLocale = globalLocale._abbr; aliasedRequire = require; aliasedRequire('./locale/' + name); <2> getSetGlobalLocale(oldLocale); } catch (e) { // mark as not found to avoid repeating expensive file require call causing high CPU // when trying to find en-US, en_US, en-us for every format call locales[name] = null; // null means not found } } return locales[name]; }

<1> Performs a regex check to disallow / or \ characters within the provided locale name.

<2> The vulnerable sink that introduced CVE-2022-24785.

Flowise used moment version v2.29.3, which had the CVE-2022-24785 patch applied. However, the patch is ineffective in preventing directory traversal in a sandbox context. The validation function uses the match function from the provided object, so an object with a match function that always returns true would bypass the validation check, as shown in the following proof-of-concept script.

fake = new String("../../../../../../../../../../../../../../../etc/passwd");
fake.match = function(regexp){return true;}; <1>
require("moment").locale(fake);

<1> Bypasses the validation check for CVE-2022-24785.

In commit e765367fdc9761a7d9cf01a048cac15c78903b85 (https://github.com/FlowiseAI/Flowise/commit/e765367fdc9761a7d9cf01a048cac15c78903b85), the default sandbox was changed to the E2B sandbox, as shown in the code snippet below.

https://github.com/FlowiseAI/Flowise/blob/e765367fdc9761a7d9cf01a048cac15c78903b85/packages/components/src/utils.ts

export const executeJavaScriptCode = async (
    code: string,
    sandbox: ICommonObject,
    options: {
        timeout?: number
        useSandbox?: boolean
        libraries?: string[]
        streamOutput?: (output: string) => void
        nodeVMOptions?: ICommonObject
    } = {}
): Promise<any> => {
    const { timeout = 300000, useSandbox = true, streamOutput, libraries = [], nodeVMOptions = {} } = options <1>
    if (useSandbox && !process.env.E2B_APIKEY) { <1>
        throw new Error(
            'Sandboxed code execution requires E2B_APIKEY to be configured. ' +
                'Set E2B_APIKEY in your environment or contact your administrator.'
        )
    }
    let timeoutMs = timeout
    if (process.env.SANDBOX_TIMEOUT) {
        timeoutMs = parseInt(process.env.SANDBOX_TIMEOUT, 10)
    }
    ...

<1> The default was changed to use the E2B sandbox.

However, there are several components within the application that still use the insecure vm2 sandbox, as shown in the following grep output.

$ grep -r 'useSandbox: false'
packages/components/nodes/tools/AgentAsTool/AgentAsTool.ts:            useSandbox: false
packages/components/nodes/tools/ChatflowTool/ChatflowTool.ts:            useSandbox: false
packages/components/nodes/sequentialagents/ExecuteFlow/ExecuteFlow.ts:                    useSandbox: false

The above files also contain an injection vulnerability into the sandboxed code, due to an improper URL validation check validating the baseURL input. The following code snippets demonstrate the injection vulnerability within AgentAsTool.ts and the broken isValidURL validation function.

https://github.com/FlowiseAI/Flowise/blob/0c6924bb08a2156513b447d0e600651f29ea5aa8/packages/components/nodes/tools/AgentAsTool/AgentAsTool.ts

class AgentAsTool_Tools implements INode {
    ...
    async init(nodeData: INodeData, input: string, options: ICommonObject): Promise<any> {
        ...
        const baseURL = (nodeData.inputs?.baseURL as string) || (options.baseURL as string)

        // Validate agentflowid is a valid UUID
        if (!selectedAgentflowId || !isValidUUID(selectedAgentflowId)) {
            throw new Error('Invalid agentflow ID: must be a valid UUID')
        }

        // Validate baseURL is a valid URL
        if (!baseURL || !isValidURL(baseURL)) { <1>
            throw new Error('Invalid base URL: must be a valid URL')
        }
        ...
    }
}

class AgentflowTool extends StructuredTool {
    ...
    // @ts-ignore
    protected async _call(
        arg: z.infer<typeof this.schema>,
        _?: CallbackManagerForToolRun,
        flowConfig?: { sessionId?: string; chatId?: string; input?: string }
    ): Promise<string> {
        ...
        const code = `
const fetch = require('node-fetch');
const url = "${this.baseURL}/api/v1/prediction/${this.agentflowid}"; <2>

const body = $callBody;

const options = $callOptions;

try {
	const re

Références