Feb 26, 2026·7 min read·10 visits
A critical RCE in n8n's Merge node allows authenticated users to execute arbitrary code via malicious SQL queries. The flaw stems from the AlaSQL engine escaping the sandbox.
n8n, the popular workflow automation tool that connects everything to everything, recently discovered it had connected its internal server shell to authenticated users. CVE-2026-27497 is a critical RCE vulnerability residing in the Merge node's SQL mode. By leveraging the AlaSQL engine—a library that brings the chaos of SQL to the flexibility of JavaScript—attackers could bypass n8n's sandbox and execute arbitrary code or write files to the underlying server. It’s a classic case of 'feature creep' turning into 'security breach,' allowing anyone with workflow permissions to turn the automation server into their personal playground.
In the world of low-code automation, n8n is the heavy lifter. It’s the glue that holds together your Slack, AWS, and database infrastructure. But as any engineer knows, the more powerful the tool, the sharper the edges. Enter the Merge Node. Its job is simple: take data from Input A, data from Input B, and mash them together. To make this even more 'flexible,' the developers introduced SQL Mode, powered by a library called AlaSQL.
AlaSQL is an open-source SQL database for JavaScript. It’s incredibly cool—it lets you run full SQL queries on JSON objects in memory. However, AlaSQL is also notoriously permissive. It treats JavaScript functions as first-class citizens within SQL queries. Do you see where this is going? n8n essentially wrapped a feature that says 'Run this SQL' around an engine that says 'Sure, I can also run this JavaScript code and write these files to disk while I'm at it.'
For a hacker, this is the holy grail. We aren't just looking for a SQL Injection to dump a database table; we are looking for a way to break out of the data plane and into the control plane. By exposing AlaSQL directly to user input, n8n didn't just open a window; they installed a doggy door for attackers to crawl through and start executing shell commands on the host server.
The root cause of CVE-2026-27497 isn't a simple buffer overflow; it's a logic flaw in trust boundaries. n8n implements a sandbox to prevent user-defined expressions from wrecking the server. They know that users will write JavaScript in their workflows, so they try to contain it. However, the implementation of the SQL Merge mode failed to realize just how 'meta' AlaSQL is. The engine supports syntax that allows for the definition and execution of JavaScript functions inside the SQL query string, effectively bypassing the initial layer of expression sandboxing.
The vulnerability, flagged as CWE-94 (Code Injection) and CWE-89 (SQL Injection), arises because the input validation sanitizing the SQL query didn't account for AlaSQL's advanced features. Specifically, AlaSQL allows for SELECT ... INTO syntax which can write files, and it allows for user-defined functions (UDFs) that execute in the context of the application.
Think of it like this: n8n built a prison cell (the sandbox) and put the prisoner (the user input) inside. But then they gave the prisoner a magic wand (AlaSQL) that can conjure keys. The sandbox checks if the prisoner is trying to pick the lock, but it doesn't check if the prisoner is casting a spell to teleport out. The failure here was assuming that the SQL engine would behave like a strict database, rather than a dynamic JavaScript interpreter.
The remediation for this vulnerability was not a one-line fix. It required a scorched-earth approach to the JavaScript execution environment. Analyzing the git history, specifically commits 49d7e160287556e65d7daf754bd155095b7738d5 and e9e2456708c8025151e5a9f3096f589a87be241f, we see a massive overhaul in packages/workflow/src/expression-sandboxing.ts.
The developers had to implement what is essentially a 'global freeze.' In previous versions, the sandbox context might have looked something like this (simplified):
// Vulnerable Context Setup
const context = vm.createContext({
require: () => { throw new Error('No require allowed') },
// ... other mocks
});
vm.runInContext(userCode, context);The problem is that complex objects passed into the context often retain references to their constructors. If you have access to {} (an object), you have access to Object, and from there Object.constructor, and eventually you might find a way to Function constructor to compile new code.
The fix involved over 200 lines of code dedicated to locking down these prototypes. They implemented a deep freeze on global objects within the execution realm. Furthermore, in packages/nodes-base/nodes/Merge/v3/actions/mode/combineBySql.ts, they explicitly blacklisted dangerous AlaSQL keywords. The patch essentially says: 'If the query contains INTO, ATTACH, Use, or Load, kill it with fire.'
So, how do we weaponize this? We need an authenticated user account, but in many organizations, n8n access is shared or loosely guarded. Once in, we create a new Workflow, drag in a Merge Node, and switch the mode to SQL Query.
In a standard SQL injection, you might try ' OR 1=1 --. Boring. Here, we are speaking AlaSQL. We can define a JavaScript function directly in the query and execute it. The goal is to escape the Node.js sandbox and access the child_process module to run system commands.
Here is a conceptual payload that demonstrates the RCE. This payload abuses the VALUE modifier in AlaSQL to evaluate a closure:
SELECT VALUE (function(){
// We are now inside a JS execution context managed by AlaSQL
// Attempt to leverage the host's process binding if not properly stripped
const process = this.constructor.constructor('return this.process')();
process.mainModule.require('child_process').exec('id > /tmp/pwned.txt');
return 'Command Executed';
})()
FROM ?If the direct child_process access is blocked, an attacker might pivot to the Arbitrary File Write vector using AlaSQL's export features:
SELECT * INTO CSV('/app/static/shell.js') FROM ?By writing a malicious JS file to a directory served by the web application, the attacker can then simply browse to https://n8n.target/static/shell.js (or trigger it via another node) to achieve execution. It is a dual-threat vector: direct memory corruption via JS or persistence via filesystem.
Why should you panic? Because n8n is the keeper of the keys. By design, n8n stores credentials for everything it automates: AWS Access Keys, Stripe API tokens, Slack Webhooks, Database connection strings, and SSH keys. It is a central repository of secrets.
Successfully exploiting CVE-2026-27497 gives an attacker Code Execution on the n8n server. This means they can:
This isn't just 'the server crashed.' This is 'we need to rotate every credential in the company and call legal.'
If you are running n8n versions < 1.123.22, 2.0.0 through 2.9.2, or 2.10.0, you are vulnerable. The fix is straightforward: Update immediately. The patched versions (1.123.22, 2.9.3, 2.10.1) introduce the necessary sandbox hardening.
If you cannot update right now (perhaps you enjoy living dangerously), you have two partial mitigations:
NODES_EXCLUDE environment variable to disable the vulnerable component entirely. Set NODES_EXCLUDE=n8n-nodes-base.merge. Note that this will break any workflow using this node, which is likely all of them.For the long term, security teams should treat low-code platforms like n8n as critical infrastructure. They are not just 'tools'; they are privileged identity providers.
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| Product | Affected Versions | Fixed Version |
|---|---|---|
n8n n8n | < 1.123.22 | 1.123.22 |
n8n n8n | >= 2.0.0, < 2.9.3 | 2.9.3 |
n8n n8n | >= 2.10.0, < 2.10.1 | 2.10.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-94 (Code Injection) |
| CVSS v4.0 | 9.4 (Critical) |
| Attack Vector | Network (Authenticated) |
| Impact | Remote Code Execution (RCE) |
| Affected Component | Merge Node (v3) - SQL Mode |
| Engine | AlaSQL |
Improper Control of Generation of Code ('Code Injection')