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 *