Prevent Privilege Escalation in Workflow Execution: 4 Steps

Step by Step Guide to solve privilege escalation workflow execution 
Step by Step Guide to solve privilege escalation workflow execution


Who this is for: Security engineers and DevOps professionals responsible for hardening n8n installations in production environments. We cover this in detail in the n8n Security & Hardening Guide.


Quick Diagnosis

Problem: A maliciously crafted n8n workflow can execute actions with the permissions of the n8n service account, giving an attacker a path to elevate privileges and access restricted resources.

Featured‑snippet solution:

  1. Identify any workflow that runs commands or accesses external services with elevated credentials.
  2. Restrict the Execute Command node (and any node that can invoke external APIs) to the minimum required scope.
  3. Enforce role‑based access control (RBAC) on workflow creation/modification.
  4. Audit workflow versions and enable “run as” isolation (Docker sandbox or separate process).

1. How n8n Workflows Can Become Privilege‑Escalation Vectors ?

If you encounter any database injection risks resolve them before continuing with the setup.
Micro‑summary: The following node types are the most common escalation bridges when they run with unrestricted privileges.

Attack surface Typical node(s) What the node can do when unrestricted
Execute Command `Execute Command` Run arbitrary shell commands on the host OS.
HTTP Request `HTTP Request` Call internal APIs that require admin tokens.
Database `Postgres`, `MySQL`, `MongoDB` Query/modify privileged databases using stored credentials.
File System `Write Binary File`, `Read Binary File` Read or overwrite config files (e.g., /etc/passwd).
Scripting `Function`, `Function Item` Execute JavaScript that can invoke child_process.exec.

EEFA note: In many production setups n8n runs as a Docker container with the host’s network stack. An unrestricted Execute Command node can break out of the container if it is started with --privileged or with excessive Linux capabilities.


2. Step‑by‑Step Exploit Example

Micro‑summary: A minimal workflow that upgrades a low‑privilege user to root on a typical Docker‑based n8n deployment.

2.1 Workflow definition – header

