The most dangerous fix is the one that makes you feel safe while leaving the door wide open. CVE-2026-33157 is a textbook example: Craft CMS shipped a patch for a behavior-injection RCE chain, teams updated and moved on — and an entirely parallel code path sat unsanitized the whole time. Any authenticated control panel user, on every Craft CMS installation between versions 5.6.0 and 5.9.12, can leverage this bypass to achieve Remote Code Execution right now. The uncomfortable question for every team running Craft is not just “are we patched?” — it’s “how many other half-fixed vulnerabilities are hiding in our stack?”
What Is CVE-2026-33157?
CVE-2026-33157 is a Remote Code Execution vulnerability rated CVSS 7.2 (HIGH) in Craft CMS, a widely used PHP-based CMS built on top of the Yii2 framework. The vulnerability was published on 2026-03-24 and affects versions 5.6.0 through 5.9.12. It has been resolved in version 5.9.13.
To understand why this CVE matters beyond a routine patch, you need a bit of Yii2 context. Yii2’s configuration system supports a feature called behavior and event injection: by passing specially prefixed keys — "as ..." (behaviors) or "on ..." (event handlers) — inside a configuration array, you can dynamically attach arbitrary PHP code to any Yii2 component. This is a legitimate framework feature, but when user-controlled data flows into a Yii2 config array without stripping those keys, it becomes a direct path to code execution.
How the Original Fix Failed ⚠️
When the original behavior-injection RCE was discovered, the Craft CMS team responded by introducing a cleanseConfig() function. This sanitizer was applied in two places: assembleLayoutFromPost() and various actions inside FieldsController. Both of those touch points now strip the dangerous "as" and "on" prefixed keys before they reach FieldLayout::createFromConfig().
The problem? The same underlying FieldLayout::createFromConfig() function is also called from a completely different controller: ElementIndexesController::actionFilterHud(). This action accepts a fieldLayouts parameter from the request and passes it directly to createFromConfig() — no cleanseConfig(), no sanitization, nothing. The attack chain is functionally identical to the original; only the entry point changed.
In my experience auditing patch coverage, this pattern shows up constantly: the security fix is applied to the symptom locations (the places where the issue was first found), but the root cause — a shared, dangerous function that trusts its callers — goes unaddressed. Every new caller of createFromConfig() is a potential re-entry point. This is exactly why security reviews should validate the entire call graph of any patched function, not just the originally reported code path.
Who Is Affected and What’s the Real Risk?
The official requirement is authenticated control panel access. At CVSS 7.2, that authentication requirement is what keeps this out of the critical tier — but don’t let that number lull you into complacency. In enterprise and agency deployments, the control panel is often accessible to editors, content managers, and freelancers, not just administrators. The realistic attacker population for this vulnerability is significantly wider than “admin-only.”
Consider common real-world scenarios: a compromised editor account via phishing, a disgruntled contractor, or a credential stuffing attack against a CMS login with weak password hygiene. Any of those gives an attacker a foothold in the control panel — and from there, CVE-2026-33157 hands them code execution on the underlying server. If that server runs with overprivileged permissions (common in shared hosting or misconfigured VPS deployments), the blast radius extends to the entire host.
MITRE ATT&CK mappings relevant here include:
- 🔴 T1190 — Exploit Public-Facing Application: Direct exploitation of the CMS endpoint.
- 🔴 T1059 — Command and Scripting Interpreter: PHP-based code execution via injected Yii2 behaviors.
- 🔴 T1078 — Valid Accounts: Exploitation requires authenticated access, making stolen credentials the primary enabler.
- 🔴 T1505.003 — Web Shell: Post-exploitation persistence via dropped web shells is the expected next step after RCE.
🔧 Detection With Wazuh: What to Watch For
Patching to 5.9.13 is the only real fix — but detection-in-depth is your safety net for the window between exposure and remediation, and for the inevitable cases where systems don’t get patched on schedule. Here’s how to build meaningful coverage in Wazuh.
The exploitation attempt will generate a POST request to the element-indexes/filter-hud action endpoint, with a fieldLayouts body parameter containing Yii2 behavior injection keys (as or on prefixed). Your web server or application logs are the first line of telemetry.
Add the following custom Wazuh rule to your local_rules.xml:
<!-- CVE-2026-33157: Craft CMS Yii2 Behavior Injection via ElementIndexesController -->
<group name="craft_cms,rce,cve-2026-33157,">
<rule id="100600" level="12">
<if_group>web_log</if_group>
<url>element-indexes/filter-hud</url>
<match>POST</match>
<description>CVE-2026-33157: Possible Craft CMS RCE bypass attempt via actionFilterHud endpoint</description>
<mitre>
<id>T1190</id>
<id>T1059</id>
</mitre>
<group>attack,exploit,rce</group>
</rule>
<rule id="100601" level="14">
<if_group>web_log</if_group>
<url>element-indexes/filter-hud</url>
<match>POST</match>
<!-- Yii2 behavior/event injection key patterns in decoded request body -->
<regex type="pcre2">fieldLayouts.*?(\\bas\\s|\\bon\\s)</regex>
<description>CVE-2026-33157: Craft CMS Yii2 behavior injection key detected in fieldLayouts parameter — high-confidence RCE attempt</description>
<mitre>
<id>T1190</id>
<id>T1059</id>
</mitre>
<group>attack,exploit,rce,high_confidence</group>
</rule>
</group>
A few notes on operationalizing this: Rule 100600 fires on any POST to the vulnerable endpoint (broad net, will generate noise in active CMS environments). Rule 100601 is the high-fidelity version — it requires the presence of Yii2 injection key patterns in the request body, which means your Wazuh agent needs to be ingesting full request body logging from your web server or WAF. Enable Nginx/Apache access log enrichment or route your WAF logs into Wazuh to make rule 100601 effective.
Complement detection with File Integrity Monitoring (FIM). If exploitation succeeds, a web shell drop or PHP file modification is the immediate next step. Configure Wazuh FIM to monitor your Craft CMS web/ and storage/ directories for unexpected file creation:
<!-- ossec.conf FIM addition for Craft CMS web shell detection -->
<syscheck>
<directories check_all="yes" realtime="yes" report_changes="yes">/var/www/html/web</directories>
<directories check_all="yes" realtime="yes" report_changes="yes">/var/www/html/storage</directories>
<!-- Alert on new PHP files in web-accessible directories -->
<alert_new_files>yes</alert_new_files>
</syscheck>
In our enterprise deployments, combining real-time FIM on CMS document roots with WAF log ingestion catches post-exploitation activity even when the initial exploit request slips through. Defense-in-depth isn’t a buzzword here — it’s the difference between a contained incident and a full compromise. If you’re thinking about how to layer detection like this across your broader stack, the approach we covered in the Rails CVE-2026-33174 analysis is worth reviewing as a parallel framework.
🛡️ What to Do Right Now
- Update immediately. Upgrade all Craft CMS installations to version 5.9.13 or later. There is no workaround — the vulnerable endpoint is core functionality. If you can’t patch today, restrict control panel access to trusted IP ranges at the network perimeter as a stopgap.
- Audit your CP user list. Pull every account with control panel access and ask whether each one genuinely needs it. Remove stale accounts, contractors who have left, and anyone with permissions beyond their role. Credential compromise is the prerequisite for this exploit — shrinking the authorized user pool shrinks your exposure.
- Enable MFA on all CP accounts. CVSS 7.2 depends on authenticated access. Multi-factor authentication raises the bar for that authentication step substantially. If your Craft deployment doesn’t enforce MFA today, make it a blocker before end of week.
- Deploy Wazuh detection rules and FIM. Use the rules provided above. Pair them with real-time FIM on your CMS web root. Set alert thresholds that will page on-call for level 14 alerts — this is not a “review in the morning” severity.
- Review your patch validation process. This CVE exists because patch coverage wasn’t validated across the entire call graph of
createFromConfig(). Ask your team: when a security fix is applied, do you audit all callers of the patched function, or just the reported entry point? If the answer is the latter, that’s a process gap worth addressing now, not after the next bypass. - Check for indicators of prior compromise. If you’ve been running an affected version since it shipped, review web server access logs for POST requests to
element-indexes/filter-hud— particularly any with unusual session origins or outside business hours. An attacker who exploited this before the patch dropped may already have persistence on your server.
The lesson of CVE-2026-33157 isn’t just “patch faster.” It’s that partial fixes create a dangerous illusion of security. When you tell your team “we patched the RCE,” but the underlying dangerous pattern still exists in a parallel code path, you’ve traded a known vulnerability for an unknown one. That’s arguably worse. Security engineers should treat every patch as a hypothesis to be tested — not a problem to be closed. If you’re interested in how similar bypass patterns play out in other stacks, our analysis of CVE-2026-33046 in Indico covers another case where an incomplete input sanitization assumption led to full RCE via an unexpected code path.
Original source: https://nvd.nist.gov/vuln/detail/CVE-2026-33157
Bir Cevap Yazın