highJul 9, 2026

CVE-2026-56382: Craft CMS RCE via Yii2 Event Handler Injection in FieldsController

Shubham Kandhare
Security Engagement Manager, SecureLayer7

An authenticated Craft CMS admin can execute arbitrary PHP code by injecting a Yii2 event handler into a POST parameter that the card-preview endpoint passes directly to the object factory without san

Packagecraftcms/cms
Ecosystemcomposer
Affected>= 5.5.0, <= 5.9.13
Fixed in5.9.14

The problem

The `actionRenderCardPreview()` method in `FieldsController` reads the `fieldLayoutConfig` POST body and spreads it directly into `Craft::createObject()` to build a `FieldLayout` instance. No call to `Component::cleanseConfig()` was made, so Yii2 "on eventName" keys were accepted as legitimate event handler registrations.

Any admin with a valid session and CSRF token can POST a config containing `on init` set to any callable PHP function. When Yii2 constructs the component and fires the `init` event, the callable executes immediately, with the output (including `phpinfo` environment variables such as `CRAFT_SECURITY_KEY` and database credentials) returned in the HTTP response.

Proof of concept

A working proof-of-concept for this issue in craftcms/cms, with the exact payload below.

http
POST /index.php?p=admin/actions/fields/render-card-preview HTTP/1.1
Host: target.example.com
Content-Type: application/x-www-form-urlencoded
Cookie: CraftSessionId=<valid-session-cookie>

CSRF_TOKEN=<valid-csrf-token>&fieldLayoutConfig[on+init]=phpinfo

The root cause is CWE-94: the `fieldLayoutConfig` array was spread into `Craft::createObject()` verbatim. Yii2 treats any config key matching the pattern `on <eventName>` as an event handler registration, so `on init` becomes a registered listener that fires during `Component::init()`.

The patch (commit 27f55886) wraps the input in `Component::cleanseConfig()` before spreading it, which strips all keys prefixed with `on ` or `as ` before they reach the Yii2 object factory. This is the same pattern that was missing here but correctly applied in the nearby `_fldComponent()` method and in sibling controllers (EntryTypesController, ElementIndexesController).

Because `phpinfo()` is a valid PHP callable, the basic PoC leaks full environment state with no further setup. Replacing it with `shell_exec` or `system` escalates to full OS command execution.

The fix

Update `craftcms/cms` to version 5.9.14 or later. The fix is a one-line change: wrap the user-supplied `$fieldLayoutConfig` array in `Component::cleanseConfig()` before passing it to `Craft::createObject()`. If immediate upgrade is not possible, restrict admin-panel access to trusted networks and rotate `CRAFT_SECURITY_KEY` and database credentials as a precaution.

Reporter not attributed.

References: [1][2]

Related research