Jul 23, 2026·6 min read·2 visits
A shared Node.js process and module cache in n8n's JavaScript task runner allows low-privileged users to dynamically hijack ('monkey-patch') globally imported Node.js and npm modules. This permits cross-tenant data theft and unauthorized execution boundaries breach within multi-user n8n environments.
A module-cache poisoning vulnerability exists in the n8n JavaScript task runner. In multi-tenant or multi-user n8n deployments, custom code executed inside Code nodes shares a single Node.js process and memory space. If custom module loading is enabled via configuration, an authorized user can dynamically patch (monkey-patch) globally cached modules. Subsequent executions of workflows by other tenants or users that load the same module will receive the poisoned reference, resulting in cross-tenant data exposure, credential hijacking, or integrity compromise.
The n8n workflow automation platform features a JavaScript Code node, allowing users to execute custom scripts as part of automated flows. In environments with multi-user configurations, multiple tenants construct and execute workflows within the same instance. To allow complex logic, administrators can enable the loading of built-in Node.js modules or external npm packages using specific environment parameters.
The vulnerability, registered under the identifier GHSA-9cmh-xcqm-5hqr, constitutes a cross-tenant module-cache poisoning flaw. The underlying flaw resides within the execution model of the JS Task Runner, which utilizes a single Node.js process to execute Code nodes from different tenants. Because the process space is shared, the module resolution caching mechanism remains global across distinct workflow execution scopes.
An authenticated user with permissions to create or execute workflows containing a Code node can manipulate shared resources within the process memory space. By monkey-patching methods of globally loaded modules, an attacker is capable of breaking tenant isolation barriers. Consequently, this leads to an isolation compromise affecting subsequent executions of workflows on the same worker process.
The Node.js runtime leverages an internal caching registry, known as require.cache for CommonJS modules, to optimize performance. When a script initiates a require() or import operation, Node.js compiles and executes the file on its initial invocation and caches the resulting exports object. Subsequent requests for the same module bypass disk access and directly return a pointer to the existing cached object.
In the vulnerable architecture of n8n, the JS Task Runner did not instantiate independent, clean virtual machine contexts or isolated processes for each user's execution scope. Instead, code blocks from varying users run inside the same underlying process structure. When an administrator enables module imports using NODE_FUNCTION_ALLOW_BUILTIN or NODE_FUNCTION_ALLOW_EXTERNAL, modules are loaded into this shared Node.js process space.
This architecture creates a shared mutable state. An attacker can write code that intercepts and rewrites properties on returned module exports. Since the runtime supplies the identical reference to any other execution thread inside the same process, the modifications persist globally. This enables unauthorized cross-tenant state interception and dynamic object-prototype manipulation.
To resolve this cache-poisoning vulnerability, the module-loading design within the task runner was redesigned. Rather than allowing standard, shared imports that reference the parent process cache, the execution environment must restrict or fully isolate the module resolution registry for each distinct tenant context.
The remediation introduces context-specific virtual machine sandboxes or distinct process isolations that construct a fresh module loader environment for each run. In isolated contexts, calling require constructs a separate, non-shared instance of the requested module, entirely independent of the parent process's global cache registries. This ensures that any monkey-patching attempts or runtime object modifications affect only the attacker's execution block.
Furthermore, the application of isolated task-running sandboxes ensures that custom functions do not leak references across executions. The patch isolates execution context so that the require loader is either virtualized per execution or process-isolated. This blocks cross-tenant module modification because the module exports are reinstantiated or cloned per execution block.
// Before patch (Vulnerable): Modules are resolved globally
const fs = require('fs');
fs.readFile = newProxyFunction; // Modifies global cache reference
// After patch (Patched): Context-isolated loader
// Inside isolated VM or subprocess:
const vmFs = isolatedRequire('fs');
// Modifications do not escape the tenant's execution contextAn attacker requires network access to an n8n deployment with workflow creation privileges. Additionally, the instance must have module-loading variables NODE_FUNCTION_ALLOW_BUILTIN or NODE_FUNCTION_ALLOW_EXTERNAL enabled. The attacker identifies target modules frequently utilized by other workflows, such as the built-in file system utility fs or HTTP client library axios.
The exploitation flow begins with the injection of a standard monkey-patching payload inside a standard Code node. The payload replaces a targeted method with an interceptor function designed to capture parameters. Once executed, this patch persists in the global memory space of the active runner process.
// Attacker's Code Node payload targeting the 'fs' module
const fs = require('fs');
if (!fs.__poisoned__) {
const originalReadFile = fs.readFile;
// Hijack standard readFile method to intercept parameters
fs.readFile = function(path, options, callback) {
// Intercept data and exfiltrate or log sensitive file access
console.log(`[EXFILTRATION] Intercepted access to file: ${path}`);
// Invoke original function to avoid operational disruption
return originalReadFile.apply(this, arguments);
};
fs.__poisoned__ = true;
}When a victim tenant triggers a workflow utilizing the same module, the victim's execution invokes the hijacked wrapper. The wrapper captures sensitive objects, including system paths, authentication keys, or internal API parameters. The captured data is then transmitted to an attacker-controlled endpoint or stored locally for subsequent retrieval.
The impact of this vulnerability is assessed as Medium, yielding a CVSS score of 5.8. The attack does not result in direct, host-level remote code execution outside the JS sandbox or complete host control. Instead, the core risk lies in the violation of the security boundaries separating individual tenants within the same n8n environment.
In a multi-tenant or shared enterprise instance, this flaw represents a total compromise of internal confidentiality and integrity. Attackers can intercept sensitive customer data, hijack database queries, or capture outbound API tokens. Additionally, because the hijacked code runs within the context of the victim's workflow, it executes with the victim's privileges and service connections.
This vulnerability poses no immediate threat to single-user deployments where tenant isolation boundaries are unnecessary. However, in software-as-a-service (SaaS) structures or shared agency environments, this issue presents a substantial compliance and isolation risk. Organizations must assume that any tenant with execution privileges could read or alter data belonging to other tenants running workflows on the same worker node.
The primary remediation action is to upgrade the n8n application to a patched release. For environments operating under 1.x, deploy version 1.123.67 or higher. For deployments running pre-releases within the 2.x range, upgrade to 2.31.5 or higher. For 2.32.x deployments, upgrade to 2.32.1 or higher.
If an upgrade cannot be executed immediately, administrators must disable custom module imports. This is achieved by unsetting or clearing the relevant environment variables in the runner container configuration. Setting these variables to empty values prevents users from importing built-in or external modules, eliminating the cache-poisoning attack vector:
NODE_FUNCTION_ALLOW_BUILTIN=
NODE_FUNCTION_ALLOW_EXTERNAL=Furthermore, deployments can implement architectural isolation by running external queue-based task workers. By ensuring that task runners are single-use or containerized per user group, the risk of a shared memory space is mitigated. Administrators should also limit workflow-creation privileges strictly to trusted operators.
CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:N/VI:N/VA:N/SC:H/SI:H/SA:H| Attribute | Detail |
|---|---|
| CWE ID | CWE-20 |
| Attack Vector | Network (AV:N) |
| CVSS Score | 5.8 |
| Exploit Status | No Public PoC |
| Impact | Cross-Tenant Information Disclosure / Integrity Compromise |
| Privileges Required | Low (PR:L) |
An authenticated SQL injection vulnerability (CWE-89) in n8n's PostgresTrigger node allows users with workflow creation or modification privileges to inject arbitrary SQL statements. Because n8n dynamically constructs database administration and event subscription queries by directly interpolating user-controlled parameters—such as PostgreSQL channel, function, and trigger names—without sanitization or identifier quoting, attackers can execute arbitrary queries within the context of the configured database credentials, potentially leading to unauthorized data exposure, system tampering, or remote code execution.
A SQL Injection vulnerability exists in the n8n Snowflake node's executeQuery operation. The vulnerability is caused by improper neutralization of expressions interpolated directly into database query strings. When raw Snowflake queries are built using untrusted external data without parameterization, an attacker can execute arbitrary SQL commands on the subsequent Snowflake database instance.
Eclipse Jetty is subject to an uncontrolled resource consumption vulnerability in its HTTP connection handling component. When processing certain HTTP request sequences, such as those invoking the Expect: 100-Continue handshake under specific network constraints, the server fails to return allocated buffers to its central pool. Over time, this leads to buffer pool exhaustion and a complete denial of service via memory starvation.
CVE-2026-65595 is a high-severity privilege escalation vulnerability in the Token Exchange module of the n8n visual workflow automation platform. Due to an validation omission, the system unconditionally maps all Public API scopes to session tokens exchanged through trusted Identity Providers, entirely bypassing user-specific role checks.
A critical DOM-based Cross-Site Scripting (XSS) vulnerability exists in n8n's workflow editor HTML preview component. By failing to include a sandbox attribute on the iframe used to display node execution output, n8n allowed rendered execution outputs to run arbitrary JavaScript within the same-origin context of the editor parent window. This vulnerability can be exploited by an attacker with low-privileged ('global:member') access to hijack an authenticated administrator's session and perform unauthorized API actions.
A Stored DOM-based Cross-Site Scripting (XSS) vulnerability exists within the frontend Resource Locator component of n8n. The flaw stems from insecure usage of window.open() where the application evaluates the workflow-persisted parameter 'cachedResultUrl' without verifying its protocol scheme. Authenticated attackers with permissions to create or edit workflows can insert a 'javascript:' URI payload, leading to arbitrary code execution in the victim's browser context upon interaction.