How to Fix n8n CVE-2026-44791: Patch the XML Node Prototype Pollution Bypass
Introduction
If you self-host n8n, there is a critical patch you need to apply. In May 2026, n8n published security advisory GHSA-wrwr-h859-xh2r for CVE-2026-44791, an XML node prototype pollution bypass rated CVSS 4.0 9.4 Critical. An authenticated user with permission to create or modify workflows can dodge the earlier XML node fix and, combined with other nodes, reach remote code execution on the n8n host. This guide walks you through checking whether your instance is vulnerable, applying the emergency workaround, upgrading on Docker and npm, locking down permissions, and verifying the fix. It is written for anyone who runs their own n8n, from a single Docker container on a VPS to a multi-worker queue mode cluster. If you installed n8n with our Ubuntu VPS install guide, start at Step 1.
Quick answer
Upgrade self-hosted n8n to 1.123.43, 2.20.7, or 2.22.1 to fix CVE-2026-44791, an XML node prototype pollution bypass (CVSS 9.4) that enables RCE. If you cannot upgrade now, disable the XML node with NODES_EXCLUDE=n8n-nodes-base.xml.
Evidence
Start with what the vendor itself says. n8n’s official advisory for GHSA-wrwr-h859-xh2r states: “An authenticated user with permission to create or modify workflows could bypass the patch for GHSA-hqr4-h3xv-9m3r in the XML node. When combined with other nodes, this could lead to RCE on the n8n host.” That sentence defines both the precondition and the stakes: the attacker must already be a logged-in user with workflow edit rights, but the payoff is code execution on the machine that runs your automations. The advisory’s own workaround is equally direct: “Disable the XML node by adding n8n-nodes-base.xml to the NODES_EXCLUDE environment variable.” Both quotations come from the official GitHub security advisory for GHSA-wrwr-h859-xh2r, which also lists the fixed releases: 1.123.43, 2.20.7, and 2.22.1.
The severity is not vendor hype. CVE databases list CVE-2026-44791 at CVSS 4.0 9.4 Critical, and n8n’s advisory publishes the CVSS 3.1 vector AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H, which describes a network-exploitable, low-complexity flaw with full confidentiality, integrity, and availability impact. Full vector details are mirrored on the StackFlag CVE-2026-44791 page.
The exposure surface is large because self-hosted n8n is popular and often internet-facing. The n8n repository held 204,949 GitHub stars as of the 17 September 2026 GitHub trending archive. Censys data reported by The Hacker News in January 2026 counted 26,512 publicly exposed n8n hosts, and the Obstracts “OverDoS” research blog estimated more than 70,000 Shodan-visible instances around June 2026. Those two exposure figures date from earlier vulnerability waves, not from CVE-2026-44791 specifically, but they show how many self-hosted instances sit on the public internet. A Cyera researcher summed up why that matters, as quoted by The Hacker News: “A compromised n8n instance doesn’t just mean losing one system — it means handing attackers the keys to everything.” Your n8n holds API keys, database credentials, and OAuth tokens for every connected service, which is why a workflow-editor RCE is a crown-jewels problem. The earlier flaw this bypasses, GHSA-hqr4-h3xv-9m3r (CVE-2026-42232), was fixed in 1.123.32, 2.17.4, and 2.18.1, so if your version sits between that fix and the new one, you patched once and are still exposed.
Prerequisites
- A self-hosted n8n instance you administer (Docker Compose, plain Docker, or npm install). n8n Cloud users are patched by n8n and can skip this guide.
- Shell access to the machine running n8n, or access to its docker-compose.yml.
- A backup of your workflows and credentials. If you do not have one, follow our n8n update guide’s backup section before touching anything.
- About 15 minutes of maintenance window. The upgrade itself takes under five; verification takes the rest.
Step 1: Check whether your instance is vulnerable
You are vulnerable if your version is below the fixed release on your line: anything before 1.123.43 on the 1.x line, before 2.20.7 on the 2.20.x line, or before 2.22.1 on the 2.22.x line. Check three ways and trust the lowest number you find.
In the editor, open Settings, then About. The version is shown at the top. On the command line, run:
n8n --version
On Docker Compose, run it inside the container so you see the running image, not the host:
docker compose exec n8n n8n --version
Then open your docker-compose.yml and read the image tag:
services:
n8n:
image: n8nio/n8n:2.20.4
If the tag is pinned to a specific vulnerable release, as in the example above, the container will stay vulnerable no matter how many times you restart it. The tag is the truth about what will run after your next deploy, so update it as part of Step 3. If the compose file layout is unfamiliar, our n8n Docker Compose setup guide explains each service block before you edit it.
Step 2: Apply the emergency workaround if you cannot patch today
If your maintenance window is days away, do not leave the vulnerable code reachable. The advisory’s workaround removes the XML node from the instance entirely:
services:
n8n:
image: n8nio/n8n:2.20.4
environment:
- NODES_EXCLUDE=n8n-nodes-base.xml
This is the documented behavior of the NODES_EXCLUDE variable, which the n8n environment variables reference describes as the way to exclude specific nodes from loading. For an npm install, export it before starting n8n:
export NODES_EXCLUDE=n8n-nodes-base.xml
n8n start
Then recreate the container and confirm the node is gone:
docker compose up -d n8n
Open the editor, add a node, and search for “XML”. It should not appear. Any workflow that uses the XML node will now fail because its node type is no longer registered, so audit first: search your workflows for XML nodes and decide which ones can wait for the real patch and which need a temporary replacement, such as a Code node doing the parsing. Keep a note of this change, because Step 6 removes it after the upgrade.
While the workaround is active, tighten the other half of the attack precondition. CVE-2026-44791 requires an authenticated user with workflow create or modify rights. Review your members list and demote anyone who does not need editor access. Fewer people who can edit workflows means fewer accounts an attacker can abuse.
Step 3: Upgrade on Docker Compose
This is the path most self-hosted users take, and it mirrors the safe-upgrade procedure from our n8n update guide. Back up first, then update the image tag to a fixed release. If you pin versions, set it explicitly:
services:
n8n:
image: n8nio/n8n:2.22.1
If you track a floating tag, you can keep it, but an explicit fixed version removes all doubt about what you deployed. Remove the NODES_EXCLUDE line you added in Step 2 at the same time, so the XML node comes back after the patch. Then pull and recreate:
docker compose pull n8n
docker compose up -d n8n
Watch the startup logs for database migrations:
docker compose logs -f n8n
A clean start ends with the editor reachable on your usual port. If you run queue mode, this step has a trap: the main instance and every worker must run the identical image version. Pull and recreate everything, not just the main service:
docker compose pull
docker compose up -d
Then confirm every container reports the new version with docker compose ps and a spot check of one worker’s logs. Our queue mode scaling guide covers the multi-service layout if you need a refresher on which containers belong to the cluster.
Step 4: Upgrade on npm
If you installed n8n with npm, the upgrade is one command, run as the same user that owns the install:
npm update -g n8n
Restart the n8n process afterward. How you restart depends on how you run it: pm2 restart n8n under PM2, systemctl restart n8n under systemd, or Ctrl+C and n8n start in a terminal session. If you exported NODES_EXCLUDE in Step 2, unset it before restarting so the XML node loads again:
unset NODES_EXCLUDE
n8n start
Verify the new version with n8n --version and confirm it is at or above 1.123.43, 2.20.7, or 2.22.1 depending on your line.
Step 5: Lock down workflow permissions
Patching closes the hole, but the advisory’s attack precondition is worth hardening permanently. An n8n instance where every member can edit every workflow gives any compromised account the keys to the RCE chain. In the editor, go to the members or users section and apply least privilege: viewers get view-only roles, and only the people who actually build automations keep editor rights on production workflows. Rotate any credentials you suspect were exposed while the instance was vulnerable, especially service accounts whose tokens appear in workflow credentials. If your database runs alongside n8n in Compose, our n8n Postgres tutorial covers safe backup and restore of the data layer too. This step costs ten minutes and shrinks the blast radius of the next vulnerability, whatever it turns out to be.
Step 6: Verify the patch
Verification has three parts, and all three are cheap.
First, confirm the running version. Use the editor’s Settings, About page and the CLI together, because the UI can be cached by your browser while the CLI reads the running process:
docker compose exec n8n n8n --version
The output must show a release at or above the fixed version for your line.
Second, confirm the XML node is back if you disabled it. Remove NODES_EXCLUDE from your compose file or environment, recreate the container, and search for the XML node in the editor. It should appear again, and a simple XML parse workflow should execute normally.
Third, run an optional regression check for the vulnerability class. Create a workflow with an XML node set to the Parse operation and feed it this document:
<root><__proto__><polluted>true</polluted></__proto__></root>
Follow it with a Code node in “Run Once for All Items” mode containing:
if (({}).polluted !== undefined) {
throw new Error("Prototype pollution detected: instance may still be vulnerable");
}
return [{ json: { patched: true } }];
On a patched instance the workflow succeeds and returns patched: true, because the hardened parser no longer merges __proto__ keys into Object.prototype. This check does not reproduce the original exploit chain; it verifies the parser behavior the advisory’s patch hardens. If it throws, your instance is not on the fixed build, and you should repeat Steps 3 or 4.
Troubleshooting
Workflows fail after adding NODES_EXCLUDE. This is expected, not a bug. Excluded nodes are not registered, so any workflow containing an XML node errors when it reaches that step. Either remove the mitigation after upgrading, which restores the node, or replace the XML step with a Code node that parses the document. Our Code node JavaScript guide shows the patterns you need for a quick replacement.
npm update fails with EACCES permission errors. This happens when the global npm prefix is owned by a different user than the one running the update, typically after installing n8n with sudo but updating without it. Do not run the update with sudo as a habit; instead, run it as the user that owns the install, or fix the prefix ownership once with sudo chown -R $(whoami) $(npm config get prefix), then rerun npm update -g n8n.
Docker still runs the old version after docker compose up -d. Your compose file pins the image tag to a vulnerable release, so Compose correctly recreates the same old image. Edit the image: line to a fixed version, such as n8nio/n8n:2.22.1, then run docker compose pull n8n followed by docker compose up -d n8n. Verify with docker compose exec n8n n8n --version, not just by reading the file.
Queue mode workers still show the old version. You upgraded the main service but not the workers, leaving a mixed-version cluster where vulnerable code still executes jobs. Run docker compose pull with no service filter and docker compose up -d to recreate every service from the new image, then spot-check a worker container’s version the same way you checked the main one.
n8n will not start after the upgrade. Stop and restore from the backup you took in Prerequisites, then investigate on a staging copy: the usual culprits are a database migration that needs more disk space or an environment variable that a newer version renamed. Never debug a failed production upgrade by repeatedly restarting the live container; restore first, then reproduce the failure somewhere safe. The rollback procedure is covered in our n8n update guide.
Conclusion
CVE-2026-44791 is a reminder that patching once is not patching done: the May fix for CVE-2026-42232 was bypassed, and only 1.123.43, 2.20.7, and 2.22.1 close the hole. Check your version today, use NODES_EXCLUDE=n8n-nodes-base.xml if the upgrade must wait, upgrade every node in the cluster to a fixed release, and verify with the version check and the __proto__ regression test. Then keep the habit: subscribe to n8n’s security advisories and treat every self-hosted upgrade as a scheduled task, not a reaction. For the full safe-upgrade routine with backups and rollbacks, read How to Update n8n Self-Hosted next.
Frequently asked questions
Am I affected by CVE-2026-44791 if I use n8n Cloud?
No. n8n patches its Cloud fleet directly, so Cloud users do not need to take any action. CVE-2026-44791 only affects self-hosted n8n instances running 1.123.42 or earlier, 2.20.6 or earlier, or 2.22.0 or earlier. If you are unsure which plan you are on, check Settings, then About in the editor: Cloud instances show a managed badge and no local version you control.
Was this not already fixed back in May as CVE-2026-42232?
CVE-2026-42232 (GHSA-hqr4-h3xv-9m3r) fixed the original XML node prototype pollution in versions 1.123.32, 2.17.4, and 2.18.1. CVE-2026-44791 is a bypass of that exact patch: an authenticated user with workflow edit rights found a way around the first fix. Patching for the May advisory does not protect you; you must upgrade again to 1.123.43, 2.20.7, or 2.22.1.
Is disabling the XML node with NODES_EXCLUDE enough if I cannot upgrade this week?
It is the workaround n8n's own advisory prescribes, and it removes the vulnerable code path entirely, which is stronger than a partial upgrade. Pair it with tightened workflow permissions so only trusted members can create or modify workflows, and treat it as temporary: schedule the real upgrade, because a disabled node breaks any workflow that depends on XML parsing.
Will disabling the XML node break my existing workflows?
Only workflows that actually use the XML node. Those workflows will fail because the node type is no longer registered. Search your instance for XML nodes before applying the mitigation, and plan replacements, such as a Code node with a small parser, for any production workflow that cannot wait for the upgrade.
Which exact version should I upgrade to?
Match your current release line: 1.123.43 or later on the 1.x line, 2.20.7 or later on the 2.20.x line, or 2.22.1 or later on the 2.22.x line. In practice, upgrading to the latest stable release is simplest and picks up every fix at once. Always check the release notes for breaking changes before jumping major lines.
How do I confirm the patch actually worked?
Check the version three ways: the editor's Settings, About page, the CLI command n8n --version, and the image tag in your docker-compose.yml. The running version must be at or above the fixed release for your line. Then remove NODES_EXCLUDE if you used it, restart, and confirm the XML node is available again. Optionally run the __proto__ regression check in Step 6.