# [CRIT] [GHSA / CRITICAL] CVE-2026-44789: n8n: HTTP Request Node Pagination Prototype Pollution to RCE

**Source:** GitHub Security Advisories
**Published:** 2026-05-14
**Article:** https://github.com/advisories/GHSA-c8xv-5998-g76h

## Threat Profile

n8n: HTTP Request Node Pagination Prototype Pollution to RCE

## Impact
An authenticated user with permission to create or modify workflows could achieve global prototype pollution via an unvalidated pagination parameter in the HTTP Request node. Combined with other techniques this could lead to RCE on the instance.

## Patches
The issue has been fixed in n8n versions 1.123.43, 2.20.7, and 2.22.1. Users should upgrade to one of these versions or later to remediate the vulnerability.

## Workarou…

## Indicators of Compromise (high-fidelity only)

- **CVE:** `CVE-2026-44789`

## MITRE ATT&CK Techniques

- **T1190** — Exploit Public-Facing Application
- **T1059.007** — Command and Scripting Interpreter: JavaScript
- **T1059** — Command and Scripting Interpreter
- **T1059.001** — PowerShell
- **T1059.004** — Unix Shell
- **T1592.002** — Gather Victim Host Information: Software

## Kill chain phases observed

_(none detected from narrative keywords)_

## Recommended hunts

### n8n workflow API request body containing JS prototype pollution tokens (CVE-2026-44789)

`UC_301_1` · phase: **exploit** · confidence: **High** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats `summariesonly` count min(_time) as firstTime max(_time) as lastTime values(Web.url) as url values(Web.http_method) as http_method values(Web.src) as src from datamodel=Web.Web where Web.url="*/rest/workflows*" OR Web.url="*/rest/executions*" OR Web.url="*/webhook*" by Web.dest Web.user Web.http_user_agent | `drop_dm_object_name(Web)` | search url="*__proto__*" OR url="*constructor.prototype*" OR url="*__defineGetter__*" OR url="*prototype%5B*" | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
```

**Defender KQL:**
```kql
let LookbackDays = 7d;
let PollutionTokens = dynamic(["__proto__", "constructor.prototype", "__defineGetter__", "prototype[", "%5F%5Fproto%5F%5F", "%5Fproto%5F"]);
DeviceNetworkEvents
| where Timestamp > ago(LookbackDays)
| where RemotePort in (5678, 443, 80) or LocalPort in (5678, 443, 80)
| where InitiatingProcessFileName has_any ("node.exe", "n8n.exe")
   or InitiatingProcessCommandLine has "n8n"
| where RemoteUrl has_any (PollutionTokens)
    or InitiatingProcessCommandLine has_any (PollutionTokens)
| project Timestamp, DeviceName, RemoteIP, RemoteUrl, LocalPort, RemotePort,
          InitiatingProcessFileName, InitiatingProcessCommandLine,
          InitiatingProcessAccountName, InitiatingProcessFolderPath
| order by Timestamp desc
```

### Post-exploit RCE: node.js (n8n) spawning shell or scripting interpreter

`UC_301_2` · phase: **install** · confidence: **High** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| tstats `summariesonly` count min(_time) as firstTime max(_time) as lastTime values(Processes.process) as process values(Processes.process_path) as process_path from datamodel=Endpoint.Processes where Processes.parent_process_name IN ("node.exe","node") (Processes.process_name IN ("cmd.exe","powershell.exe","pwsh.exe","sh","bash","zsh","dash","mshta.exe","wscript.exe","cscript.exe","rundll32.exe","regsvr32.exe","certutil.exe","bitsadmin.exe","curl.exe","wget.exe")) by Processes.dest Processes.user Processes.parent_process Processes.parent_process_name Processes.process_name Processes.process_path | `drop_dm_object_name(Processes)` | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`
```

**Defender KQL:**
```kql
let LookbackDays = 7d;
let ShellsAndLolbins = dynamic(["cmd.exe","powershell.exe","pwsh.exe","sh","bash","zsh","dash","mshta.exe","wscript.exe","cscript.exe","rundll32.exe","regsvr32.exe","certutil.exe","bitsadmin.exe","curl.exe","wget.exe","nc","ncat","socat"]);
DeviceProcessEvents
| where Timestamp > ago(LookbackDays)
| where InitiatingProcessFileName in~ ("node.exe","node")
| where InitiatingProcessCommandLine has_any ("n8n", "\\n8n\\", "/n8n/")
   or InitiatingProcessFolderPath has_any ("n8n", "\\.n8n\\")
