
In April 2025, Orange Cyberdefense discovered a critical vulnerability in Craft CMS during an incident investigation, now tracked as CVE-2025-32432. The flaw enables unauthenticated RCE (remote code execution) with the maximum severity CVSS v3.1 score of 10.0 (Critical) from the NVD (National Vulnerability Database).
As part of the OPSWAT Critical Infrastructure Cybersecurity Graduate Fellowship Program, our fellows conducted a comprehensive study of this vulnerability, including reproducing the exploit, validating its impact, assessing organizational risks, and analyzing recommended protection strategies.
This blog delivers a comprehensive deep dive into CVE-2025-32432, analyzing its root cause, exploitation flow, and broader security implications, while offering actionable guidance for organizations to defend against this threat.
CVE-2025-32432 Introduction
CVE-2025-32432 affects Craft CMS versions 3.0.0-RC1 through 3.9.14, 4.0.0-RC1 through 4.14.14, and 5.0.0-RC1 through 5.6.16. Classified as CWE-94: Code Injection, the flaw arises from improper handling of untrusted input, ultimately enabling unauthenticated RCE.

Craft CMS & The Yii Framework
Craft CMS is a modern content management system that enables developers and content teams to build flexible, fully customized websites rather than relying on rigid, pre-defined templates. With adoption across more than 46,000 websites worldwide, it is both widely used and a frequent target for attackers seeking high-impact vulnerabilities.
Craft CMS is built on top of the Yii Framework, a fast and powerful PHP framework made for modern web development. Yii provides the core structure and tools, while Craft CMS extends it to deliver a flexible content management system.

One of the core features of the Yii framework is its Dependency Injection (DI) container. Dependency Injection is a design pattern that supplies components with the resources they need, instead of requiring them to construct those resources themselves. Yii’s DI container is highly flexible, capable of building complex objects from relatively simple configuration rules.
However, this flexibility comes with risk. In the case of CVE-2025-32432, the DI container was misused in combination with untrusted user input, creating a pathway to remote code execution. This case demonstrates that even safe and powerful framework features can become dangerous if they are integrated without a complete understanding of their security implications.
Deep Dive Into CVE-2025-32432
Craft CMS includes a feature called Image Transforms, which is designed to optimize performance by generating resized images directly on the server. Instead of delivering a large 4.5 MB image to display as a 300×300 thumbnail, Craft CMS automatically creates and serves a smaller, optimized version. This approach reduces bandwidth usage and significantly improves page load speed.
To make this functionality widely available, Craft CMS exposes the actions/assets/generate-transform endpoint without requiring authentication. While this ensures that both authenticated and anonymous users can benefit from optimized images, it also introduces a publicly accessible attack surface where anyone can supply crafted input to the application.

Through a detailed analysis of this workflow, our fellows identified that the method AssetsController::actionGenerateTransform is invoked whenever a POST request is sent to the exposed endpoint. This function retrieves the handle parameter directly from the request body and forwards it downstream for further processing in the next stage.

In the next step, the ImageTransforms::normalizeTransform() method is called. This method takes the user-supplied handle parameter and converts it into an ImageTransform object. Since the object is created directly from untrusted input, this represents a critical point of risk in the execution flow.

During this process, all key–value pairs from the user-controlled $transform array (originating from handle parameter) are merged into a configuration array. The normalizeTransform method then passes this array to Craft::createObject(), which is responsible for instantiating a new ImageTransform object.

The vulnerability stems from the way Craft::createObject() (wrapping Yii’s Yii::createObject()) processes configuration arrays. Because this mechanism uses the DI container to instantiate and configure objects directly from the unvalidated array, attackers may gain control over the object construction process.

When a malicious payload is passed in, the object’s constructor (inherited from the Model class) invokes the App::configure() method.

This method iterates over each property in the attacker-controlled array and assigns them to the new object.

When App::configure() assigns properties from the attacker-controlled configuration array, most keys are mapped directly onto the object. However, if a key begins with the prefix as, the assignment is routed through Component::__set, Yii’s magic setter. This method interprets as <name> as an instruction to attach a behavior (mixin) to the object.
One such malicious payload can be crafted to exploit how Component::__set processes properties prefixed with as, such as as exploit:

