n8n HTTP Request Node Pagination Prototype Pollution → Remote Code Execution (CVE-2026-44789)
by Caio Fabrício (BiiTts) · 2026-07-05
- Severity
- Critical
- CVE
- CVE-2026-44789 / GHSA-c8xv-5998-g76h
- Category
- web
- Affected product
- n8n (workflow automation platform)
- Affected versions
- < 1.123.43, 2.0.0-rc.0 … < 2.20.7, 2.21.0 … < 2.22.1
- Disclosed
- 2026-07-05
- Patch status
- patched
Archive entry
intelseclab/poc-archiveMetadata
| Field | Value |
|---|---|
| Date Added | 2026-07-05 |
| Last Updated | 2026-07 |
| Author / Researcher | Caio Fabrício (BiiTts) |
| CVE / Advisory | CVE-2026-44789 / GHSA-c8xv-5998-g76h |
| Category | web |
| Severity | Critical |
| CVSS Score | 9.4 (CVSS 4.0) |
| Status | PoC |
| Tags | n8n, prototype-pollution, rce, node-options, sandbox-escape, task-runner, workflow-automation |
| Related | N/A |
Affected Target
| Field | Value |
|---|---|
| Software / System | n8n (workflow automation platform) |
| Versions Affected | < 1.123.43, 2.0.0-rc.0 … < 2.20.7, 2.21.0 … < 2.22.1 |
| Language / Platform | Node.js / TypeScript (target), Python 3 (PoC) |
| Authentication Required | Yes (workflow create/modify permission) |
| Network Access Required | Yes |
Summary
The n8n HTTP Request node’s pagination feature (updateAParameterInEachRequest mode) allows an attacker-controlled parameter.type value of __proto__, causing paginationData.request[parameter.type][parameterName] = parameterValue to write directly onto Object.prototype — a global prototype pollution in the n8n server process. This repository documents and automates a concrete, verified escalation from that pollution primitive to full remote code execution: polluting Object.prototype.NODE_OPTIONS leaks into the environment of the child node process n8n spawns for its task runner (via Node’s for...in-based environment enumeration in normalizeSpawnArguments), letting the attacker --require an arbitrary local JS file at runner startup and escape the Code-node sandbox entirely.
Vulnerability Details
Root Cause
packages/nodes-base/nodes/HttpRequest/V3/HttpRequestV3.node.ts builds paginationData.request as a plain object and indexes it with an attacker-supplied parameter.type string without guarding against prototype-referencing keys (__proto__, constructor, prototype). Separately, packages/cli/src/task-runners/task-runner-process-js.ts spawns the JS task runner with spawn('node', [...], { env: this.getProcessEnvVars(...) }); Node’s internal normalizeSpawnArguments builds the child’s environment using for (const key in env), which enumerates inherited enumerable properties — so a polluted Object.prototype.NODE_OPTIONS is inherited into the spawned runner’s environment even though it was never explicitly set on the env object. The fix builds paginationData.request with Object.create(null), making ["__proto__"] an ordinary null-proto key instead of the prototype.
Attack Vector
- Authenticated attacker (with workflow create/modify permission) builds a workflow that writes an attacker-controlled
--requirepayload file (e.g./tmp/evil.js) to disk via Set → Convert to File → Read/Write Files nodes. - Attacker dispatches a Code node with an infinite loop (
while(true){}) to hang the JS task runner, forcing an eventual timeout/OOM kill — this must happen before the pollution, since the runner respawn is what will pick up the change. - Attacker triggers the HTTP Request node pagination logic with
parameter.type = "__proto__"andparameterName = "NODE_OPTIONS", pollutingObject.prototype.NODE_OPTIONS = "--require=/tmp/evil.js". - When the hung runner times out, n8n’s runner lifecycle (
onProcessExit → start()) respawns a newnodechild process, which inherits the pollutedNODE_OPTIONSviafor...inenvironment enumeration and--requires the attacker’s file at startup — executing arbitrary code outside the Code-node sandbox, as the n8n service user.
Impact
Any authenticated user able to create or modify a workflow can achieve OS command execution on the n8n host, fully escaping the Code-node sandbox. This compromises the entire automation server, including every credential and downstream system the n8n instance has access to.
Environment / Lab Setup
Target: n8nio/n8n:1.123.42 (Docker image), via lab/docker-compose.yml
N8N_RUNNERS_ENABLED=true (mirrors 2.x default configuration, off by
default in the 1.123.x branch used for the lab)
N8N_RUNNERS_TASK_TIMEOUT lowered only to make the hung-runner respawn
fire faster during testing (not required for
the underlying bug)
Attacker tooling: Python 3 stdlib only (exploit.py), driving the n8n REST API
Proof of Concept
PoC Script
See
exploit.pyin this folder, andlab/docker-compose.ymlfor the target environment.
| |
Running this drives the full chain end-to-end via the n8n REST API (owner setup/login, workflow deployment, and firing the pollution + hang sequence), culminating in live command execution (id/hostname) inside the n8n container as the node service user — proving genuine RCE rather than input echo.
Detection & Indicators of Compromise
- Workflows containing HTTP Request pagination parameters where `type` is
`__proto__`, `constructor`, or `prototype`.
- TypeORM/n8n server logs showing "for...in" / entity-property errors
referencing `NODE_OPTIONS` (a symptom of the pollution breaking workflow
persistence).
- Task runner process restarts immediately followed by unexpected
`--require` flags or unfamiliar child-process command lines.
Signs of compromise:
- Unexpected files (e.g. attacker
--requirepayload scripts) written under/tmpor other writable paths by n8n workflow executions. - n8n task runner (
node) child processes launched with unexplainedNODE_OPTIONS/--requireflags.
Remediation
| Action | Detail |
|---|---|
| Primary fix | Upgrade to n8n >= 1.123.43 / 2.20.7 / 2.22.1, where the pagination request object is built with Object.create(null), preventing the __proto__ write from reaching Object.prototype. |
| Interim mitigation | Restrict workflow create/modify permissions to trusted users only; note that runner hardening flags (--disable-proto=delete, --disallow-code-generation-from-strings) protect the runner process but do not prevent pollution landing in the main n8n process. |
References
Notes
Mirrored from https://github.com/BiiTts/CVE-2026-44789-n8n-PrototypePollution-RCE on 2026-07-05. See ANALYSIS.md in this folder for the full technical writeup of the pollution primitive, Node’s for...in environment-inheritance behavior, the runner lifecycle, and the upstream patch.
| |