diff --git a/src/gateway/auth.test.ts b/src/gateway/auth.test.ts index 4012b6990c3..0dfb232ffaa 100644 --- a/src/gateway/auth.test.ts +++ b/src/gateway/auth.test.ts @@ -431,7 +431,6 @@ describe("trusted-proxy auth", () => { socket: { remoteAddress: "127.0.0.1" }, headers: { host: "gateway.local", - "x-forwarded-for": "203.0.113.10", "x-forwarded-user": "nick@example.com", "x-forwarded-proto": "https", }, diff --git a/src/gateway/auth.ts b/src/gateway/auth.ts index de82ee3a33e..cdfd4519f40 100644 --- a/src/gateway/auth.ts +++ b/src/gateway/auth.ts @@ -393,6 +393,24 @@ function authorizeSharedSecretFallback(params: SharedSecretAuthParams): GatewayA return null; } +function hasConfiguredTrustedProxyHeaders( + req: IncomingMessage | undefined, + trustedProxyConfig: GatewayTrustedProxyConfig | undefined, +): boolean { + if (!req || !trustedProxyConfig) { + return false; + } + + const headers = [trustedProxyConfig.userHeader, ...(trustedProxyConfig.requiredHeaders ?? [])] + .map((header) => header?.trim().toLowerCase()) + .filter((header): header is string => Boolean(header)); + + return headers.some((header) => { + const value = headerValue(req.headers[header]); + return typeof value === "string" && value.trim() !== ""; + }); +} + export async function authorizeGatewayConnect( params: AuthorizeGatewayConnectParams, ): Promise { @@ -414,9 +432,7 @@ export async function authorizeGatewayConnect( const localLoopbackWithoutProxyHeaders = Boolean(req) && isLoopbackAddress(req?.socket?.remoteAddress) && - !req?.headers?.["x-forwarded-for"] && - !req?.headers?.["x-real-ip"] && - !req?.headers?.["x-forwarded-host"]; + !hasConfiguredTrustedProxyHeaders(req, auth.trustedProxy); if (auth.mode === "trusted-proxy") { if (localLoopbackWithoutProxyHeaders && limiter) {