# Craft CMS Vulnerable to potential authenticated Remote Code Execution via malicious attached Behavior

Craft CMS assembleLayoutFromPost() passes unsanitized fieldLayout JSON to Craft::createObject(), letting admins inject an AttributeTypecastBehavior that runs shell commands via ConsoleProcessus::execute.

- Payout: Research
- Severity: high
- Program: Craft CMS
- Found by: RajChowdhury240, rlarabee
- Disclosed: 2026-02-09
- CVE: CVE-2026-25498
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-7jx7-3846-m7w7
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-7jx7-3846-m7w7
- Tags: area:web domain:web impact:rce kind:research platform:ghsa sev:high tech:php technique:chained technique:incomplete-fix technique:source-review vuln:deserialization vuln:rce

**Target:** Admin field layout save endpoints (Fields.php assembleLayoutFromPost)
**Root cause:** assembleLayoutFromPost() decodes the user-supplied fieldLayout POST param and passes it to Craft::createObject() without cleanseConfig(), so Yii2's 'as <behavior>' config key attaches an attacker-chosen behavior.
**Steps:**
1. Authenticate as admin and reach an endpoint calling assembleLayoutFromPost() (e.g. TagsController actionSaveTagGroup).
2. POST a `fieldLayout` JSON body containing an `as rce` key configuring `AttributeTypecastBehavior` with `typecastAfterValidate` and `attributeTypes` mapping `uid` to `['Psy\Readline\Hoa\ConsoleProcessus','execute']`.
3. Submit the form so createLayout() calls Craft::createObject($config), attaching the behavior via Component::__set().
4. Model validate() fires EVENT_AFTER_VALIDATE, typecastAttributes() runs call_user_func with the uid value as the shell command.
**How found:** Followed up on GHSA-255j-qw47-wjh5: same 'as <behavior>' injection pattern but found a different unpatched code path (assembleLayoutFromPost in Fields.php) using typecastAfterValidate instead of typecastBeforeSave, without needing the wildcard event listener.
**Exploitation:** Admin submits crafted fieldLayout JSON; Yii2 attaches AttributeTypecastBehavior; on validate() the after-validate typecast invokes ConsoleProcessus::execute with the uid attribute as command, yielding OS command execution as the web user.
**Insight:** When a behavior-injection fix patches specific routes, grep for other callers of the same sink (Craft::createObject with request-derived config) — sibling code paths often skip the added cleanseConfig() and can trigger the gadget via a different event (afterValidate vs beforeSave).

