Skip to content

react-router/dev incorrect action request url origin (always http) #15454

Description

@divyeshsachan

Reproduction

Since Pull #15419 (@brophdawg11)

react-router dev always computes wrong req.url, it assumes protocol = http

Details follows:

In Fetcher action I get error in development mode

Error: Bad Request
    at singleFetchAction (file:///Users/node_modules/react-router/dist/development/lib/server-runtime/single-fetch.js:27:44)
    at handleSingleFetchRequest (file:///Users/node_modules/react-router/dist/development/lib/server-runtime/server.js:203:50)
    at requestHandler (file:///Users/node_modules/react-router/dist/development/lib/server-runtime/server.js:107:21)
    at requestHandler (file:///Users/node_modules/react-router/dist/development/lib/server-runtime/server.js:173:10)
    at nodeHandler (file:///Users/node_modules/@react-router/dev/dist/vite.js:1661:43)
    at async file:///Users/node_modules/@react-router/dev/dist/vite.js:1663:8

Further debugging it

singleFetchAction -> /Users/node_modules/react-router/dist/development/lib/server-runtime/single-fetch.js
the error is thrown due to throwIfPotentialCSRFAttack

throwIfPotentialCSRFAttack -> /Users/node_modules/react-router/dist/development/lib/actions.js is thrown due to

	let originMatchesRequest = originUrl ? originUrl.origin === requestUrl.origin : originDomain === requestUrl.host;
	if (originDomain && !originMatchesRequest) {
		if (!isAllowedOrigin(originDomain, allowedActionOrigins)) throw new Error("The `request.url` origin does not match `origin` header from a forwarded action request. Aborting the action.");
	}

Here originMatchesRequest is false, since, originUrl.origin & requestUrl.origin mismatches.
In my case, values determined are:
originUrl.origin: 'https://demo.example.com' & requestUrl.origin: 'http://demo.example.com'

My Headers are:

...
    host: 'demo.example.com',
    'x-real-ip': '127.0.0.1',
    'x-forwarded-for': '127.0.0.1',
    'x-forwarded-host': 'demo.example.com',
    'x-forwarded-port': '443',
    'x-forwarded-proto': 'https',
    'content-length': '51',
    pragma: 'no-cache',
    'cache-control': 'no-cache',
    'sec-ch-ua-platform': '"macOS"',
    'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36 Edg/151.0.0.0',
    'sec-ch-ua': '"Not=A?Brand";v="99", "Microsoft Edge";v="151", "Chromium";v="151"',
    'content-type': 'application/x-www-form-urlencoded;charset=UTF-8',
    'sec-ch-ua-mobile': '?0',
    accept: '*/*',
    origin: 'https://demo.example.com',
...

To find the cause of wrong protocol (http instead of https), i traced futher,

In file, /node_modules/@react-router/dev/dist/vite.js
function -> reactRouterVitePlugin -> line let req = await fromNodeRequest(nodeReq, nodeRes);

and in same file, function fromNodeRequest is defined as

async function fromNodeRequest(nodeReq, nodeRes) {
	invariant(nodeReq.originalUrl, "Expected `nodeReq.originalUrl` to be defined");
	nodeReq.url = nodeReq.originalUrl;
	return createRequest(nodeReq, nodeRes);
}

It calls createRequest with only 2 arguments, createRequest of /node_modules/@remix-run/node-fetch-server/dist/lib/request-listener.js expects third argument options which has many property including protocol, trustproxy, etc. which is not passed when calling this function.
Hence, options is always undefined and the url returned by this createRequest always have url starting with "http" and it throws error due to cors. There is no way to fix this in development mode.

Kindly check and resolve this.

System Info

System:
    OS: macOS 26.5.2
    CPU: (10) arm64 Apple M2 Pro
    Memory: 93.33 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 22.22.3 - /Users/.nvm/versions/node/v22.22.3/bin/node
    Yarn: 1.22.22 - /Users/.nvm/versions/node/v22.22.3/bin/yarn
    npm: 10.9.8 - /Users/.nvm/versions/node/v22.22.3/bin/npm
  Browsers:
    Chrome: 152.0.7977.64
    Edge: 152.0.4191.53
    Firefox: 154.0.1
    Safari: 26.5.2
  npmPackages:
    @react-router/dev: ^8.3.1 => 8.3.1 
    @react-router/express: ^8.3.1 => 8.3.1 
    @react-router/fs-routes: ^8.3.1 => 8.3.1 
    @react-router/node: ^8.3.1 => 8.3.1 
    react-router: ^8.3.0 => 8.3.1 
    vite: ^8.2.2 => 8.2.2

Used Package Manager

npm

Expected Behavior

react-reouter dev should respect protocol "https" of request url, it should allow "trust proxy" and header "X-Forwarded-Proto"

Actual Behavior

react-router dev always computes wrong req.url, it assumes protocol = http

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions