Investigating an in-the-wild campaign using RCE in CraftCMS
Introduction
In mid-February, Orange Cyberdefense’s CSIRT was tasked with investigating a server that had been hosting a now-unavailable website. The site had been built using CraftCMS running version 4.12.8. The forensic investigation and post-analysis with the Ethical Hacking team led to the discovery of two CVEs: CVE-2024-58136 and CVE-2025-32432.
This blog post aims to present:

The investigation that led to the finding of those two CVEs, and details of the different IOCs found during the analysis.
The technical details of both CVEs, explaining how the Craft CMS was vulnerable through the Yii Framewrork.
An assessment of the vulnerable assets online.

I. Forensic investigation
TL;DR

On the 14th of February, a threat actor compromised a web server using CVE-2025-32432.
The threat actor used it to download a file manager written in PHP on the server which was later used to upload other PHP files to the server.

The rest of this section will cover the following points:
Introduction
In mid-February, Orange Cyberdefense’s CSIRT was tasked with investigating a server that had been hosting a now-unavailable website. The site had been built using CraftCMS running version 4.12.8. The forensic investigation and post-analysis with the Ethical Hacking team led to the discovery of two CVEs: CVE-2024-58136 and CVE-2025-32432.
This blog post aims to present:
- The investigation that led to the finding of those two CVEs, and details of the different IOCs found during the analysis.
- The technical details of both CVEs, explaining how the Craft CMS was vulnerable through the Yii Framewrork.
- An assessment of the vulnerable assets online.
I. Forensic investigation
TL;DR
- On the 14th of February, a threat actor compromised a web server using CVE-2025-32432.
- The threat actor used it to download a file manager written in PHP on the server which was later used to upload other PHP files to the server.
The rest of this section will cover the following points:
- Investigating a Craft CMS incident: details about which logs were used during the investigation.
- Exploiting CVE-2025-32432: details about how the threat actor leveraged the CVE to compromise the web server.
- Post-exploitation: details about the actions performed by the threat actor after leveraging the CVE.
- Summary: summary of the findings.
- What to look for: key points to look for if you need to investigate a Craft CMS instance that might have been compromised using CVE-2025-32432.
IOCs found during the investigation and linked to the exploitation of CVE-2025-32432 are available in the appendix.
I.1 Investigating a Craft CMS incident
The investigation of the Craft CMS was based on two log sources:
- Access logs produced by the web server.
- Craft CMS logs, mostly its web logs that journalized every request going through
index.phpand details about it such as the parameters for a POST request. Other Craft CMS logs such as the phperrors.log can contain valuable information for the post-exploitation analysis. The default path for logs is the directoryCRAFT_INSTALL_PATH/storage/logs/.
An analysis of the server was also performed to ensure the threat actor did not compromise the system more widely.
I.2 Exploiting CVE-2025-32432
****Step 1: Finding a valid asset ID****
Craft CMS uses the notion of “Asset” to manage document files and media on the web site; each asset is defined by a set of properties such as a filename or a unique ID. Specifically, for images Craft CMS offers a built-in image transformation feature to help admins keep images to a certain format. Those transformations can be predefined by creating a transformation template or they can be made on the fly for a selected image.
CVE-2025-32432 relies on the fact that an unauthenticated user could send a POST request to the endpoint responsible for the image transformation and the data within the POST would be interpreted by the server. The data is interpreted when the transformation object is created. In versions 3.x of Craft CMS, the asset ID is checked before the creation of the transformation object whereas in version 4.x and 5.x, the asset ID is checked after. Thus, for the exploit to function with every version of Craft CMS, the threat actor needs to find a valid asset ID. The technical analysis section provides an in-depth analysis of the CVE.
As such the threat actor started to query the URI /index.php?p=admin/actions/assets/generate-transform multiple times. This URI is responsible for the transformation of an image. With each query the threat actor incremented the asset ID number. Those queries were probably made using a python script as suggested by the user-agent of the requester.
2025-02-10 08:13:48 [web.WARNING] [application] Request context: {"environment":"production","body":"{\"assetId\":162,\"handle\":{\"width\":123,\"height\":123}}","vars":{"\_GET":{"p":"admin/actions/assets/generate-transform"},"\_FILES":[],"\_COOKIE":{"CRAFT\_CSRF\_TOKEN":"••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••"},"\_SERVER":{"USER":[REDACTED],"HOME":[REDACTED],"SCRIPT\_NAME":"/index.php","REQUEST\_URI":"/index.php?p=admin/actions/assets/generate-transform","QUERY\_STRING":"p=admin/actions/assets/generate-transform","REQUEST\_METHOD":"POST","SERVER\_PROTOCOL":"HTTP/1.1","GATEWAY\_INTERFACE":[REDACTED],"REMOTE\_PORT":"36142","SCRIPT\_FILENAME":[REDACTED],"SERVER\_ADMIN":[REDACTED],"CONTEXT\_DOCUMENT\_ROOT":[REDACTED],"CONTEXT\_PREFIX":"","REQUEST\_SCHEME":"https","DOCUMENT\_ROOT":[REDACTED],"REMOTE\_ADDR":"103.106.66.123","SERVER\_PORT":"443","SERVER\_ADDR":[REDACTED],"SERVER\_NAME":[REDACTED],"SERVER\_SOFTWARE":[REDACTED],"SERVER\_SIGNATURE":[REDACTED],"PATH":"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin","CONTENT\_LENGTH":"57","HTTP\_COOKIE":[REDACTED],"CONTENT\_TYPE":"application/json","HTTP\_X\_CSRF\_TOKEN":"••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••","HTTP\_CONNECTION":"keep-alive","HTTP\_ACCEPT":"\*/\*","HTTP\_ACCEPT\_ENCODING":"gzip, deflate","HTTP\_USER\_AGENT":"python-requests/2.27.1",[...]}}}
Figure 1: Extract of Craft CMS web logs showing the content of a POST request targeting the endpoint generate-transform
When the return code is 404, it means that the requested asset ID doesn’t exist whilst a return code of 302 means that the asset ID exists and the transformation completed, redirecting the user to the transformed asset.
The script was probably made to stop the search as soon as a valid asset ID is found. Indeed, Craft CMS logs indicates that the asset ID was incremented from 125 to 162 which returned a 302 code whilst the others all returned a 404 code.
103.106.66.123 - - [10/Feb/2025:08:13:46 +0100] "POST /index.php?p=admin/actions/assets/generate-transform HTTP/1.1" 404 25853
103.106.66.123 - - [10/Feb/2025:08:13:46 +0100] "POST /index.php?p=admin/actions/assets/generate-transform HTTP/1.1" 404 25853
103.106.66.123 - - [10/Feb/2025:08:13:47 +0100] "POST /index.php?p=admin/actions/assets/generate-transform HTTP/1.1" 302 -
Figure 2: Extract of access logs showing POST requests targeting the endpoint generate-transform
****Step 2: Checking if the server is vulnerable****
Once a valid asset ID was found, the threat actor tried to determine if the server was vulnerable. They ran a python script that searched again for a valid asset ID – which found the asset ID 11 – and then proceeded to send a POST request to the URI /index.php?p=admin/actions/assets/generate-transform targeting the asset ID 11. The contents of the body has been modified by adding a new field named as session:
[...]