[PR #8579] fix: remove request header leak from before-hook early return #24976

Open
opened 2026-04-15 22:39:58 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/better-auth/better-auth/pull/8579
Author: @thefotios
Created: 3/12/2026
Status: 🔄 Open

Base: mainHead: fix/before-hook-request-header-leak


📝 Commits (3)

  • 108877d fix: remove request header leak from before hook early return
  • 2f217cf fix: address review feedback on before-hook header leak
  • 724a978 style: apply biome formatting

📊 Changes

2 files changed (+69 additions, -4 deletions)

View changed files

📝 packages/better-auth/src/api/to-auth-endpoints.test.ts (+67 -0)
📝 packages/better-auth/src/api/to-auth-endpoints.ts (+2 -4)

📄 Description

Summary

When a hooks.before middleware short-circuits (returns early without a context key), the response incorrectly receives the request's headers — including Content-Length, Host, Cookie, etc. This causes net::ERR_CONTENT_LENGTH_MISMATCH in browsers.

A companion defensive fix in better-call is at https://github.com/better-auth/better-call/pull/120.

Root Cause

In to-auth-endpoints.ts lines 161-172, when a before hook returns a non-context value (early return), the code was:

return context?.asResponse
    ? toResponse(before, { headers: context?.headers })  // ← request headers!
    : context?.returnHeaders
        ? { headers: context?.headers, response: before } // ← request headers!
        : before;

At this point in execution, internalContext.context.responseHeaders is undefined (line 117) — no response headers have been accumulated. context?.headers contains the request headers (set at line 121 from new Headers(context?.headers)). Passing these to toResponse() grafts request headers onto the response.

Fix

Remove context?.headers from the early-return path entirely:

return context?.asResponse
    ? toResponse(before)          // no headers — toResponse sets its own
    : context?.returnHeaders
        ? { headers: new Headers(), response: before }  // empty response headers
        : before;

This is correct because:

  1. No response headers exist at this point (responseHeaders is undefined)
  2. The hook's return value IS the response — it doesn't need request headers grafted onto it
  3. toResponse() sets appropriate headers (like Content-Type) based on the data type

Test plan

  • New test: before hook early return with asResponse: true does not leak request headers
  • New test: before hook early return with returnHeaders: true does not leak request headers
  • Verify content-type: application/json is correctly set on early-return responses
  • All 36 existing + new tests pass

Summary by cubic

Fixes a bug in better-auth where early returns in before hooks leaked request headers into responses, causing browser net::ERR_CONTENT_LENGTH_MISMATCH errors.

  • Bug Fixes
    • Stop passing context.headers to toResponse() on early return.
    • Return empty headers when returnHeaders: true.
    • Add tests to ensure no header leak and correct content-type is set.

Written for commit 724a978259. 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/8579 **Author:** [@thefotios](https://github.com/thefotios) **Created:** 3/12/2026 **Status:** 🔄 Open **Base:** `main` ← **Head:** `fix/before-hook-request-header-leak` --- ### 📝 Commits (3) - [`108877d`](https://github.com/better-auth/better-auth/commit/108877dfc36d0a72a05f777bf2fe72e0cd4dd900) fix: remove request header leak from before hook early return - [`2f217cf`](https://github.com/better-auth/better-auth/commit/2f217cf3c510221915ce09d5ad7880a0cfea4ec2) fix: address review feedback on before-hook header leak - [`724a978`](https://github.com/better-auth/better-auth/commit/724a978259c1b8751fe0cbafc093a8e962797446) style: apply biome formatting ### 📊 Changes **2 files changed** (+69 additions, -4 deletions) <details> <summary>View changed files</summary> 📝 `packages/better-auth/src/api/to-auth-endpoints.test.ts` (+67 -0) 📝 `packages/better-auth/src/api/to-auth-endpoints.ts` (+2 -4) </details> ### 📄 Description ## Summary When a `hooks.before` middleware short-circuits (returns early without a `context` key), the response incorrectly receives the **request's** headers — including `Content-Length`, `Host`, `Cookie`, etc. This causes `net::ERR_CONTENT_LENGTH_MISMATCH` in browsers. A companion defensive fix in better-call is at https://github.com/better-auth/better-call/pull/120. ## Root Cause In `to-auth-endpoints.ts` lines 161-172, when a before hook returns a non-context value (early return), the code was: ```typescript return context?.asResponse ? toResponse(before, { headers: context?.headers }) // ← request headers! : context?.returnHeaders ? { headers: context?.headers, response: before } // ← request headers! : before; ``` At this point in execution, `internalContext.context.responseHeaders` is `undefined` (line 117) — no response headers have been accumulated. `context?.headers` contains the **request** headers (set at line 121 from `new Headers(context?.headers)`). Passing these to `toResponse()` grafts request headers onto the response. ## Fix Remove `context?.headers` from the early-return path entirely: ```typescript return context?.asResponse ? toResponse(before) // no headers — toResponse sets its own : context?.returnHeaders ? { headers: new Headers(), response: before } // empty response headers : before; ``` This is correct because: 1. No response headers exist at this point (`responseHeaders` is `undefined`) 2. The hook's return value IS the response — it doesn't need request headers grafted onto it 3. `toResponse()` sets appropriate headers (like `Content-Type`) based on the data type ## Test plan - [x] New test: before hook early return with `asResponse: true` does not leak request headers - [x] New test: before hook early return with `returnHeaders: true` does not leak request headers - [x] Verify `content-type: application/json` is correctly set on early-return responses - [x] All 36 existing + new tests pass <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Fixes a bug in `better-auth` where early returns in before hooks leaked request headers into responses, causing browser `net::ERR_CONTENT_LENGTH_MISMATCH` errors. - **Bug Fixes** - Stop passing `context.headers` to `toResponse()` on early return. - Return empty headers when `returnHeaders: true`. - Add tests to ensure no header leak and correct `content-type` is set. <sup>Written for commit 724a978259c1b8751fe0cbafc093a8e962797446. 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-15 22:39:58 -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#24976