{
  "nodes": [

2.2 First node – check current UID

{
  "parameters": { "command": "id" },
  "name": "Check Current UID",
  "type": "n8n-nodes-base.executeCommand",
  "typeVersion": 1,
  "position": [250, 300]
},

2.3 Second node – install sudo and modify sudoers

{
  "parameters": {
    "command": "apt-get update && apt-get install -y sudo && echo 'user ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers"
  },
  "name": "Escalate to Root",
  "type": "n8n-nodes-base.executeCommand",
  "typeVersion": 1,
  "position": [500, 300],
  "executeAfter": ["Check Current UID"]
}

2.4 Connections and settings (truncated for brevity)

  ],
  "connections": {
    "Check Current UID": {
      "main": [
        [
          {
            "node": "Escalate to Root",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": { "executionMode": "manual" }
}

Why it works:

  1. The workflow is saved by a user with only the “workflow editor” role.
  2. n8n’s service account runs as root inside the container (common default).
  3. The Execute Command node runs apt-get and edits /etc/sudoers, granting the attacker full sudo rights on the host.
  4. If you encounter any xss vectors in custom code resolve them before continuing with the setup.

3. Real‑World Constraints

Constraint Impact if ignored Mitigation
Container runs with --privileged Full host escape possible Remove --privileged; use a minimal runtime profile (--cap-drop ALL).
Service account UID = 0 All nodes inherit root privileges Run n8n as a non‑root user (e.g., n8n UID 1000).
Stored admin tokens in environment variables Nodes can read them without restriction Use secret‑management (Docker secrets, HashiCorp Vault) and limit node access.

4. Harden the Workflow Execution Environment

4.1 Run n8n in a Restricted Docker Sandbox

Context: The command below starts n8n with a non‑privileged user, drops all capabilities, and enforces a read‑only root filesystem.

docker run -d \
  --name n8n \
  --user 1000:1000 \
  --cap-drop ALL \
  --read-only \
  -v /data/n8n:/home/node/.n8n \
  -p 5678:5678 \
  n8nio/n8n:latest

If you need writable temporary storage, bind‑mount a sub‑directory:

docker run -d \
  ... \
  -v /data/n8n/tmp:/tmp:rw \
  n8nio/n8n:latest

EEFA note: Mount only the directories you need (/tmp for logs, /home/node/.n8n for data).

4.2 Enable “Run as Separate Process” for Dangerous Nodes

Setting Recommended value Reason
Run Node in Separate Process Enabled Isolates each node in its own child process, limiting blast radius.
Maximum Concurrent Executions 2 (or lower) Reduces parallel attack surface.
Execution Timeout 300s Stops long‑running malicious commands.

5. Role‑Based Access Control (RBAC) for Workflow Creation

Micro‑summary: Restrict who can add high‑risk node types and enforce a deny list.

Role Permissions on Workflow Nodes
Viewer Read‑only access to workflow definitions.
Editor Can add/modify nodes except Execute Command, Function, Function Item.
Admin Full access – limit to trusted users only.

5.1 Enable RBAC in n8n

  1. Set N8N_USER_MANAGEMENT=true (or edit ~/.n8n/config).
  2. In the UI, go to Settings → Users & Permissions and create the roles above.

5.2 Add a node‑type deny list for the *Editor* role

{
  "nodeTypesDenied": [
    "n8n-nodes-base.executeCommand",
    "n8n-nodes-base.function",
    "n8n-nodes-base.functionItem"
  ]
}

3. Save and restart n8n.

EEFA note: The deny list blocks UI creation of those nodes, but an attacker could still import a JSON workflow containing them. Combine RBAC with import validation (next section).


6. Validate Imported Workflows – Prevent “Supply‑Chain” Escalation

Context: A pre‑execution hook scans incoming workflow JSON for prohibited node types and aborts execution if any are found.

6.1 Hook implementation (part 1)

module.exports = async function preExecuteWorkflow(workflow) {
  const prohibited = [
    'n8n-nodes-base.executeCommand',
    'n8n-nodes-base.function',
    'n8n-nodes-base.functionItem'
  ];

6.2 Hook implementation (part 2)

  const offending = workflow.nodes.filter(
    node => prohibited.includes(node.type)
  );
  if (offending.length) {
    throw new Error(
      `Workflow rejected: contains prohibited node(s) ${offending
        .map(n => n.type)
        .join(', ')}`
    );
  }
  return workflow;
};

6.3 Register the hook

export N8N_CUSTOM_HOOKS="/home/node/.n8n/custom/hooks"

Now any workflow import that includes a dangerous node will be blocked before execution. Secure your n8n webhooks – prevents credential leakage via exposed endpoints.


7. Detection & Monitoring

Micro‑summary: Combine audit logs, log shipping, metrics, and runtime security to surface suspicious activity.

Tool What to monitor Alert condition
Audit Logs (n8n → Settings → Audit) Creation/modification of Execute Command nodes Log entry with nodeType=executeCommand and userRole!=admin.
Filebeat / Fluent Bit Container stdout/stderr for privileged commands Regex sudo|chmod|chown → send to SIEM.
Prometheus Exporter n8n_execution_time_seconds per node type Spike in execution time for executeCommand > 30 s.
Falco (runtime security) execve syscalls from n8n container Alert on execve with /bin/sh -c apt-get.

Sample Falco rule (part 1)

- rule: n8n Execute Command Abuse
  desc: Detect execution of privileged commands from n8n container
  condition: >
    container.image = "n8nio/n8n:latest"
    and evt.type = execve

Sample Falco rule (part 2)

    and proc.name in (apt-get, yum, sudo, chmod, chown)
  output: "Potential privilege escalation via n8n workflow (container=%container.id command=%proc.cmdline)"
  priority: WARNING
  tags: [n8n, privilege_escalation]

8. Checklist – Secure Your n8n Workflows Against Privilege Escalation

  • Run n8n container as non‑root (--user 1000:1000).
  • Drop all Linux capabilities (--cap-drop ALL).
  • Enable “Run Node in Separate Process”.
  • Configure RBAC: deny Execute Command, Function, Function Item for non‑admin roles.
  • Deploy the pre‑execution hook to reject prohibited node types on import.
  • Audit workflow changes daily; alert on any new Execute Command nodes.
  • Set up Falco (or equivalent) to catch privileged syscalls.
  • Rotate stored admin tokens and store them in a secret manager, not environment variables.

Conclusion

By isolating the n8n runtime (non‑root Docker sandbox, capability drop, read‑only root), enforcing strict RBAC, validating imported workflows, and continuously monitoring for privileged command execution, you eliminate the most common privilege‑escalation pathways that stem from malicious workflow design. This hardening aligns with production‑grade security standards and ensures that workflow execution never becomes a backdoor into your infrastructure.

Leave a Comment

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