| where FileName in~ (ShellsAndLolbins)
| where AccountName !endswith "$"
| project Timestamp, DeviceName, AccountName, AccountDomain,
          ParentImage = InitiatingProcessFolderPath,
          ParentCmd = InitiatingProcessCommandLine,
          ChildImage = FolderPath,
          ChildCmd = ProcessCommandLine,
          SHA256
| order by Timestamp desc
```

### Vulnerable n8n versions in TVM inventory (CVE-2026-44789)

`UC_301_3` · phase: **recon** · confidence: **High** · AI-generated for this article

**Splunk SPL (CIM):**
```spl
| inputlookup assets_software | where like(software_name,"%n8n%") | rex field=software_version "(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)" | eval major=tonumber(major), minor=tonumber(minor), patch=tonumber(patch) | eval vulnerable=case( major==1 AND (minor<123 OR (minor==123 AND patch<43)), "yes-1.x", major==2 AND minor>=0 AND minor<=19, "yes-2.0-2.19", major==2 AND minor==20 AND patch<7, "yes-2.20.<7", major==2 AND minor==21, "yes-2.21", major==2 AND minor==22 AND patch<1, "yes-2.22.0", true(), "no") | where vulnerable!="no" | table host software_name software_version vulnerable
```

**Defender KQL:**
```kql
DeviceTvmSoftwareInventory
| where SoftwareName =~ "n8n" or SoftwareName has "n8n"
| extend Parts = split(SoftwareVersion, ".")
| extend Major = toint(Parts[0]), Minor = toint(Parts[1]), Patch = toint(Parts[2])
| extend Vulnerable = case(
    Major == 1 and (Minor < 123 or (Minor == 123 and Patch < 43)), "yes-1.x (<1.123.43)",
    Major == 2 and Minor >= 0 and Minor <= 19, strcat("yes-2.", tostring(Minor), " (<2.20.7)"),
    Major == 2 and Minor == 20 and Patch < 7, "yes-2.20.<7",
    Major == 2 and Minor == 21, "yes-2.21 (<2.22.1)",
    Major == 2 and Minor == 22 and Patch < 1, "yes-2.22.0",
    "no")
| where Vulnerable != "no"
| join kind=leftouter (DeviceInfo | summarize arg_max(Timestamp, *) by DeviceId | project DeviceId, IsInternetFacing, OSPlatform) on DeviceId
| project DeviceName, DeviceId, SoftwareVendor, SoftwareName, SoftwareVersion, Vulnerable, IsInternetFacing, OSPlatform
| order by IsInternetFacing desc, DeviceName asc
```

### IOC-driven hunts (use shared templates)

These are standard IOC-substitution hunts — the canonical SPL and KQL live once in [`_TEMPLATES.md`](../_TEMPLATES.md), so we don't repeat the same boilerplate on every CVE / hash / network-IOC briefing.

- **Asset exposure — vulnerability matches article CVE(s)** ([template](../_TEMPLATES.md#asset-exposure)) — phase: **recon**, confidence: **High**
  - CVE(s): `CVE-2026-44789`


## Why this matters

Severity classified as **CRIT** based on: CVE present, 4 use case(s) fired, 6 technique(s) inferred. Read the full article for actor attribution, tooling details, and any defanged IOCs in the body that aren't visible in the RSS summary.
