Skip to content

Commit 6fdb79b

Browse files
authored
host parse (#13309)
1 parent efa08f6 commit 6fdb79b

File tree

3 files changed

+38
-3
lines changed

3 files changed

+38
-3
lines changed

.changeset/honest-mangos-sneeze.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@react-router/express": patch
3+
---
4+
5+
Better validation of `x-forwarded-host` header to preent potential security issues.

packages/react-router-express/__tests__/server-test.ts

+24
Original file line numberDiff line numberDiff line change
@@ -217,4 +217,28 @@ describe("express createRemixRequest", () => {
217217
);
218218
expect(remixRequest.headers.get("host")).toBe("localhost:3000");
219219
});
220+
221+
it("validates parsed port", async () => {
222+
let expressRequest = createRequest({
223+
url: "/foo/bar",
224+
method: "GET",
225+
protocol: "http",
226+
hostname: "localhost",
227+
headers: {
228+
"Cache-Control": "max-age=300, s-maxage=3600",
229+
Host: "localhost:3000",
230+
"x-forwarded-host": ":/spoofed"
231+
},
232+
});
233+
let expressResponse = createResponse();
234+
235+
let remixRequest = createRemixRequest(expressRequest, expressResponse);
236+
237+
expect(remixRequest.method).toBe("GET");
238+
expect(remixRequest.headers.get("cache-control")).toBe(
239+
"max-age=300, s-maxage=3600"
240+
);
241+
expect(remixRequest.headers.get("host")).toBe("localhost:3000");
242+
expect(remixRequest.url).toBe("http://localhost:3000/foo/bar");
243+
});
220244
});

packages/react-router-express/server.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,15 @@ export function createRemixRequest(
9898
): Request {
9999
// req.hostname doesn't include port information so grab that from
100100
// `X-Forwarded-Host` or `Host`
101-
let [, hostnamePort] = req.get("X-Forwarded-Host")?.split(":") ?? [];
102-
let [, hostPort] = req.get("host")?.split(":") ?? [];
103-
let port = hostnamePort || hostPort;
101+
let [, hostnamePortStr] = req.get("X-Forwarded-Host")?.split(":") ?? [];
102+
let [, hostPortStr] = req.get("host")?.split(":") ?? [];
103+
let hostnamePort = Number.parseInt(hostnamePortStr, 10);
104+
let hostPort = Number.parseInt(hostPortStr, 10);
105+
let port = Number.isSafeInteger(hostnamePort)
106+
? hostnamePort
107+
: Number.isSafeInteger(hostPort)
108+
? hostPort
109+
: "";
104110
// Use req.hostname here as it respects the "trust proxy" setting
105111
let resolvedHost = `${req.hostname}${port ? `:${port}` : ""}`;
106112
// Use `req.originalUrl` so Remix is aware of the full path

0 commit comments

Comments
 (0)