[PR #9134] fix(auth)!: gate dynamic baseURL proxy headers behind trustedProxyHeaders #16706

Open
opened 2026-04-13 10:39:06 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/better-auth/better-auth/pull/9134
Author: @gustavovalverde
Created: 4/12/2026
Status: 🔄 Open

Base: 2026-04-11/fix/dynamic-baseurl-api-callsHead: 2026-04-12/security/dynamic-baseurl-proxy-trust-default


📝 Commits (1)

  • 6294885 fix(auth)!: gate dynamic baseURL proxy headers behind trustedProxyHeaders

📊 Changes

6 files changed (+141 additions, -46 deletions)

View changed files

.changeset/proxy-trust-default-dynamic.md (+29 -0)
📝 packages/better-auth/src/auth/base.ts (+5 -1)
📝 packages/better-auth/src/auth/full.test.ts (+7 -0)
📝 packages/better-auth/src/context/helpers.ts (+8 -1)
📝 packages/better-auth/src/utils/url.test.ts (+57 -21)
📝 packages/better-auth/src/utils/url.ts (+35 -23)

📄 Description

Security hardening split out from #9131.

Problem

The static-config baseURL path already required advanced.trustedProxyHeaders: true to honor x-forwarded-host / x-forwarded-proto. The dynamic (allowedHosts) path trusted them implicitly, so deployments that don't strip client-supplied x-forwarded-* let an attacker pivot between any two hosts listed in allowedHosts via header spoofing.

This aligns the two paths: proxy headers are now ignored unless the user explicitly opts in with trustedProxyHeaders: true.

Migration

Dynamic configs deployed behind a reverse proxy that only exposes the public hostname via x-forwarded-host need to add:

betterAuth({
  baseURL: { allowedHosts: [...] },
  advanced: {
    trustedProxyHeaders: true,
  },
});

Setups where the proxy rewrites Host: to the public hostname (nginx default, Vercel, Cloudflare, Netlify) are unaffected.

Scope

Small, focused on the security default only. The DX and correctness fixes from the same bug class (direct auth.api calls, MCP/OAuth-provider metadata forwarding, APIError on unresolvable, etc.) ship in #9131.

Related: #9105


Summary by cubic

Hardened dynamic baseURL resolution in better-auth by ignoring x-forwarded-host and x-forwarded-proto unless advanced.trustedProxyHeaders is true. This aligns allowedHosts with static configs and prevents header-spoofing pivots between allowed hosts.

  • Migration
    • If using baseURL.allowedHosts behind a proxy that exposes the public hostname via x-forwarded-host, set advanced.trustedProxyHeaders: true.
    • No changes needed when the proxy rewrites Host to the public hostname (nginx default, Vercel, Cloudflare, Netlify).

Written for commit 6294885e64. Summary will update on new commits.


🔄 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/9134 **Author:** [@gustavovalverde](https://github.com/gustavovalverde) **Created:** 4/12/2026 **Status:** 🔄 Open **Base:** `2026-04-11/fix/dynamic-baseurl-api-calls` ← **Head:** `2026-04-12/security/dynamic-baseurl-proxy-trust-default` --- ### 📝 Commits (1) - [`6294885`](https://github.com/better-auth/better-auth/commit/6294885e64c810c4d7b0eb6bf8c3842c98b5e631) fix(auth)!: gate dynamic baseURL proxy headers behind trustedProxyHeaders ### 📊 Changes **6 files changed** (+141 additions, -46 deletions) <details> <summary>View changed files</summary> ➕ `.changeset/proxy-trust-default-dynamic.md` (+29 -0) 📝 `packages/better-auth/src/auth/base.ts` (+5 -1) 📝 `packages/better-auth/src/auth/full.test.ts` (+7 -0) 📝 `packages/better-auth/src/context/helpers.ts` (+8 -1) 📝 `packages/better-auth/src/utils/url.test.ts` (+57 -21) 📝 `packages/better-auth/src/utils/url.ts` (+35 -23) </details> ### 📄 Description Security hardening split out from #9131. ## Problem The static-config `baseURL` path already required `advanced.trustedProxyHeaders: true` to honor `x-forwarded-host` / `x-forwarded-proto`. The dynamic (`allowedHosts`) path trusted them implicitly, so deployments that don't strip client-supplied `x-forwarded-*` let an attacker pivot between any two hosts listed in `allowedHosts` via header spoofing. This aligns the two paths: proxy headers are now ignored unless the user explicitly opts in with `trustedProxyHeaders: true`. ## Migration Dynamic configs deployed behind a reverse proxy that only exposes the public hostname via `x-forwarded-host` need to add: ```ts betterAuth({ baseURL: { allowedHosts: [...] }, advanced: { trustedProxyHeaders: true, }, }); ``` Setups where the proxy rewrites `Host:` to the public hostname (nginx default, Vercel, Cloudflare, Netlify) are unaffected. ## Scope Small, focused on the security default only. The DX and correctness fixes from the same bug class (direct `auth.api` calls, MCP/OAuth-provider metadata forwarding, `APIError` on unresolvable, etc.) ship in #9131. Related: #9105 <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Hardened dynamic baseURL resolution in `better-auth` by ignoring `x-forwarded-host` and `x-forwarded-proto` unless `advanced.trustedProxyHeaders` is true. This aligns `allowedHosts` with static configs and prevents header-spoofing pivots between allowed hosts. - **Migration** - If using `baseURL.allowedHosts` behind a proxy that exposes the public hostname via `x-forwarded-host`, set `advanced.trustedProxyHeaders: true`. - No changes needed when the proxy rewrites `Host` to the public hostname (nginx default, Vercel, Cloudflare, Netlify). <sup>Written for commit 6294885e64c810c4d7b0eb6bf8c3842c98b5e631. Summary will update on new commits.</sup> <!-- End of auto-generated description by cubic. --> --- <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-13 10:39:06 -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#16706