{"id":"GHSA-fg79-cr9c-7369","summary":"OpenMage LTS: Phar Deserialization leads to Remote Code Execution","details":"PHP functions such as `getimagesize()`, `file_exists()`, and `is_readable()` can trigger deserialization when processing `phar://` stream wrapper paths. OpenMage LTS uses these functions with potentially controllable file paths during image validation and media handling. An attacker who can upload a malicious phar file (disguised as an image) and trigger one of these functions with a `phar://` path can achieve arbitrary code execution.\n\n| Metric                   | Value     | Justification                                    |\n| ------------------------ | --------- | ------------------------------------------------ |\n| Attack Vector (AV)       | Network   | Exploitable via file upload and web requests     |\n| Attack Complexity (AC)   | High      | Requires file upload + triggering phar:// access |\n| Privileges Required (PR) | None      | Some upload vectors don't require authentication |\n| User Interaction (UI)    | None      | Exploitation is automatic once triggered         |\n| Scope (S)                | Unchanged | Impacts the vulnerable component                 |\n| Confidentiality (C)      | High      | Full system access via RCE                       |\n| Integrity (I)            | High      | Arbitrary code execution                         |\n| Availability (A)         | High      | Complete system compromise possible              |\n\n## Affected Products\n\n- OpenMage LTS versions \u003c 20.16.1\n- All versions derived from Magento 1.x with these code paths\n\n## Affected Files\n\n| File                                                      | Line | Vulnerable Function                            |\n| --------------------------------------------------------- | ---- | ---------------------------------------------- |\n| `app/code/core/Mage/Core/Model/File/Validator/Image.php`  | 72   | `getimagesize($filePath)`                      |\n| `app/code/core/Mage/Cms/Model/Wysiwyg/Images/Storage.php` | 137  | `getimagesize($item-\u003egetFilename())`           |\n| `lib/Varien/Image.php`                                    | 71   | `$this-\u003e_getAdapter()-\u003eopen($this-\u003e_fileName)` |\n\n## Vulnerability Details\n\nPHP's phar (PHP Archive) format stores metadata that is serialized. When PHP's stream wrapper functions access a file using the `phar://` protocol, the metadata is automatically deserialized. This occurs even with seemingly safe functions like `file_exists()` or `getimagesize()`.\n\nA polyglot file can be crafted that is both a valid image (passing initial validation) and a valid phar archive containing malicious serialized objects. When the application later processes this file using `phar://`, the deserialization triggers a gadget chain leading to RCE.\n\n### Attack Flow\n\n1. **Create polyglot file**: Attacker creates a file that is both valid JPEG and valid PHAR\n2. **Upload file**: Attacker uploads the polyglot via product images, CMS media, or import\n3. **Trigger phar:// access**: Attacker causes the application to access the file using `phar://` wrapper\n4. **Code execution**: PHAR metadata deserialization triggers gadget chain\n\n### Proof of Concept\n\n```php\n\u003c?php\n// Create malicious phar file\nclass ExploitGadget {\n    public $cmd = 'id \u003e /tmp/pwned';\n    function __destruct() {\n        system($this-\u003ecmd);\n    }\n}\n\n$phar = new Phar('exploit.phar');\n$phar-\u003estartBuffering();\n$phar-\u003eaddFromString('test.txt', 'test');\n$phar-\u003esetStub('\u003c?php __HALT_COMPILER(); ?\u003e');\n$phar-\u003esetMetadata(new ExploitGadget());\n$phar-\u003estopBuffering();\n\n// Rename to appear as image\nrename('exploit.phar', 'exploit.jpg');\n\n// When getimagesize('phar://path/to/exploit.jpg') is called,\n// the ExploitGadget::__destruct() method executes\n```\n\n## Remediation\n\nBlock `phar://` paths before passing to vulnerable functions:\n\n```php\n// Before (vulnerable)\n[$imageWidth, $imageHeight, $fileType] = getimagesize($filePath);\n\n// After (fixed)\nif (str_starts_with($filePath, 'phar://')) {\n    throw new Exception('Invalid image path.');\n}\n[$imageWidth, $imageHeight, $fileType] = getimagesize($filePath);\n```\n\nAdditionally, ICO files (which cannot be re-encoded by GD) are now scanned for phar signatures:\n\n- `__HALT_COMPILER();` - Required phar stub\n- `\u003c?php` - PHP opening tag\n- `\u003c?=` - PHP short echo tag\n\nAdditional hardening measures:\n\n1. **ICO uploads removed**: ICO file support is completely removed from new image uploads. This eliminates the polyglot attack vector entirely since all other image formats are re-encoded by GD, which strips any embedded phar metadata.\n\n2. **Phar wrapper disabled**: The `phar://` stream wrapper is unregistered at application bootstrap, preventing any phar deserialization attacks regardless of code path.\n\n3. **Cache deserialization hardening**: All `unserialize()` calls on cached data now use `allowed_classes =\u003e false` as defense-in-depth.\n\n**Note:** Existing uploaded ICO files will continue to work. Only new ICO uploads will be rejected. Users are encouraged to use PNG favicons for new uploads.\n\n## Workarounds\n\nIf immediate upgrade is not possible:\n\n1. **Disable phar stream wrapper** (if not needed):\n\n   ```ini\n   ; php.ini\n   disable_functions = phar://\n   ```\n\n   Or in code:\n\n   ```php\n   stream_wrapper_unregister('phar');\n   ```\n\n2. **Strict upload validation**: Implement additional validation beyond file extension\n\n3. **File storage isolation**: Store uploads outside web root with randomized names\n\n4. **Web Application Firewall**: Block requests containing `phar://` in parameters\n\n\n## Credit\n\nThis vulnerability was discovered and responsibly disclosed by [blackhat2013](https://hackerone.com/blackhat2013) through HackerOne.\n\n## Timeline\n\n- **2025-12-31**: Vulnerability reported via HackerOne\n- **2026-01-21**: Fix developed and tested\n\nSource: https://hackerone.com/reports/3482926","aliases":["CVE-2026-25524"],"modified":"2026-04-21T14:56:36.629087Z","published":"2026-04-21T14:32:48Z","database_specific":{"github_reviewed":true,"github_reviewed_at":"2026-04-21T14:32:48Z","nvd_published_at":"2026-04-20T17:16:32Z","cwe_ids":["CWE-502"],"severity":"HIGH"},"references":[{"type":"WEB","url":"https://github.com/OpenMage/magento-lts/security/advisories/GHSA-fg79-cr9c-7369"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-25524"},{"type":"PACKAGE","url":"https://github.com/OpenMage/magento-lts"},{"type":"WEB","url":"https://github.com/OpenMage/magento-lts/releases/tag/v20.17.0"}],"affected":[{"package":{"name":"openmage/magento-lts","ecosystem":"Packagist","purl":"pkg:composer/openmage/magento-lts"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"20.17.0"}]}],"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"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/04/GHSA-fg79-cr9c-7369/GHSA-fg79-cr9c-7369.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H"}]}