CVE-2026-55220
Pimcore Hotspotimage getDataFromResource() unrestricted Serialize::unserialize over object-store column
Pimcore is an Open Source Data & Experience Management Platform. Prior to 11.5.19, 12.3.10, and 2026.1.6, Pimcore\Model\DataObject\ClassDefinition\Data\Hotspotimage::getDataFromResource() in models/DataObject/ClassDefinition/Data/Hotspotimage.php passes the field __hotspots object-store column to Pimcore\Tool\Serialize::unserialize() without an allowed-classes restriction after JSON decoding fails. An attacker with a separate capability to write crafted PHP serialized bytes into that column can instantiate available classes and trigger magic methods when an affected DataObject is loaded, which can produce arbitrary file writes or code execution through bundled gadget chains. The related ImageGallery, Block, and Video callers use the same fallback pattern, but the identified June fix changes the Hotspotimage caller only. This issue is fixed for Hotspotimage in versions 11.5.19, 12.3.10, and 2026.1.6.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
9.3
Pimcore Hotspotimage getDataFromResource() unrestricted Serialize::unserialize over object-store column
Pimcore is an Open Source Data & Experience Management Platform. Prior to 11.5.19, 12.3.10, and 2026.1.6, Pimcore\Model\DataObject\ClassDefinition\Data\Hotspotimage::getDataFromResource() in models/DataObject/ClassDefinition/Data/Hotspotimage.php passes the field __hotspots object-store column to Pimcore\Tool\Serialize::unserialize() without an allowed-classes restriction after JSON decoding fails. An attacker with a separate capability to write crafted PHP serialized bytes into that column can instantiate available classes and trigger magic methods when an affected DataObject is loaded, which can produce arbitrary file writes or code execution through bundled gadget chains. The related ImageGallery, Block, and Video callers use the same fallback pattern, but the identified June fix changes the Hotspotimage caller only. This issue is fixed for Hotspotimage in versions 11.5.19, 12.3.10, and 2026.1.6.
- Record
CVE-2026-55220- CVSS 4.0
- 9.3 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N - Weakness
- CWE-502
- Updated
- 2026-11-02
EUVDEUVD-2026-67870
9.3
Pimcore is an Open Source Data & Experience Management Platform. Prior to 11.5.19, 12.3.10, and 2026.1.6, Pimcore\Model\DataObject\ClassDefinition\Data\Hotspotimage::getDataFromResource() in models/DataObject/ClassDefinition/Data/Hotspotimage.php passes the field __hotspots object-store column to Pimcore\Tool\Serialize::unserialize() without an allowed-classes restriction after JSON decoding fails. An attacker with a separate capability to write crafted PHP serialized bytes into that column can instantiate available classes and trigger magic methods when an affected DataObject is loaded, which can produce arbitrary file writes or code execution through bundled gadget chains. The related ImageGallery, Block, and Video callers use the same fallback pattern, but the identified June fix changes the Hotspotimage caller only. This issue is fixed for Hotspotimage in versions 11.5.19, 12.3.10, and 2026.1.6.
- Record
EUVD-2026-67870- CVSS 4.0
- 9.3 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-w23p-wrp7-ch38
9.3
Pimcore Hotspotimage getDataFromResource() unrestricted Serialize::unserialize over object-store column (PHP Object Injection, CWE-502)
Summary
Pimcore\Model\DataObject\ClassDefinition\Data\Hotspotimage::getDataFromResource() deserializes the *__hotspots object-store column through the Pimcore\Tool\Serialize::unserialize() wrapper without a class allowlist (the wrapper's $allowedClasses parameter defaults to true, i.e. fully unrestricted). Because the persistence layer always stores this column as PHP-serialize()d bytes, every load of a DataObject that has a Hotspotimage (advanced image) field runs an unrestricted unserialize() over the stored column value. An attacker who can write the *__hotspots store column with crafted serialized bytes achieves PHP Object Injection (CWE-502): arbitrary classes are instantiated and their magic methods (__wakeup/__destruct) execute, which is exploitable for remote code execution via gadget chains present in Pimcore's own bundled dependencies (e.g. guzzlehttp/guzzle).
The same field-data family also affects the sibling marshallers ImageGallery, Block, and Video, which use the identical json_decode(...) ?: Serialize::unserialize(...) fallback over their respective store columns. The root cause is shared: Serialize::unserialize() defaults to an unrestricted class list, and these callers pass no second argument.
Severity
High. Successful exploitation yields PHP Object Injection leading to remote code execution (proven below as arbitrary file write using a gadget from Pimcore's bundled guzzlehttp/guzzle 7.11.0). This is the deserialization leg of an attack: it requires the ability to write the *__hotspots object-store column with attacker-chosen serialized bytes. No class-allowlist defense is present, so any such write is directly weaponizable on the next object load. CVSS-wise this is comparable to other deserialization sinks over attacker-influenceable storage in this codebase.
Affected component
- File:
models/DataObject/ClassDefinition/Data/Hotspotimage.php, methodgetDataFromResource(). - Vulnerable lines (v2026.1.4 / v12.3.8):
$metaData = $data[$this->getName() . '__hotspots']; // check if the data is JSON (backward compatibility) $md = json_decode($metaData, true); if (!$md) { $md = Serialize::unserialize($metaData); // unrestricted: allowed_classes defaults to true } elseif (is_array($md)) { $md['hotspots'] = $md; } - Root enabler:
lib/Tool/Serialize.phppublic static function unserialize(?string $data = null, array|bool $allowedClasses = true): mixed { if ($data === null || $data === '') { return $data; } return unserialize($data, ['allowed_classes' => $allowedClasses]); // default true = unrestricted } - Sibling marshallers with the identical fallback shape:
ImageGallery,Block,Video(DataObject\ClassDefinition\Data). - Package:
pimcore/pimcore(Composer). - Affected versions: all currently maintained releases, including the latest
v2026.1.4andv12.3.8(verified against deployedv2026.1.4).
Data flow
- On save,
Hotspotimage::getDataForResource()stores the hotspot/marker/crop metadata asSerialize::serialize($metaData)into the<field>__hotspotsobject-store column — i.e. PHP serialized bytes, not JSON. - On load,
Hotspotimage::getDataFromResource()reads that column, callsjson_decode()(which fails for the serialized format), and therefore falls through toSerialize::unserialize($metaData)with the default unrestricted class list. Serialize::unserialize()invokesunserialize($data, ['allowed_classes' => true]), instantiating any class named in the bytes and triggering its magic methods.- The load path is exercised on essentially every object retrieval (admin grid/detail, frontend rendering, Studio/API reads, inheritance walks) for objects whose class declares a Hotspotimage field, with a non-null
<field>__image.
The attacker primitive is the ability to place crafted serialized bytes into the <field>__hotspots store column (for…
- Record
GHSA-w23p-wrp7-ch38- CVSS 4.0
- 9.3 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N - Weakness
- CWE-502
- Updated
- 2026-11-02
NVD
9.3
Pimcore is an Open Source Data & Experience Management Platform. Prior to 11.5.19, 12.3.10, and 2026.1.6, Pimcore\Model\DataObject\ClassDefinition\Data\Hotspotimage::getDataFromResource() in models/DataObject/ClassDefinition/Data/Hotspotimage.php passes the field __hotspots object-store column to Pimcore\Tool\Serialize::unserialize() without an allowed-classes restriction after JSON decoding fails. An attacker with a separate capability to write crafted PHP serialized bytes into that column can instantiate available classes and trigger magic methods when an affected DataObject is loaded, which can produce arbitrary file writes or code execution through bundled gadget chains. The related ImageGallery, Block, and Video callers use the same fallback pattern, but the identified June fix changes the Hotspotimage caller only. This issue is fixed for Hotspotimage in versions 11.5.19, 12.3.10, and 2026.1.6.
- Record
CVE-2026-55220- CVSS 4.0
- 9.3 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - Weakness
- CWE-502
- Updated
- 2026-11-02
OSV
9.3
Pimcore Hotspotimage getDataFromResource() unrestricted Serialize::unserialize over object-store column
Pimcore is an Open Source Data & Experience Management Platform. Prior to 11.5.19, 12.3.10, and 2026.1.6, Pimcore\Model\DataObject\ClassDefinition\Data\Hotspotimage::getDataFromResource() in models/DataObject/ClassDefinition/Data/Hotspotimage.php passes the field __hotspots object-store column to Pimcore\Tool\Serialize::unserialize() without an allowed-classes restriction after JSON decoding fails. An attacker with a separate capability to write crafted PHP serialized bytes into that column can instantiate available classes and trigger magic methods when an affected DataObject is loaded, which can produce arbitrary file writes or code execution through bundled gadget chains. The related ImageGallery, Block, and Video callers use the same fallback pattern, but the identified June fix changes the Hotspotimage caller only. This issue is fixed for Hotspotimage in versions 11.5.19, 12.3.10, and 2026.1.6.
- Record
CVE-2026-55220- CVSS 4.0
- 9.3 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N - Weakness
- CWE-502
- Updated
- 2026-11-02
OSVGHSA-w23p-wrp7-ch38
9.3
Pimcore Hotspotimage getDataFromResource() unrestricted Serialize::unserialize over object-store column (PHP Object Injection, CWE-502)
Summary
Pimcore\Model\DataObject\ClassDefinition\Data\Hotspotimage::getDataFromResource() deserializes the *__hotspots object-store column through the Pimcore\Tool\Serialize::unserialize() wrapper without a class allowlist (the wrapper's $allowedClasses parameter defaults to true, i.e. fully unrestricted). Because the persistence layer always stores this column as PHP-serialize()d bytes, every load of a DataObject that has a Hotspotimage (advanced image) field runs an unrestricted unserialize() over the stored column value. An attacker who can write the *__hotspots store column with crafted serialized bytes achieves PHP Object Injection (CWE-502): arbitrary classes are instantiated and their magic methods (__wakeup/__destruct) execute, which is exploitable for remote code execution via gadget chains present in Pimcore's own bundled dependencies (e.g. guzzlehttp/guzzle).
The same field-data family also affects the sibling marshallers ImageGallery, Block, and Video, which use the identical json_decode(...) ?: Serialize::unserialize(...) fallback over their respective store columns. The root cause is shared: Serialize::unserialize() defaults to an unrestricted class list, and these callers pass no second argument.
Severity
High. Successful exploitation yields PHP Object Injection leading to remote code execution (proven below as arbitrary file write using a gadget from Pimcore's bundled guzzlehttp/guzzle 7.11.0). This is the deserialization leg of an attack: it requires the ability to write the *__hotspots object-store column with attacker-chosen serialized bytes. No class-allowlist defense is present, so any such write is directly weaponizable on the next object load. CVSS-wise this is comparable to other deserialization sinks over attacker-influenceable storage in this codebase.
Affected component
- File:
models/DataObject/ClassDefinition/Data/Hotspotimage.php, methodgetDataFromResource(). - Vulnerable lines (v2026.1.4 / v12.3.8):
$metaData = $data[$this->getName() . '__hotspots']; // check if the data is JSON (backward compatibility) $md = json_decode($metaData, true); if (!$md) { $md = Serialize::unserialize($metaData); // unrestricted: allowed_classes defaults to true } elseif (is_array($md)) { $md['hotspots'] = $md; } - Root enabler:
lib/Tool/Serialize.phppublic static function unserialize(?string $data = null, array|bool $allowedClasses = true): mixed { if ($data === null || $data === '') { return $data; } return unserialize($data, ['allowed_classes' => $allowedClasses]); // default true = unrestricted } - Sibling marshallers with the identical fallback shape:
ImageGallery,Block,Video(DataObject\ClassDefinition\Data). - Package:
pimcore/pimcore(Composer). - Affected versions: all currently maintained releases, including the latest
v2026.1.4andv12.3.8(verified against deployedv2026.1.4).
Data flow
- On save,
Hotspotimage::getDataForResource()stores the hotspot/marker/crop metadata asSerialize::serialize($metaData)into the<field>__hotspotsobject-store column — i.e. PHP serialized bytes, not JSON. - On load,
Hotspotimage::getDataFromResource()reads that column, callsjson_decode()(which fails for the serialized format), and therefore falls through toSerialize::unserialize($metaData)with the default unrestricted class list. Serialize::unserialize()invokesunserialize($data, ['allowed_classes' => true]), instantiating any class named in the bytes and triggering its magic methods.- The load path is exercised on essentially every object retrieval (admin grid/detail, frontend rendering, Studio/API reads, inheritance walks) for objects whose class declares a Hotspotimage field, with a non-null
<field>__image.
The attacker primitive is the ability to place crafted serialized bytes into the <field>__hotspots store column (for…
- Record
GHSA-w23p-wrp7-ch38- CVSS 4.0
- 9.3 Critical
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N - Weakness
- CWE-502
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
pimcore/pimcorePackagist |
2026.1.0 to 2026.1.5 | 2026.1.6 |
pimcore/pimcorePackagist |
through 12.3.9 | 12.3.10 |
pimcore/pimcorePackagist |
2026.1.0 up to 2026.1.6, plus listed versions v2026.1.0v2026.1.1v2026.1.2v2026.1.3v2026.1.4v2026.1.5 |
2026.1.6 |
pimcore/pimcorePackagist |
before 12.3.10, plus listed versions 10.0.82.2.02.2.12.2.22.3.0 Show 45 moreShow less3.0.03.0.13.0.23.0.33.0.43.0.53.0.63.1.03.1.14.0.04.0.14.1.04.1.14.1.24.1.34.2.04.3.04.3.14.4.04.4.14.4.24.4.34.5.04.6.04.6.14.6.24.6.34.6.44.6.5v10.0.0v10.0.0-BETA1v10.0.0-BETA2v10.0.0-BETA3v10.0.0-BETA4v10.0.1v10.0.2v10.0.3v10.0.4v10.0.5v10.0.6v10.0.7v10.0.9v10.1.0v10.1.1v10.1.2 |
12.3.10 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-55220 is a critical vulnerability (CVSS 9.3) in Pimcore, published August 28, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.68%, the 52nd percentile. Fixed in pimcore/pimcore 2026.1.6.
References
github.com/pimcore/pimcore/security/advisories/GHSA-w23p-wrp7-ch38
github.com/pimcore/pimcore/pull/19181
github.com/pimcore/pimcore/commit/b184c01bf11e213e601d965b4e96c8bb7248e980
github.com/pimcore/pimcore/releases/tag/v12.3.10
github.com/pimcore/pimcore/releases/tag/v2026.1.6
github.com/advisories/GHSA-w23p-wrp7-ch38
github.com/CVEProject/cvelistV5/tree/main/cves/2026/55xxx/CVE-2026-55220.json
nvd.nist.gov/vuln/detail/CVE-2026-55220
github.com/pimcore/pimcore
Left out here: 275 versions and the rest of 2 source descriptions. The JSON record has them.