n8n env var access denied – [error: access to env vars denied] fix

Step by Step Guide to solve env var secrets leakage 
Step by Step Guide to solve env var secrets leakage


Who this is for: n8n operators, DevOps engineers, and security‑focused developers who run n8n in Docker, Kubernetes, or on‑premise servers and need to keep API keys, DB passwords, and OAuth tokens out of logs, process listings, and container metadata. We cover this in detail in the n8n Security & Hardening Guide.


Quick Diagnosis

If API keys, database passwords, or OAuth tokens appear in logs, container metadata, or ps output, you are most likely leaking environment‑variable secrets. The fastest remediation is to stop storing production secrets directly in plain‑text env vars and move them to a secret‑management solution (Docker/Kubernetes secrets, OS vault, or encrypted .env).


Why Environment Variables Leak in n8n ?

If you encounter any default credentials vulnerability resolve them before continuing with the setup.

Common Leak Vectors

Vector Typical Impact
Process list (ps aux) – n8n inherits all env vars Immediate exposure of API keys, DB passwords
Docker inspect / docker‑compose config – env vars stored in container definition Secrets visible to anyone with Docker access
Kubernetes describe pod / env – env vars in pod spec Cluster‑wide breach if RBAC is weak
Log files – accidental console.log(process.env) Persistent secret copies in log storage
CI/CD pipeline prints – debug mode echoes env vars Secrets leak to build logs, possibly public

EEFA note: The process list is the most overlooked vector. Even with restricted Docker commands, a compromised container can read its own environment via cat /proc/$$/environ.

How n8n Loads Secrets ?

  1. Bootstrap – The Docker entrypoint runs node packages/cli/src/cli.js.
  2. Config loadersrc/cli.ts calls dotenv.config() (if a .env file exists) and merges process.env into the NodeConfig object.
  3. Runtime – Nodes retrieve credentials with this.getNodeParameter('apiKey'), which resolves to process.env.N8N_API_KEY when the parameter is set to “environment variable”.

Credential resolver snippet

// Resolve env‑based credential
if (credentialValue.startsWith('env:')) {
  const envKey = credentialValue.replace(/^env:/, '');
  const secret = process.env[envKey];
  if (!secret) throw new Error(`Missing env var ${envKey}`);
  return secret;
}

EEFA warning: The error message reveals the missing variable name, unintentionally disclosing which secret is expected.


Real‑World Exposure Scenarios

If you encounter any insecure webhook exposure resolve them before continuing with the setup.

Scenario Symptoms Root Cause
Accidental docker logs dump Log lines contain Authorization: Bearer <token> Custom webhook node logs the full request object
CI pipeline prints env Build log shows N8N_DB_PASSWORD=***** CI step uses set -x (bash debug)
Kubernetes pod crash Error: ENOENT … open '/run/secrets/N8N_API_KEY' Secret volume not mounted; fallback to empty env var
Docker Compose --force-recreate New containers start with old env vars Hard‑coded environment: entries remain in compose file

Secure Storage Options

1. Docker Secrets (Swarm)

Store each secret as a read‑only file inside the container and avoid exposing it via environment:.

Create a secret

# Example: DB password
echo "SuperSecretPass123!" | docker secret create n8n_db_password -

Reference in docker‑compose.yml

services:
  n8n:
    image: n8nio/n8n
    secrets:
      - n8n_db_password
    environment:
      - DB_PASSWORD_FILE=/run/secrets/n8n_db_password
secrets:
  n8n_db_password:
    external: true

EEFA note: Docker secrets are mounted as read‑only files. Never duplicate the value in environment:.

2. Kubernetes Secrets

Mount secrets as environment variables or files.

Define the secret

apiVersion: v1
kind: Secret
metadata:
  name: n8n-api-key
type: Opaque
stringData:
  N8N_API_KEY: "k8s-super-secret-key"

Use in a deployment

apiVersion: apps/v1
kind: Deployment
metadata:
  name: n8n
spec:
  template:
    spec:
      containers:
        - name: n8n
          image: n8nio/n8n
          envFrom:
            - secretRef:
                name: n8n-api-key

EEFA warning: Kubernetes secrets are base64‑encoded, not encrypted. Enable EncryptionConfiguration on the API server for true at‑rest encryption.

3. OS‑Level Secret Stores

Leverage native secret managers (Linux pass, macOS Keychain, Windows Credential Manager) and inject values at runtime.

Bash wrapper example (Linux pass)

#!/usr/bin/env bash
# fetch-secret.sh – injects N8N_API_KEY from `pass`
export N8N_API_KEY=$(pass show n8n/api-key)
exec "$@"

Run n8n with: ./fetch-secret.sh node packages/cli/src/cli.js start.

4. Encrypted .env Files (last resort)

Tool Encryption Integration
sops GPG/PGP or cloud KMS sops -e .env > .env.enc; decrypt in entrypoint script
dotenv‑vault HashiCorp Vault vault kv get -field=value secret/n8n/api-key > .env then dotenv -e .env node …

EEFA tip: Keep the decryption key separate from the image layer; use an init side‑car that fetches the key from a vault. If you encounter any jwt auth misconfiguration resolve them before continuing with the setup.


Step‑by‑Step Migration: .env → Docker Secrets

1. List current secrets

grep -E '^N8N_' .env
# Example output:
# N8N_DB_PASSWORD=SuperSecret
# N8N_API_KEY=abcd1234

2. Create Docker secrets

# DB password
cat .env | grep '^N8N_DB_PASSWORD=' | cut -d= -f2- | docker secret create n8n_db_password -
# API key
cat .env | grep '^N8N_API_KEY=' | cut -d= -f2- | docker secret create n8n_api_key -

3. Update docker‑compose.yml

services:
  n8n:
    image: n8nio/n8n
    secrets:
      - n8n_db_password
      - n8n_api_key
    environment:
      - DB_PASSWORD_FILE=/run/secrets/n8n_db_password
      - API_KEY_FILE=/run/secrets/n8n_api_key
    command: >
      sh -c "export DB_PASSWORD=$(cat $DB_PASSWORD_FILE) &&
             export N8N_API_KEY=$(cat $API_KEY_FILE) &&
             node packages/cli/src/cli.js start"
secrets:
  n8n_db_password:
    external: true
  n8n_api_key:
    external: true

4. Clean up

  • Remove secret entries from .env.
  • Add a .env.example with non‑secret defaults for developers.

5. Deploy

docker stack deploy -c docker-compose.yml n8n_stack

6. Verify no leakage

docker exec -it $(docker ps -q -f "name=n8n") env | grep N8N_
# Should output nothing because secrets are read from files, not env.

Checklist: Confirm No Secret Leakage

Item Verification Command
Process list ps aux | grep node – ensure no N8N_ vars appear
Docker inspect docker inspect <container> | grep -i env – no secret entries
Kubernetes pod env kubectl exec <pod> -- env | grep N8N_ – only non‑secret vars
Log sanitization Review custom node code; mask process.env before logging
CI/CD hygiene Disable set -x; enable secret masking in CI platform
Secret rotation Update a Docker secret and confirm n8n picks up the new value (via file‑watch script)

EEFA final advice: Secret leakage is often discovered after an incident. Apply defense‑in‑depth: combine Docker/K8s secrets with runtime checks (the checklist) and audit every CI/CD job that interacts with n8n.

This page is part of the comprehensive “n8n security guide”. For a high‑level overview, visit the n8n security guide.

Leave a Comment

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