This episode dissects n8n's security side: how credentials are stored and encrypted, managing environment variables and external secrets manager integration, up to best practices for locking down UI and API access so the instance is safe to use in production.

In episode 11 you automated files and media: S3, Google Drive, FTP, up to document and image manipulation. All those integrations rest on one shared thing — credentials. API keys, OAuth tokens, and database passwords are the fuel of every workflow, and they're exactly what attackers look for most. An instance with complete integrations but leaked credentials is the same as handing someone the key to your warehouse.
Episode 12 covers Security & Credential Management. The roadmap has three parts: how n8n stores sensitive credentials securely, how to manage environment variables and secrets, then best practices for locking down UI and API access.
When you add credentials to a node — say the email service API key from episode 8 — n8n doesn't store them as plain text. Credential values are encrypted then stored in the database, and what's written on the node is only a reference to those credentials.
Here's a security property often missed: credential values never become part of the workflow JSON or node output. Credentials are applied internally to requests, then removed from the data flow. As a result, when you export a workflow or inspect execution history, token contents are never visible. Compare that with pasting a token directly into a node parameter — that value is permanently printed in the parameters and leaks into execution history and every workflow export.
Warning
Never store secrets through the $env or $vars expression inside nodes. Values injected via expressions enter node parameters and flow into execution data — visible in the editor, execution history, and export files. For sensitive data, use the credential mechanism, not env.
The security key of n8n credentials is the encryption key. On first run, n8n generates a random key automatically — but for production, you must set it yourself via the N8N_ENCRYPTION_KEY environment variable. This key derives the ciphertext for all credentials in the database.
N8N_ENCRYPTION_KEY=$(openssl rand -hex 32)
N8N_USER_MANAGEMENT_JWT_SECRET=$(openssl rand -hex 32)Two things you must hold onto firmly:
Store the key in a vault or infrastructure secret store, not in a repo. For Docker-based self-hosting, inject it via Docker secrets or Kubernetes secrets.
The safest way to store integration secrets in n8n is to use the credential entity available on many nodes. When writing custom credentials — for example a header auth for HTTP Request — the field type that marks a secret is the password type, so the value is displayed as asterisks and doesn't enter exports.
The second layer is guarding env access inside nodes. Since version 2.0, the N8N_BLOCK_ENV_ACCESS_IN_NODE environment variable defaults to true, meaning expressions reading $env and functions in Code nodes no longer see your environment. This is intentional: reading env from within a workflow is the most common secret-leak hole.
N8N_BLOCK_ENV_ACCESS_IN_NODE=true
NODE_FUNCTION_ALLOW_BUILTIN=*
NODE_FUNCTION_ALLOW_EXTERNAL=axios,lodashIf you genuinely need non-secret values from the environment (base URLs that differ per environment), opening access is still allowed — but limit which values are consumed, and never use it for tokens. For non-sensitive config between environments, the $vars variable can also be used, as long as it's not for secrets.
For team or enterprise scale, storing secrets inside the n8n database isn't the best option. n8n supports an external secrets manager that pulls directly at runtime. Supported providers: HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, GCP Secret Manager, Infisical, and 1Password Connect Server.
The flow: open Settings → External Secrets, add a vault with a unique name, then choose the provider and fill in the connection credentials. Once connected, any credential field can reference a secret using an expression — the vault name becomes the first segment:
{
"provider": "infisical",
"vaultName": "prod-infisical",
"credentialField": "DB_PASSWORD",
"expression": "{{ $secrets.prod-infisical.DB_PASSWORD }}"
}n8n refreshes the secret cache periodically via N8N_EXTERNAL_SECRETS_UPDATE_INTERVAL (default 300 seconds). New secret values automatically become available at the next execution without restarting the instance. Important note: this feature is licensed as enterprise on n8n, so make sure your license supports it before planning to use it.
Access to the editor UI is access to all workflows and credentials. Protecting it is the highest priority:
N8N_DISABLE_UI=true, so there's no editor attack surface.Besides the UI, n8n opens a Public REST API for external integration. This API is protected by API keys managed in Settings → API. Every request must carry the X-N8N-API-KEY header.
curl -s https://n8n.example.com/api/v1/workflows \
-H "X-N8N-API-KEY: n8n_api_xxxxxxxxxxxx"Several points you must maintain:
/metrics endpoint publicly. This endpoint reveals operational data — let it be accessed only by the internal monitoring network.Summarizing all the steps above into a short checklist:
N8N_ENCRYPTION_KEY set explicitly, stable, and backed up separately.$env access in nodes left locked (N8N_BLOCK_ENV_ACCESS_IN_NODE=true)./metrics endpoint hidden from the public.Episode 12 closed the most frequently exploited gap: credentials. You understand that credential values are stored encrypted and never leak into workflow JSON, the importance of setting and backing up N8N_ENCRYPTION_KEY, how to manage environment variables and move secrets to an external secrets manager, and the steps to lock down UI and API access.
Key takeaways:
N8N_ENCRYPTION_KEY must be explicit, stable, and backed up — losing it means losing all credentials.$env or $vars because the values flow into execution data.In the next episode we'll learn to monitor what happens in the instance: Audit, Monitoring & Observability — tracking workflow executions and node logs, integrating Prometheus, Grafana, and ELK, and applying alerts for failures. See you there!