CVE-2025-55182: React Server Components Deserialization Vulnerability
Overview
CVE-2025-55182 is a critical vulnerability in React Server Components that allows attackers to pollute JavaScript prototypes through malicious deserialization, leading to authentication bypass, privilege escalation, and potential remote code execution.
CVSS Score: 9.8 (Critical)
Discovered: January 2025
Affects: Next.js applications using Server Actions and Server Components
Also Known As: React2Shell
The Vulnerability Explained
How React Server Components Work
React Server Components use a protocol called React Flight to serialize and deserialize data between client and server:
// Client sends data to server
const result = await serverAction({
username: "john",
email: "john@example.com"
});
// React Flight serializes this as:
// M1:{"username":"john","email":"john@example.com"}
// Server deserializes and processes
The Flaw
React Flight's deserialization process doesn't validate dangerous object keys before processing:
// Attacker sends this payload
{
"__proto__": {
"isAdmin": true
}
}
// React deserializes it as:
Object.assign({}, JSON.parse(payload));
// This pollutes Object.prototype
Object.prototype.isAdmin = true;
// Now EVERY object has isAdmin: true
const user = {};
console.log(user.isAdmin); // true ⚠️
Technical Details
Attack Vector 1: Prototype Pollution via proto
// Malicious client request
POST /api/user/update
{
"name": "John",
"__proto__": {
"isAdmin": true,
"canExecute": true,
"role": "superadmin"
}
}
// Server-side code (vulnerable)
export async function updateUser(data) {
// React deserializes data with Object.assign
const user = Object.assign({}, data);
// Prototype pollution occurred
// Object.prototype now has: isAdmin, canExecute, role
// Check admin status (BYPASSED!)
if (user.isAdmin) {
// Any user can now access admin functions
return executeAdminAction();
}
}
Result:
Object.prototype.isAdmin = true- All subsequent objects inherit
isAdmin - Authentication completely bypassed
Attack Vector 2: Constructor Manipulation
// Attacker payload
{
"username": "attacker",
"constructor": {
"prototype": {
"isVerified": true,
"permissions": ["read", "write", "delete"]
}
}
}
// Affects all objects created with Object constructor
const newUser = {};
console.log(newUser.isVerified); // true
console.log(newUser.permissions); // ["read", "write", "delete"]
Result:
- Constructor prototype modified
- All new objects inherit malicious properties
- Authorization checks bypassed
Attack Vector 3: Nested Payload Bypass
// Sophisticated attack hiding pollution deep
{
"profile": {
"settings": {
"preferences": {
"theme": "dark",
"__proto__": {
"authenticated": true,
"sessionValid": true
}
}
}
}
}
// Shallow validation misses deep pollution
// Application processes it and gets compromised
Result:
- Deep nesting bypasses shallow validators
- WAFs don't catch it
- Prototype pollution succeeds
Attack Vector 4: Ghost Mode (Encoding Bypass)
// Attacker uses UTF-16LE encoding
POST /api/data
Content-Type: application/json; charset=utf-16le
// Binary payload (UTF-16LE):
[0xFF, 0xFE, 0x7B, 0x00, 0x22, 0x00, 0x5F, 0x00, 0x5F, 0x00, ...]
// WAF sees: ÿþ{�"�_�_�p�r�o�t�o�_�_�
// Application decodes to: {"__proto__": {...}}
Result:
- WAF completely bypassed
- Application receives malicious payload
- Attack undetected
Real-World Exploitation Scenarios
Scenario 1: E-Commerce Platform
// Vulnerable checkout process
export async function processOrder(orderData) {
const order = await deserialize(orderData);
// Check if user has premium shipping
if (order.premiumShipping) {
// Apply free shipping
}
// Check discount eligibility
if (order.discountEligible) {
// Apply 50% discount
}
}
// Attacker sends:
{
"items": ["product1", "product2"],
"__proto__": {
"premiumShipping": true,
"discountEligible": true,
"price": 0
}
}
// Result:
// - Free premium shipping
// - 50% discount applied
// - Price set to 0
// - Financial fraud
Scenario 2: Social Media Platform
// Vulnerable content moderation
export async function publishPost(postData) {
const post = await deserialize(postData);
// Check if user is moderator
if (post.author.isModerator) {
// Skip content moderation
await publishDirectly(post);
}
}
// Attacker sends:
{
"content": "Spam content here",
"author": {
"id": "attacker123",
"__proto__": {
"isModerator": true,
"isVerified": true
}
}
}
// Result:
// - Content moderation bypassed
// - Spam published immediately
// - Platform reputation damaged
Scenario 3: Banking Application
// Vulnerable transaction processing
export async function transferMoney(transferData) {
const transfer = await deserialize(transferData);
// Verify transaction limits
if (transfer.verified && transfer.withinLimit) {
await executeTransfer(transfer);
}
}
// Attacker sends:
{
"from": "attacker_account",
"to": "attacker_account_2",
"amount": 1000000,
"__proto__": {
"verified": true,
"withinLimit": true,
"approved": true
}
}
// Result:
// - Verification bypassed
// - Unlimited transfers
// - Financial theft
How nextjs-fortress Prevents This
Layer 1: Dangerous Keys Detection
// Blocks __proto__, constructor, prototype
private checkDangerousKeys(obj: unknown): ValidationResult {
const keys = Reflect.ownKeys(obj); // Gets ALL keys including non-enumerable
for (const key of keys) {
if (this.blockList.has(key.toLowerCase())) {
return {
valid: false,
severity: 'critical',
message: `Dangerous key detected: "${key}"`,
rule: 'dangerous_key',
confidence: 1.0,
};
}
}
}
Layer 2: Depth Limiting
// Prevents deeply nested attacks
private checkDepth(obj: unknown, depth: number): ValidationResult {
if (depth > this.config.maxDepth) {
return {
valid: false,
message: 'Nesting depth exceeded',
rule: 'max_depth_exceeded',
};
}
}
Layer 3: Pattern Detection
// Detects React Flight exploitation markers
const patterns = [
'resolved_model', // React internal
'_response', // RSC marker
'_prefix', // Malware dropper
];
for (const pattern of patterns) {
if (stringified.includes(pattern)) {
return { valid: false };
}
}
Layer 4: Encoding Validation
// Blocks UTF-16LE Ghost Mode bypass
if (bytes[0] === 0xFF && bytes[1] === 0xFE) {
return {
valid: false,
message: 'UTF-16LE BOM detected (Ghost Mode)',
rule: 'bom_utf16le',
};
}
Affected Versions
Next.js
- Next.js 13.0.0 - 13.5.6
- Next.js 14.0.0 - 14.2.18
- Next.js 15.0.0 - 15.1.3
React
- React 18.0.0+
- All versions with Server Components
Mitigation Timeline
January 5, 2025 - Vulnerability discovered
January 6, 2025 - nextjs-fortress v1.0.0 released
January 10, 2025 - Next.js patches released
January 15, 2025 - Widespread exploitation attempts
Protection Checklist
✅ Install nextjs-fortress
✅ Enable deserialization validation
✅ Configure dangerous key blocking
✅ Enable depth limiting
✅ Turn on encoding validation
✅ Monitor security events
✅ Update Next.js to patched version
Testing for Vulnerability
Test 1: Basic Prototype Pollution
curl -X POST http://localhost:3000/api/test \
-H "Content-Type: application/json" \
-d '{"__proto__": {"isAdmin": true}}'
# Vulnerable: 200 OK
# Protected: 403 Forbidden
Test 2: Constructor Attack
curl -X POST http://localhost:3000/api/test \
-H "Content-Type: application/json" \
-d '{"constructor": {"prototype": {"hacked": true}}}'
# Vulnerable: 200 OK
# Protected: 403 Forbidden
Test 3: Nested Attack
curl -X POST http://localhost:3000/api/test \
-H "Content-Type: application/json" \
-d '{"a":{"b":{"c":{"d":{"e":{"f":{"g":{"h":{"i":{"j":{"k":{"__proto__":{"bad":true}}}}}}}}}}}}}'
# Vulnerable: 200 OK (if no depth limit)
# Protected: 403 Forbidden (depth exceeded)
Test 4: Ghost Mode
# Send UTF-16LE encoded payload
curl -X POST http://localhost:3000/api/test \
-H "Content-Type: application/json; charset=utf-16le" \
--data-binary @malicious_utf16le.bin
# Vulnerable: 200 OK
# Protected: 403 Forbidden (encoding blocked)
How to Deploy Protection
// fortress.config.ts
import { FortressConfig } from 'nextjs-fortress';
export const fortressConfig: FortressConfig = {
enabled: true,
mode: 'production',
modules: {
// PRIMARY DEFENSE against CVE-2025-55182
deserialization: {
enabled: true,
maxDepth: 10,
detectCircular: true,
blockList: [
'__proto__',
'constructor',
'prototype',
],
dangerousPatterns: [
'resolved_model',
'_response',
'_prefix',
],
},
// SECONDARY DEFENSE - Ghost Mode protection
encoding: {
enabled: true,
blockNonUTF8: true,
detectBOM: true,
},
// TERTIARY DEFENSE - Additional injection protection
injection: {
enabled: true,
checks: ['sql', 'command', 'xss', 'codeInjection'],
},
},
};
Summary
CVE-2025-55182 enables:
- Prototype pollution
- Authentication bypass
- Privilege escalation
- Remote code execution
nextjs-fortress protects by:
- Blocking dangerous keys
- Limiting payload depth
- Detecting attack patterns
- Preventing encoding bypasses
Deploy protection immediately:
deserialization: {
enabled: true,
maxDepth: 10,
detectCircular: true,
}
Related Documentation: