cloudflare / cloudflare/workers-sdk
wrangler dev rewrites in-Worker Host/Origin/request.url to the routes host in local mode, breaking origin-based auth/CORS checks
- Dominant language
- TypeScript
- Stars
- 4.5k
- Forks
- 1.5k
- Avg merge
- 3d 8h
- Merged PRs (30d)
- 186
Description
### Which Cloudflare product(s) does this pertain to?
Wrangler
### What version(s) of the tool(s) are you using?
wrangler 4.62.0
### What version of Node are you using?
22.14.0
### What operating system and version are you using?
Linux
### Describe the Bug
**Summary**
In local `wrangler dev`, when a `routes` entry (with `zone_name`) is configured, the Worker receives its incoming `Host` header, `request.url`, and — when the client sends one — its `Origin` header **rewritten to the route's host**, even though the client genuinely connects to `http://localhost:PORT`.
This silently breaks any Host/Origin/CORS-sensitive logic during local development. For example, a session-cookie CORS check that allows `http://localhost:*` receives `http://` instead and rejects the request, so authenticated flows that work in production return 403 only under local `wrangler dev` — with no indication that the header was rewritten. It took server-side instrumentation to discover the headers were being altered.
**Minimal reproduction**
`src/index.ts`:
```ts
export default {
fetch(req: Request): Response {
return Response.json({
host: req.headers.get("host"),
origin: req.headers.get("origin"),
url: req.url,
});
},
};
```
`wrangler.jsonc`:
```jsonc
{
"name": "route-host-repro",
"main": "src/index.ts",
"compatibility_date": "2025-12-01",
"routes": [{ "pattern": "example.com/*", "zone_name": "example.com" }]
}
```
Run `npx wrangler dev --port 8799` (local mode), then:
```console
$ curl -s http://127.0.0.1:8799/ -H "Origin: http://localhost:8799" -H "Host: localhost:8799"
{"host":"example.com","origin":"http://example.com","url":"http://example.com/"}
$ curl -s http://127.0.0.1:8799/api/thing
{"host":"example.com","origin":null,"url":"http://example.com/api/thing"}
```
**Expected**
Local `wrangler dev` should present the Worker with the real request's `Host`/`Origin`/`url` (i.e. `localhost:8799`), or at minimum:
1. document that configured `routes` cause the in-Worker `Host`/`url`/`Origin` to be rewritten to the route host in local mode, and
2. provide a documented way to opt out (e.g. a flag), so origin/Host-sensitive code can be exercised locally without deleting the `routes` binding.
**Actual**
`Host` and `request.url` are always rewritten to the first `routes` pattern's host; a present `Origin` header is rewritten too (a missing `Origin` stays `null` — it is not invented).
**Notes**
- Reproduces with plain `wrangler dev` as shown; also surfaces via `@opennextjs/cloudflare preview` (which wraps `wrangler dev`).
- Current workaround: run local dev against a config that omits `routes`.
Contributor guide
Research direction
Reproduce with src/index.ts and wrangler.jsonc using npx wrangler dev --port 8799, then compare the Worker's host, origin, and url with the curl requests in the report. Trace Wrangler's local-mode request handling from the dev command to determine where the configured routes host is applied. Done means local requests preserve their actual host, origin, and url, or the behavior and an opt-out are documented and verified against this reproduction.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100