Summary
elFinder provides uploadDeny and uploadAllow options in its connector configuration to restrict which MIME types may be uploaded. When uploadDeny includes text/x-php, direct upload of .php, .phtml, and .phar files is correctly blocked. However, the extract command (ZIP decompression) internally calls checkExtractItems(), which invokes mimetypeInternalDetect() directly without passing the result through mimeTypeNormalize(). Because phtml, phar, and similar PHP-executable extensions are absent from mime.types, they are not resolved to text/x-php at the detection stage, causing the MIME filter to be silently bypassed. An attacker who is permitted to upload ZIP archives can therefore extract PHP-executable files into the web-accessible files/ directory. If the server is configured to execute the affected extension (e.g., .phtml, .phar) as PHP — which is the case in common Apache and Nginx deployments — this results in Remote Code Execution.
Details
elFinder's MIME validation pipeline for direct uploads (upload command) is:
mimetype()
└─ mimetypeInternalDetect() // stage 1: extension → MIME via mime.types
└─ mimeTypeNormalize() // stage 2: apply staticMimeMap
phtml:* → text/x-php
phar:* → text/x-php
php5:* → text/x-php
└─ allowPutMime() // blocked: text/x-php ∈ uploadDeny
The extract command (checkExtractItems() in elFinderVolumeDriver.class.php, line 7110) uses a shortened pipeline:
// line 7110 — stage 2 (mimeTypeNormalize) is never called
if ($chkMime
&& ($mimeByName = elFinderVolumeDriver::mimetypeInternalDetect($name))
&& !$this->allowPutMime($mimeByName)) {
Because phtml and phar are not present in mime.types, mimetypeInternalDetect() returns a generic type (e.g., application/octet-stream) for these extensions. Without mimeTypeNormalize(), the staticMimeMap entries that would map phtml:* → text/x-php are never applied, so allowPutMime() sees a non-blocked MIME and permits extraction.
Affected extensions confirmed: .phtml, .phar, .php5, .php3
Not bypassed: .php (present in mime.types, detected as text/x-php in stage 1)
PoC
Requirements:
- elFinder 2.1.69 deployed under Apache/Nginx (PHP-FPM or mod_php)
- Connector configured with
uploadDeny = ['text/x-php'] and uploadAllow including application/zip
files/ directory served under a public web path
Step 1 — Confirm direct upload is blocked
Open elFinder in a browser and click the Upload button.
Select hello.phtml (content: <?php phpinfo(); ?>).
→ Upload is rejected with: "Upload file hello.phtml: File type not allowed (text/x-php)"

Step 2 — Upload a ZIP containing the payload
Create bypass.zip containing hello.phtml.
Upload bypass.zip via the Upload button.
→ ZIP is accepted (MIME: application/zip ∈ uploadAllow).

Step 3 — Extract the ZIP
Right-click bypass.zip in the file list → Extract files.
→ hello.phtml appears in the file list without any error.
→ File is now present at {files_dir}/hello.phtml on the server.

Step 4 — Execute the extracted PHP file
Navigate to:
http://<target>/elFinder/files/hello.phtml
→ Apache processes the file as PHP and renders the full phpinfo() output, confirming Remote Code Execution.

Impact
Any user with ZIP upload permission can bypass the uploadDeny MIME restriction, place PHP-executable files in a web-accessible directory, and achieve Remote Code Execution on the server.
Concrete impact:
- Arbitrary PHP code execution on the web server
- Full server environment disclosure via
phpinfo() (paths, PHP version, loaded modules, environment variables)
- Potential access to server filesystem, database credentials, and internal network services
- Complete compromise of the web application if an attacker substitutes
phpinfo() with a web shell (e.g., <?php system($_GET['cmd']); ?>)
Extensions confirmed executable on Apache (default config):
phtml, phar, php5, php3
Recommended fix:
Apply mimeTypeNormalize() inside checkExtractItems() so that the full MIME pipeline is used consistently:
// elFinderVolumeDriver.class.php, line 7110
// Before (vulnerable):
$mimeByName = elFinderVolumeDriver::mimetypeInternalDetect($name)
// After (fixed):
$mimeByName = $this->mimeTypeNormalize(
elFinderVolumeDriver::mimetypeInternalDetect($name),
$name,
pathinfo($name, PATHINFO_EXTENSION)
)
References
Summary
elFinder provides
uploadDenyanduploadAllowoptions in its connector configuration to restrict which MIME types may be uploaded. WhenuploadDenyincludestext/x-php, direct upload of.php,.phtml, and.pharfiles is correctly blocked. However, theextractcommand (ZIP decompression) internally callscheckExtractItems(), which invokesmimetypeInternalDetect()directly without passing the result throughmimeTypeNormalize(). Becausephtml,phar, and similar PHP-executable extensions are absent frommime.types, they are not resolved totext/x-phpat the detection stage, causing the MIME filter to be silently bypassed. An attacker who is permitted to upload ZIP archives can therefore extract PHP-executable files into the web-accessiblefiles/directory. If the server is configured to execute the affected extension (e.g.,.phtml,.phar) as PHP — which is the case in common Apache and Nginx deployments — this results in Remote Code Execution.Details
elFinder's MIME validation pipeline for direct uploads (
uploadcommand) is:The
extractcommand (checkExtractItems()inelFinderVolumeDriver.class.php, line 7110) uses a shortened pipeline:Because
phtmlandpharare not present inmime.types,mimetypeInternalDetect()returns a generic type (e.g.,application/octet-stream) for these extensions. WithoutmimeTypeNormalize(), thestaticMimeMapentries that would mapphtml:*→text/x-phpare never applied, soallowPutMime()sees a non-blocked MIME and permits extraction.Affected extensions confirmed:
.phtml,.phar,.php5,.php3Not bypassed:
.php(present inmime.types, detected astext/x-phpin stage 1)PoC
Requirements:
uploadDeny = ['text/x-php']anduploadAllowincludingapplication/zipfiles/directory served under a public web pathStep 1 — Confirm direct upload is blocked

Open elFinder in a browser and click the Upload button.
Select
hello.phtml(content:<?php phpinfo(); ?>).→ Upload is rejected with: "Upload file hello.phtml: File type not allowed (text/x-php)"
Step 2 — Upload a ZIP containing the payload

Create
bypass.zipcontaininghello.phtml.Upload
bypass.zipvia the Upload button.→ ZIP is accepted (MIME:
application/zip∈uploadAllow).Step 3 — Extract the ZIP

Right-click
bypass.zipin the file list → Extract files.→
hello.phtmlappears in the file list without any error.→ File is now present at
{files_dir}/hello.phtmlon the server.Step 4 — Execute the extracted PHP file
Navigate to:
→ Apache processes the file as PHP and renders the full
phpinfo()output, confirming Remote Code Execution.Impact
Any user with ZIP upload permission can bypass the
uploadDenyMIME restriction, place PHP-executable files in a web-accessible directory, and achieve Remote Code Execution on the server.Concrete impact:
phpinfo()(paths, PHP version, loaded modules, environment variables)phpinfo()with a web shell (e.g.,<?php system($_GET['cmd']); ?>)Extensions confirmed executable on Apache (default config):
phtml, phar, php5, php3
Recommended fix:
Apply
mimeTypeNormalize()insidecheckExtractItems()so that the full MIME pipeline is used consistently:References