GitHub Security Advisory: GHSA-3j5q-7q7h-2hhv
Package: openmage/magento-lts (COMPOSER)
Severity: HIGH (CVSS 8.8)
CWE: CWE-434: Unrestricted Upload of File with Dangerous Type
Vulnerable versions: <= 20.16.0
Patched in: 20.17.0

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

Details:
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:

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

This misses the comprehensive `protected_extensions` blocklist defined elsewhere:

```xml
<!-- 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

```php
// 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


```bash
# Upload .phtml (bypasses blocklist)
curl -X POST "https://target.com/vulnerable_upload.php" \
  -F "file=@shell.phtml;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:

**Subdirectory** — `getDispretionPath($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/
```

**Filename** — `md5(file_get_contents($tmp_name))` is computed over the **raw bytes of the
uploaded payload** (`File.php:245`):

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