From our analysis, the implementation of Component::__set includes a safeguard: when a behavior is attached through such a property, the framework verifies that the class specified in the configuration array is a valid subclass of yii\base\Behavior. This check is intended to prevent arbitrary classes from being attached directly to components.

However, this safeguard is not as effective as it seems. The weakness comes from how Yii::createObject handles configuration arrays.
When instantiating an object, Yii::createObject gives priority to the special __class parameter. If this key is present, its value is used as the target class for instantiation, and the standard class key in the configuration array is ignored.

The attacker can craft a payload for the as exploit behavior that includes two keys:
- 'class' => '\craft\behaviors\FieldLayoutBehavior' - A legitimate class that extends yii\base\Behavior. This value exists solely to satisfy the is_subclass_of check in Component::__set, allowing execution to continue without raising an error.
- '__class' => '\yii\rbac\PhpManager' - The attacker’s actual target. This is the “gadget” class they want to instantiate.
When the code is executed, Component::__set passes the security check because it only inspects the class key. However, when the framework later calls Yii::createObject to attach the behavior, it gives precedence to __class, resulting in the instantiation of the attacker-chosen \yii\rbac\PhpManager object instead.
The use of \yii\rbac\PhpManager is intentional. Simply creating an object is not enough for exploitation; achieving RCE requires a gadget class with side effects that can be weaponized. PhpManager is a common target in POI (PHP Object Injection) attacks because of its initialization flow. Upon instantiation, its init() method calls load(), which then invokes loadFromFile($this->itemFile). With control over $this->itemFile, an attacker can force the application to load a malicious file, transforming object creation into code execution.

The danger lies in the loadFromFile method. In PHP, a require executes the target file as code, so if an attacker controls the file path, they can trigger arbitrary code execution.
To place malicious code on the server, the attacker exploits PHP session files. By injecting PHP into a request parameter, Craft CMS saves the payload into a session file during the redirect process. Later, when PhpManager loads this file, the attacker’s code could be executed.

The complete attack chain works in three stages. First, the attacker plants malicious PHP by sending a crafted URL, which Craft CMS saves into a session file. Next, they exploit the __class bypass in the image transform endpoint to load the PhpManager gadget and point it toward the poisoned session file. Finally, when PhpManager loads the file, the attacker’s payload executes, granting RCE and full control of the server—often through a webshell or reverse shell.



Mitigation and Remediation
To effectively mitigate the risks associated with CVE-2025-32432, organizations need visibility and control over their open-source components. Without a clear inventory of components, patching becomes guesswork.
OPSWAT SBOM, a proprietary technology within the MetaDefender® platform, addresses this need by providing an inventory of all software components, libraries, Docker containers, and dependencies in use. It allows organizations to track, secure, and update their components proactively.


In the example above, the SBOM technology in MetaDefender Core™ scanned the nginx-ingress-controller package that contained the CVE-2025-32432 vulnerability. The system automatically flagged the issue as Critical and provided guidance on fixed versions available, enabling teams to quickly prioritize and patch the vulnerability before it can be exploited.
OPSWAT SBOM is available in MetaDefender Core and MetaDefender Software Supply Chain™, enabling security teams to identify and act on vulnerabilities faster. With OPSWAT SBOM, security teams can:
- Quickly locate vulnerable components - Immediately identify the open-source components affected by deserialization attacks. This ensures swift action in either patching or replacing the vulnerable libraries.
- Ensure proactive patching and updates - Continuously monitor open-source components through OPSWAT SBOM to stay ahead of deserialization vulnerabilities. OPSWAT SBOM can detect outdated or insecure components, enabling timely updates and reduced exposure to attacks.
- Maintain compliance and reporting – OPSWAT SBOM helps organizations meet compliance requirements as regulatory frameworks increasingly mandate transparency in software supply chains.
Ready to strengthen your software supply chain against emerging threats?
