CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2024-58136
9.867.06%

The Doppelgänger Class: How a Failed Fix in Yii 2 Led to Mass RCE

Alon Barad
Alon Barad
Software Engineer

Feb 26, 2026·5 min read·47 visits

Active ExploitationCISA KEV Listed

Executive Summary (TL;DR)

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.

The Hook: A Tale of Two Patches

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.

The Flaw: Logic vs. Reality

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:

  1. class: "SafeBehavior" (The bouncer checks this. It's safe. Pass.)
  2. __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.

The Code: The Smoking Gun

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."

The Exploit: Weaponizing the Shadow Key

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:

  1. as trigger: Tells Yii to attach a behavior named "trigger".
  2. class: Points to AttributeBehavior. This satisfies the security check in 2.0.51.
  3. __class: Points to FnStream. This is what Yii::createObject actually builds.
  4. _fn_close: The property on FnStream that holds the function name to call on destruction (system).
  5. close: The argument passed to the function.

When the request ends, the FnStream object is destroyed, system('id') is executed, and the attacker wins.

The Impact: From CMS to C2

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:

  1. Drop Web Shells: Persistent access via standard PHP shells.
  2. Exfiltrate Configs: Stealing db.php or .env files to get database credentials.
  3. Lateral Movement: Using the compromised server to attack internal networks or send spam.

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.

The Fix: Stop the Bleeding

If you are running Yii 2, check your composer.json immediately. If your version is < 2.0.52, you are vulnerable.

Remediation Steps:

  1. Update: Run composer update yiisoft/yii2. Ensure you land on at least 2.0.52.
  2. Craft CMS: Update to the latest version immediately (e.g., Craft 4.10.2+ or 5.2.3+).
  3. Verify: Check your 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.

Official Patches

YiiSoftOfficial advisory urging upgrade to 2.0.52

Fix Analysis (1)

Technical Appendix

CVSS Score
9.8/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H
EPSS Probability
67.06%
Top 1% most exploited

Affected Systems

Yii Framework < 2.0.52Craft CMS (versions utilizing vulnerable Yii)Any PHP application utilizing Yii 2 component configuration via user input

Affected Versions Detail

Product
Affected Versions
Fixed Version
Yii Framework
YiiSoft
< 2.0.522.0.52
Craft CMS
Pixel & Tonic
Various (depends on Yii version)Latest Stable
AttributeDetail
CWE IDCWE-502 (Deserialization of Untrusted Data)
CVSS v3.19.8 (Critical)
Attack VectorNetwork (Remote)
ImpactRemote Code Execution (RCE)
Exploit StatusActive / Weaponized
KEV StatusListed (2025-05-02)

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1059.003Command and Scripting Interpreter: Windows Command Shell
Execution
T1203Exploitation for Client Execution
Execution
CWE-502
Deserialization of Untrusted Data

The application deserializes untrusted data without sufficiently verifying that the resulting data will be valid.

Known Exploits & Detection

SensePostAnalysis of in-the-wild campaign targeting Craft CMS using this Yii gadget chain.
GitHubCommit demonstrating the regression fix.
NucleiDetection Template Available

Vulnerability Timeline

Yii 2.0.51 released (Fixes CVE-2024-4990, introduces regression)
2024-07-18
Regression identified and fixed in code (Commit 40fe496)
2024-07-24
Active in-the-wild exploitation detected (Craft CMS campaigns)
2025-02-10
Added to CISA KEV Catalog
2025-05-02

References & Sources

  • [1]NVD - CVE-2024-58136
  • [2]Original Advisory Context
Related Vulnerabilities
CVE-2024-4990CVE-2025-32432

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.