n8n Node Security Hardening: Environment Variables & Self‑Host Config


⚡ n8n Workflow Automation
T3 · Self‑Host Security Hardening

n8n Node Security Hardening: Environment Variables & Self‑Host Config
Part of the n8n Node Security Hub

Securing a self‑hosted n8n instance demands layered hardening across six
dimensions: authentication, code execution isolation, file‑access
restrictions, network‑layer controls, container‑level configurations, and
audit monitoring. n8n 2.0 locked down defaults that were previously
permissive—Code nodes can no longer access process.env,
ExecuteCommand and LocalFileTrigger nodes are disabled by default, and
Task Runners now provide process‑level isolation for code execution
[1].
This guide provides the definitive hardening blueprint used by
production teams.

4
Critical CVEs (2026) [2]

≥2.10.1
Hardened Release [2]

6
Hardening Dimensions [3]

v2.0
Security‑by‑Default Epoch [4]

⚠️ 2026 Threat Landscape: Four critical CVEs were
disclosed in early 2026 — CVE‑2026‑21858 (Ni8mare), CVE‑2026‑25115,
CVE‑2026‑25049, and CVE‑2026‑27494 — all targeting Code‑node sandbox
escapes that can lead to full host compromise. Upgrade to n8n
≥ 2.10.1
(or ≥ 1.123.22 for 1.x LTS) and apply every
hardening layer described in this guide.
Dimension Key Environment Variables What It Protects Since
Authentication N8N_BASIC_AUTH_ACTIVE, N8N_BASIC_AUTH_USER, N8N_BASIC_AUTH_PASSWORD Editor UI + REST API v0.x
Code Isolation N8N_BLOCK_ENV_ACCESS_IN_NODE, NODES_EXCLUDE, N8N_RUNNERS_ENABLED Prevents RCE, credential leaks, file access v2.0
File Access N8N_RESTRICT_FILE_ACCESS_TO, N8N_BLOCK_FILE_ACCESS_TO_N8N_FILES Prevents arbitrary file read/write on host v2.0
Network N8N_PROXY_HOPS, N8N_HOST, N8N_PROTOCOL HTTPS enforcement, reverse proxy trust, correct webhook URLs v0.x
Container N8N_PAYLOAD_SIZE_MAX, pinned image tags, read_only rootfs DoS protection, reproducible deployments, immutable containers v0.x
Audit EXECUTIONS_DATA_SAVE_ON_SUCCESS, N8N_LOG_LEVEL Execution history, debug logs for incident investigation v0.x

How do you enable Basic Auth as the minimum authentication layer for n8n?

Set three environment variables: N8N_BASIC_AUTH_ACTIVE=true,
N8N_BASIC_AUTH_USER=admin, and
N8N_BASIC_AUTH_PASSWORD=your-secure-password. After restart,
any request to the n8n editor UI or REST API prompts a browser
authentication dialog. This is the recommended minimum security baseline
before exposing n8n to the internet, and it is lightweight enough that it
does not interfere with workflows or webhook operations.
[5]

Basic Auth protects the editor and API only—it does not
secure webhook endpoints. Webhooks stay public so external services
(Stripe, Slack, GitHub) can call them; you must secure webhooks separately
using HMAC signatures, API keys, or custom validation logic inside the
workflow [5]. Always
combine Basic Auth with HTTPS (via Nginx or Caddy) because credentials
are transmitted with every request. For Docker deployments, these
variables go in the .env file or directly in the
docker-compose.yml. Never commit Basic Auth credentials to
git; store them in a secrets manager or environment file excluded from
version control. For the complete webhook security hardening guide,
see the
n8n Webhook Node Security guide.

How do Task Runners and NODES_EXCLUDE prevent Code‑node sandbox escapes?

Task Runners provide process‑level isolation for Code
nodes. In internal mode (default), the Task Runner runs
as a separate Node.js process spawned by the main n8n process—providing
some isolation but still on the same host. In external mode,
the Task Runner runs in a dedicated sidecar container using the separate
n8nio/runners Docker image, completely isolated from the main
n8n process [6].

