AI & Agent Dev Bug Sandbox logo
AI & Agent Dev Bug Sandbox
Back to Radar

Forwarded Server Actions Expose Internal Origin (Localhost:PORT) Via Headers()

When a Server Action is forwarded to a worker that does not contain the action in its bundle, Next.js performs an internal HTTP fetch to `__NEXT_PRIVATE_ORIGIN` (http://localhost:PORT). This causes the forwarded subrequest's `Host` header to be derived from the URL, so `headers().get('host')` inside the action returns `localhost:PORT` instead of the original request's host. Self-hosted multi-tenant applications that resolve tenants from the `host` header break specifically for forwarded actions.

highConfidence 85%Next.jsAffected V16.2.2

Origin Analysis

Forwarded Server Actions are sent via an internal `fetch` to `${__NEXT_PRIVATE_ORIGIN}${workerPathname}`, where `__NEXT_PRIVATE_ORIGIN` is set to `http://localhost:PORT` in `start-server.ts`. The `fetch` API derives the `Host` header from the URL and cannot be overridden because `Host` is a forbidden header in the Fetch spec. Although `x-forwarded-host` is preserved and carries the original host, `headers().get('host')` reads the derived `localhost:PORT` value.
1. Create a shared Server Action that reads `headers()` and returns `host`, `x-forwarded-host`, and `x-action-forwarded`. 2. Import the action only on one page (e.g., `/a`) and not on another (e.g., `/b`). 3. Build and start the app with `next build && next start -p 4111`. 4. POST the action to `/b` (which is not in the action's worker set) with a custom `Host` header. 5. Observe that the response contains `host: 'localhost:4111'` instead of the original host, while `x-forwarded-host` contains the original host and `x-action-forwarded` is `'1'`.

Fixing Code Block

Edge Case Audit

Mutating `req.headers.host` may impact any code that expects the internal host (`localhost:PORT`) during forwarded actions, such as logging or internal routing logic. Ensure that the `x-forwarded-host` header is trustworthy (e.g., set by a trusted reverse proxy); if not, this change could expose an attacker-controlled host to tenant resolution logic. Rollback: remove the added block and use `x-forwarded-host` directly in application code as a workaround. Test thoroughly with IPv6, multiple reverse proxies, and concurrent requests.

Ecosystem Topology