[PR #9164] [MERGED] fix(stripe): prevent prototype pollution via user-supplied metadata #25379

Closed
opened 2026-04-15 22:51:41 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/better-auth/better-auth/pull/9164
Author: @gustavovalverde
Created: 4/14/2026
Status: Merged
Merged: 4/14/2026
Merged by: @gustavovalverde

Base: mainHead: fix/stripe-defu-prototype-pollution


📝 Commits (1)

  • 29d323b fix(stripe): drop unsafe keys when merging user-supplied metadata

📊 Changes

5 files changed (+112 additions, -36 deletions)

View changed files

.changeset/fix-stripe-defu-prototype-pollution.md (+7 -0)
📝 packages/stripe/package.json (+1 -1)
📝 packages/stripe/src/metadata.ts (+24 -23)
packages/stripe/test/metadata.test.ts (+63 -0)
📝 pnpm-lock.yaml (+17 -12)

📄 Description

The Stripe plugin previously merged ctx.body.metadata through defu, which is vulnerable to prototype pollution when attacker-controlled __proto__ keys reach the second argument (GHSA-737v-mqg7-c878).

Stripe metadata is a flat Record<string, string>, so defu's deep-merge semantics were never exercised on that path. Replacing it with an inline merge that drops __proto__, constructor, and prototype keys eliminates the attack surface rather than tracking upstream patches, and also drops the need for defu on the user-input side.

The two remaining defu call sites in index.ts and routes.ts deep-merge developer-supplied CustomerCreateParams where inputs are trusted; they continue to use defu and receive the patched range via the bumped dependency.

The regression test covers three payload shapes (__proto__, constructor.prototype, and flat values) across both customerMetadata.set and subscriptionMetadata.set, asserts on the returned object's prototype chain (not just Object.prototype), and includes a precedence test to keep the internal-fields-win invariant under guard.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/better-auth/better-auth/pull/9164 **Author:** [@gustavovalverde](https://github.com/gustavovalverde) **Created:** 4/14/2026 **Status:** ✅ Merged **Merged:** 4/14/2026 **Merged by:** [@gustavovalverde](https://github.com/gustavovalverde) **Base:** `main` ← **Head:** `fix/stripe-defu-prototype-pollution` --- ### 📝 Commits (1) - [`29d323b`](https://github.com/better-auth/better-auth/commit/29d323bf396f1d4ed19cc430dfb0c87e75fd946c) fix(stripe): drop unsafe keys when merging user-supplied metadata ### 📊 Changes **5 files changed** (+112 additions, -36 deletions) <details> <summary>View changed files</summary> ➕ `.changeset/fix-stripe-defu-prototype-pollution.md` (+7 -0) 📝 `packages/stripe/package.json` (+1 -1) 📝 `packages/stripe/src/metadata.ts` (+24 -23) ➕ `packages/stripe/test/metadata.test.ts` (+63 -0) 📝 `pnpm-lock.yaml` (+17 -12) </details> ### 📄 Description The Stripe plugin previously merged `ctx.body.metadata` through `defu`, which is vulnerable to prototype pollution when attacker-controlled `__proto__` keys reach the second argument (GHSA-737v-mqg7-c878). Stripe metadata is a flat `Record<string, string>`, so `defu`'s deep-merge semantics were never exercised on that path. Replacing it with an inline merge that drops `__proto__`, `constructor`, and `prototype` keys eliminates the attack surface rather than tracking upstream patches, and also drops the need for `defu` on the user-input side. The two remaining `defu` call sites in `index.ts` and `routes.ts` deep-merge developer-supplied `CustomerCreateParams` where inputs are trusted; they continue to use `defu` and receive the patched range via the bumped dependency. The regression test covers three payload shapes (`__proto__`, `constructor.prototype`, and flat values) across both `customerMetadata.set` and `subscriptionMetadata.set`, asserts on the returned object's prototype chain (not just `Object.prototype`), and includes a precedence test to keep the internal-fields-win invariant under guard. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-04-15 22:51:41 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#25379