For defense‑in‑depth, combine Task Runners with
NODES_EXCLUDE to block high‑risk nodes entirely. The
critical configuration pattern:
NODES_EXCLUDE=["n8n-nodes-base.executeCommand","n8n-nodes-base.localFileTrigger","n8n-nodes-base.code"]
disables shell execution, arbitrary file access, and the Code node
respectively. If you must keep Code nodes enabled, at minimum
set N8N_RUNNERS_ENABLED=true with
N8N_RUNNERS_MODE=external so Python/JavaScript code executes
in the isolated sidecar [6]. Four
2026 CVEs exploited Pyodide or internal‑mode sandbox escapes to achieve
remote code execution; all were mitigated by upgrading and switching to
external Task Runners. For the complete CVE mitigation
strategy, see the
Webhook Node Security guide.

🔒 Code Isolation Decision Tree: (1) Can you disable
Code nodes entirely? → Add n8n-nodes-base.code to
NODES_EXCLUDE. (2) Must you run Code nodes? → Enable Task
Runners in external mode: N8N_RUNNERS_ENABLED=true,
N8N_RUNNERS_MODE=external, and deploy the
n8nio/runners sidecar image. (3) Also set
N8N_BLOCK_ENV_ACCESS_IN_NODE=true to prevent credential
leakage through process.env [1].

How do you restrict file access and environment variable exposure in Code nodes?

n8n 2.0 locked down file access by default: workflows can only access
~/.n8n-files unless N8N_RESTRICT_FILE_ACCESS_TO
explicitly allows another directory. Set this to a dedicated, empty
directory containing no sensitive data. Keep
N8N_BLOCK_FILE_ACCESS_TO_N8N_FILES=true (the default) to
block Code nodes from reading the .n8n config directory
where encryption keys and credentials are stored [7].

Setting N8N_BLOCK_ENV_ACCESS_IN_NODE=true (default in v2.0)
prevents Code nodes from accessing process.env—a critical
security win that stops workflows from reading database passwords, SMTP
credentials, encryption keys, and cloud provider keys [4]. If a
workflow genuinely needs an environment variable value, pass it
explicitly as an input parameter: add a Set node before the Code node
that reads $env:MY_API_KEY and passes it as a JSON field.
This pattern keeps control in your hands and never exposes environment
variables to the Code node. For database password protection, use
the _FILE suffix notation—Docker Compose mounts a
secrets file, and n8n reads the password from the file rather than
from an environment variable [8]. For the
complete environment variable and secrets management guide, see the
n8n Credential Nodes guide.

How do you configure Nginx or Caddy as a reverse proxy for HTTPS and secure WebSocket connections?

A reverse proxy sits between the internet and n8n, terminating HTTPS
and forwarding traffic to localhost:5678. For production
with Nginx, configure a server block listening on port 443,
proxy to http://n8n:5678, and forward four critical headers:
Host $host, X-Forwarded-Proto $scheme,
X-Forwarded-For $proxy_add_x_forwarded_for, and
X-Real-IP $remote_addr [9].

For WebSocket support (required for the n8n editor live‑reload
and real‑time execution monitoring), add
proxy_set_header Upgrade $http_upgrade; and
proxy_set_header Connection "upgrade";. Set
proxy_read_timeout 3600s; to prevent timeouts during
long‑running workflow executions. Then set
N8N_PROXY_HOPS=1 so n8n trusts the proxy headers and
correctly constructs webhook URLs with https://. Without
this setting, webhook URLs may use http:// and break
integrations [1]. For
teams who prefer simpler TLS setup, Caddy auto‑negotiates HTTPS with
zero configuration beyond reverse_proxy n8n:5678 and
automatically handles certificate renewal [10].
For the complete reverse‑proxy configuration blueprint including
DDoS protection headers and rate limiting, see the
n8n Docker Compose production stack guide.

⚡ Nginx Headers Quick Reference:
proxy_set_header Host $host; — corrects webhook origin
URLs. proxy_set_header X-Forwarded-Proto $scheme;
ensures HTTPS appears in generated links. proxy_set_header
X-Forwarded-For $proxy_add_x_forwarded_for;
— preserves real
client IP for IP allowlisting. proxy_set_header Upgrade
$http_upgrade;
+ proxy_set_header Connection
"upgrade";
— enables WebSocket for editor live‑reload
[9].

How do you configure host‑level and container‑level firewall rules for n8n?

Use UFW (Uncomplicated Firewall) at the host level:
ufw allow 443/tcp && ufw allow 80/tcp && ufw enable.
This opens only HTTPS and HTTP ports—port 5678 must remain closed to
external traffic. Bind n8n to the loopback interface with
N8N_HOST=127.0.0.1 so n8n only listens on localhost,
forcing all external traffic through the reverse proxy
[1].

At the container level, enforce egress filtering
with iptables or nftables: restrict outbound
traffic from the n8n container to only the specific IPs or domains
your workflows need. This prevents a compromised workflow from
exfiltrating data to arbitrary external servers
[11]. The
strictest approach blocks all egress by default, then whitelists
only approved destinations (Slack webhook URLs, Stripe API endpoints,
your database server). For Docker deployments, define the
n8n-network as an isolated bridge network with
internal: true so only explicitly defined services can
communicate, and use service‑level restart: unless-stopped
with health checks on all containers. For additional logging, use
Docker’s --log-driver=json-file with
--log-opt max-size=10m and max-file=3 to
prevent disk exhaustion from debug logs [12]. For
the production‑ready Docker Compose blueprint that combines all
these controls, see the
n8n Docker Compose production stack guide.

Layer Tool / Setting Command / Value What It Blocks
1. Host Ingress UFW ufw allow 443/tcp && ufw allow 80/tcp Direct access to port 5678, SSH brute‑force
2. Service Bind Environment N8N_HOST=127.0.0.1:5678 Bypass of reverse proxy via direct port access
3. Container Egress iptables / Docker network internal: true on Docker network Data exfiltration to arbitrary external servers
4. Reverse Proxy Auth Nginx / Caddy TLS termination + header forwarding MITM attacks, incorrect webhook URL generation

How do you audit your self‑hosted n8n instance and monitor for security incidents?

Begin with a workflow content audit: check every Code
node for references to process.env, hardcoded API keys,
passwords, tokens, or secrets—these should immediately be replaced
by credential nodes or input‑parameter passing. Review each HTTP
Request node to verify it only calls expected endpoints, and scan
for ExecuteCommand or LocalFileTrigger nodes unless they are
explicitly required [3].

For operational monitoring, set
EXECUTIONS_DATA_SAVE_ON_SUCCESS=all to retain input/output
data for successful runs (not just failures), and
N8N_LOG_LEVEL=debug for detailed logs [13].
Build a monitoring workflow that queries the n8n REST API for
execution history, filters for anomalies (unexpected HTTP status
codes, long execution durations, access from unusual IPs), and posts
alerts to a dedicated security Slack channel. Combine these logs
with an external log aggregator (Loki, ELK, or Datadog) for
cross‑instance visibility and real‑time alerting. For compliance
audits, maintain the instance at a known version (pin Docker image
tags), regularly apply security patches, and follow the WotAI audit
checklist—the same checklist used internally by professional
automation agencies [3]. For
integrating security monitoring with incident response pipelines,
see the
n8n DevOps Nodes guide.

References

This guide is for informational purposes only. For the most current and authoritative information,
always refer to the official n8n website (n8n.io) and
the n8n documentation. Security configurations,
CVE statuses, and environment variable defaults may change across versions.



Leave a Reply

Your email address will not be published. Required fields are marked *