Feb 26, 2026·5 min read·124 visits
A critical RCE in Yii 2 (< 2.0.52) caused by a regression in a previous security fix. Attackers bypass class validation by using the `__class` key instead of `class`, allowing arbitrary object instantiation and code execution. Actively exploited.
History has a funny way of repeating itself, especially in PHP frameworks. CVE-2024-58136 is not just a vulnerability; it is a masterclass in how 'patching' can sometimes just mean 'moving the target.' In July 2024, the Yii team patched a critical RCE (CVE-2024-4990) involving behavior attachments. They added a check. It looked solid. But they forgot one tiny detail about their own Dependency Injection container: it speaks two languages. By simply using `__class` instead of `class`, attackers could bypass the check entirely, leading to active exploitation in the wild, particularly devastating for Craft CMS installations.
In the world of secure coding, the most dangerous moment is often immediately after a patch is released. Why? Because developers relax, and hackers start diffing. In July 2024, Yii Framework released version 2.0.51 to fix a nasty Remote Code Execution bug (CVE-2024-4990). The issue was simple: you could attach 'behaviors' (mixins) to components via user input, and if you attached a malicious class, you got RCE.
The fix seemed logical: before attaching a behavior, check if the requested class is actually a subclass of yii\base\Behavior. It’s like checking ID at the door of a club. If you aren't on the list, you don't get in.
But here is where the plot twists. The Yii Dependency Injection (DI) container is a polyglot. It accepts definitions in multiple formats. The developers checked one format (class), but the DI container happily prioritizes another (__class). It’s like the bouncer checking your ID, but the bartender serving anyone who whispers a secret password. This oversight turned a 'security fix' into a blueprint for bypass.
To understand this vulnerability, you have to understand how Yii creates objects. The Yii::createObject($config) method is the heart of the framework. It takes a configuration array and spits out an object. Usually, you specify the type of object using the class key.
However, for historical reasons or advanced configuration merging, Yii also supports __class. When Yii::createObject receives an array, it looks for __class first. If found, it uses that class name. If not, it falls back to class.
The vulnerability lies in yii\base\Component::__set. This magic method handles property assignment. When you try to assign a configuration to a property like as myBehavior, Yii attempts to attach it. In version 2.0.51, the code validated config['class']. It ensured config['class'] was a safe Behavior subclass.
But then it passed the entire config array to Yii::createObject.
So, if an attacker sends a payload with both keys:
class: "SafeBehavior" (The bouncer checks this. It's safe. Pass.)__class: "MaliciousGadget" (The factory uses this. It's deadly. Boom.)The validation logic and the execution logic were looking at different parts of the same data structure. This is a classic "Time-of-Check to Time-of-Use" (TOCTOU) style logic error, but purely with array keys.
Let's look at the diff. It is painfully simple, which makes it all the more tragic.
Here is the vulnerable code in 2.0.51:
// yii/base/Component.php
} elseif (isset($value['class']) && is_subclass_of($value['class'], Behavior::class, true)) {
// The check passes if 'class' is valid.
// But createObject might use '__class' if it exists in $value!
$this->attachBehavior($name, Yii::createObject($value));
}And here is the fix in 2.0.52:
// yii/base/Component.php
} elseif (
(isset($value['class']) && is_subclass_of($value['class'], Behavior::class)) ||
// NOW we check __class too
(isset($value['__class']) && is_subclass_of($value['__class'], Behavior::class))
) {
$this->attachBehavior($name, Yii::createObject($value));
}The fix is literally just acknowledging the existence of the shadow key. If you are a developer, write this on a sticky note: "Validate the data you use, not the data you expect."
So how do we turn this into a shell? We need a target application that allows user input to flow into a component configuration. Craft CMS was the unlucky winner here, exposing this via image transform settings.
The attack requires a "Gadget"—a PHP class that does something dangerous when instantiated or destructed. A classic favorite in the PHP ecosystem is GuzzleHttp\Psr7\FnStream. This class has a destructor that calls a user-defined function.
Here is what a weaponized JSON payload looks like:
{
"as trigger": {
"class": "yii\\behaviors\\AttributeBehavior",
"__class": "GuzzleHttp\\Psr7\\FnStream",
"__construct()": [[]],
"_fn_close": "system",
"methods": {
"close": "id"
}
}
}The Breakdown:
as trigger: Tells Yii to attach a behavior named "trigger".class: Points to AttributeBehavior. This satisfies the security check in 2.0.51.__class: Points to FnStream. This is what Yii::createObject actually builds._fn_close: The property on FnStream that holds the function name to call on destruction (system).close: The argument passed to the function.When the request ends, the FnStream object is destroyed, system('id') is executed, and the attacker wins.
This isn't theoretical. This is in the CISA Known Exploited Vulnerabilities (KEV) catalog. Attackers are actively scanning the internet for unpatched Yii applications, specifically Craft CMS.
Once RCE is achieved, the game is over. In the wild, we've seen attackers using this to:
db.php or .env files to get database credentials.Because this runs as the web server user (usually www-data), the attacker has full read/write access to the webroot. In modern containerized environments, they might just steal environment variables and move on. In legacy VPS hosting, they own the box.
If you are running Yii 2, check your composer.json immediately. If your version is < 2.0.52, you are vulnerable.
Remediation Steps:
composer update yiisoft/yii2. Ensure you land on at least 2.0.52.vendor/yiisoft/yii2/base/Component.php file manually if you cannot update immediately. Look for the __class check in __set.If you cannot patch (why?), you can try to mitigate this at the WAF level by blocking requests containing __class in the body, but this is risky and prone to false positives or bypasses (e.g., JSON encoding variations). Patching is the only real fix.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
Yii Framework YiiSoft | < 2.0.52 | 2.0.52 |
Craft CMS Pixel & Tonic | Various (depends on Yii version) | Latest Stable |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-502 (Deserialization of Untrusted Data) |
| CVSS v3.1 | 9.8 (Critical) |
| Attack Vector | Network (Remote) |
| Impact | Remote Code Execution (RCE) |
| Exploit Status | Active / Weaponized |
| KEV Status | Listed (2025-05-02) |
The application deserializes untrusted data without sufficiently verifying that the resulting data will be valid.
An unauthenticated remote code execution (RCE) vulnerability exists in phoenix_storybook versions 0.5.0 through 1.0.x due to improper input sanitization during HEEx template generation. By sending crafted WebSocket messages, an attacker can escape HTML attribute boundaries and execute arbitrary Elixir code.
An unauthenticated Denial-of-Service (DoS) vulnerability exists in phoenix_storybook versions 0.2.0 through 1.0.11 due to allocation of resources without limits (CWE-770). The application dynamically converts user-supplied parameter keys to atoms, leading to BEAM Atom Table exhaustion and immediate virtual machine crash.
A security vulnerability in the Elixir package phoenix_storybook (versions 0.4.0 up to 1.1.0) allows unauthenticated remote attackers to perform cross-session PubSub topic injection. By manipulating URL parameters, an attacker can hijack the real-time communications channel, enabling them to capture user state and control parameters from active sessions.
An improper authorization vulnerability in the unreleased development master branch of Dex allows clients to bypass the AllowedConnectors access control list using the token-exchange endpoint.
CVE-2024-29203 identifies a cross-site scripting (XSS) vulnerability in the content ingestion and parsing mechanics of TinyMCE rich text editor. Due to a failure to enforce sandbox attributes on dynamic iframe elements and safely handle legacy embed objects, unauthenticated attackers can inject malicious elements that execute scripts within the context of the parent application session.
A technical breakdown of the OS command injection vulnerability in the shell-quote NPM package (CVE-2026-9277 / GHSA-w7jw-789q-3m8p). The bug resides in the character-by-character backslash-escaping logic applied to the .op field of object-tokens within the quote() function, which fails to match and escape line terminators due to a regex matching oversight in JavaScript. This allows unauthenticated remote attackers to execute arbitrary shell commands if they can control inputs processed by this library.