The PoC of CVE-2026-44011: Craft CMS RCE with an authenticated user.
For authorized testing only.
The Craft CMS advisory lists >=4.0.0, <4.17.12 and >=5.0.0, <5.9.18 as affected, and credits precicom-vincent-tl as finder.
python -m pip install -r requirements.txt
python cve-2026-44011.py -b 'https://example.com' -u '<username' -p '<password>' -c '<command>'
Required arguments:
-b, --base-url: Craft URL, including http:// or https://.-u, --username: Control-panel username.-p, --password: Control-panel password.-c, --command: Command to execute and capture output from.Optional arguments:
-P, --cp-path: Control-panel path (default: /admin).-s, --site-id: Site ID (default: 1).-e, --element-type: Element type (default: craft\elements\Category).-f, --csrf-field: Login CSRF field name (default: CRAFT_CSRF_TOKEN).-t, --timeout: Request and callback timeout in seconds (default: 15).-F, --force: Continue when the Craft version is unavailable or outside the advisory ranges.-H, --callback-host: Address the target can reach (local address inferred by default; override it behind a pivot).--listen-port: Listener port (default: an OS-selected free port; set a fixed port for forwarding).In the vulnerable search action, condition goes from the POST body into object creation without cleansing.
$conditionConfig = $this->request->getBodyParam('condition');
$condition = Craft::$app->getConditions()->createCondition($conditionConfig);
ElementCondition::setFieldLayouts() constructs a layout from each supplied array.
if (is_array($fieldLayout)) {
$fieldLayout['type'] = $this->elementType;
return $fieldsService->createLayout($fieldLayout);
}
The advisory payload attaches Yii's AttributeTypecastBehavior with an as key and wires an event with on *. The behavior reaches Psy\Readline\Hoa\ConsoleProcessus::execute through Yii's callable typecast.
condition.fieldLayouts[]
-> FieldLayout behavior + event
-> AttributeTypecastBehavior::typecastValue()
-> call_user_func()
-> ConsoleProcessus::execute()
The fixed controller applies Component::cleanseConfig() to the condition before object creation.
ConsoleProcessus::execute() escapes shell metacharacters by default. The PoC serves a temporary script to run -c, receives its output on a built-in HTTP listener, and shuts the listener down afterward. Use -H if the target cannot reach the inferred address.sh, curl, and mktemp on the target.python -m unittest discover -s tests -v.