GHSA-gxmj-r5rf-ggwq: Malicious File Upload

Published Sep 2, 2026
·
Updated

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:

php // 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 modphp) - 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)" <img width="1061" height="408" alt="1" src="https://github.com/user-attachments/assets/22f833d9-7d2a-4197-85c2-3b0eb19ecfbc" />

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). <img width="886" height="320" alt="2" src="https://github.com/user-attachments/assets/30c3498f-91f4-45cf-8c2b-cc806716e3a4" />

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 {filesdir}/hello.phtml on the server. <img width="1123" height="792" alt="3" src="https://github.com/user-attachments/assets/49e7db8e-566c-4653-a57f-e80fb31ea61d" />

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.

--- <img width="1059" height="739" alt="4" src="https://github.com/user-attachments/assets/ad85fdf7-bdc7-4514-bdec-e45cfb2e2bd3" />

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:

php // elFinderVolumeDriver.class.php, line 7110 // Before (vulnerable): $mimeByName = elFinderVolumeDriver::mimetypeInternalDetect($name)

// After (fixed): $mimeByName = $this->mimeTypeNormalize( elFinderVolumeDriver::mimetypeInternalDetect($name), $name, pathinfo($name, PATHINFOEXTENSION) )

---

---

Affected Software

1 affected componentFixes available
composer/Studio-42/elFinder<2.1.70
2.1.70

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade composer/Studio-42/elFinder to a version that resolves this vulnerability.

    Fixed in 2.1.70
  2. Upgrade

    Upgrade elFinder 2.1.69 to a version that resolves this vulnerability.

    Fixed in 2.1.69
  3. Configuration

    Verify the elFinder connector is configured so that uploadDeny blocks 'text/x-php' while uploadAllow permits 'application/zip' (as described: ZIP upload is allowed but PHP MIME types should be denied).

    elFinder connector (uploadDeny/uploadAllow) uploadDeny / uploadAllow = uploadDeny includes 'text/x-php' and uploadAllow includes 'application/zip'
  4. Configuration

    Apply the code fix described: in elFinderVolumeDriver.class.php (checkExtractItems(), referenced around line 7110), call mimeTypeNormalize() so the full MIME pipeline is used consistently for extracted items; specifically avoid the shortened pipeline where stage 2 (mimeTypeNormalize) is never called during extraction.

    elFinderVolumeDriver.class.php (checkExtractItems) mimetypeInternalDetect() pipeline = Ensure mimeTypeNormalize() is applied during checkExtractItems() extract path

Event History

Sep 2, 2026
Advisory Published
via GitHub·02:37 PM
Data Sourced
via GitHub·02:37 PM
DescriptionSeverityWeaknessAffected Software

Frequently Asked Questions

1

What conditions are required for exploitation?

An unauthenticated attacker needs to be permitted to upload a ZIP archive and invoke extraction. The extracted PHP-executable file must land in the web-accessible files/ directory, and the web server must execute its extension as PHP.

2

Does blocking text/x-php prevent this issue?

It blocks direct uploads of .php, .phtml, and .phar files, but it does not prevent the affected ZIP extraction path from bypassing the MIME filter. Extensions such as .phtml and .phar may not be normalized to text/x-php during extraction.

3

Which deployments are most exposed?

Deployments that allow ZIP uploads and extraction into a web-accessible files/ directory are exposed if their server executes extracted extensions such as .phtml or .phar as PHP. The advisory identifies common Apache and Nginx configurations as examples where those extensions may be executable.

4

What can be done while patching is unavailable?

Prevent untrusted users from uploading ZIP archives or using the extraction function. Configure the web server so files in the files/ directory, including .phtml and .phar files, cannot be executed as PHP.

5

How can an administrator assess whether their configuration is affected?

Check whether ZIP upload and extraction are available to untrusted users, whether extraction writes into the web-accessible files/ directory, and whether the server executes .phtml, .phar, or similar extensions as PHP. A configuration that only relies on uploadDeny containing text/x-php does not protect the affected extraction path.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203