Merge pull request #4394 from luca-seemann/fix/client-ip-header-xff-chain

Fix client IP resolution when CLIENT_IP_HEADER is set to x-forwarded-for
This commit is contained in:
Mike Cao authored and GitHub committed 2026-07-23 15:27:51 -07:00
commit b70eda56e6
2 files changed
+24 -14

No files matched your search

+8
View File
@@ -24,6 +24,14 @@ test('getIpAddress: Custom header', () => {
expect(getIpAddress(new Headers({ 'x-custom-ip-header': IP }))).toEqual(IP); expect(getIpAddress(new Headers({ 'x-custom-ip-header': IP }))).toEqual(IP);
}); });
test('getIpAddress: Custom header set to x-forwarded-for uses leftmost IP in chain', () => {
process.env.CLIENT_IP_HEADER = 'x-forwarded-for';
expect(
getIpAddress(new Headers({ 'x-forwarded-for': `${IP}, 10.0.0.1, 10.0.0.2` })),
).toEqual(IP);
});
test('getIpAddress: CloudFlare header', () => { test('getIpAddress: CloudFlare header', () => {
expect(getIpAddress(new Headers({ 'cf-connecting-ip': IP }))).toEqual(IP); expect(getIpAddress(new Headers({ 'cf-connecting-ip': IP }))).toEqual(IP);
}); });
+16 -14
View File
@@ -58,11 +58,25 @@ function resolveIp(ip?: string | null) {
} }
} }
function parseHeaderValue(header: string, value: string) {
if (header === 'x-forwarded-for') {
return resolveIp(value?.split(',')?.[0]?.trim());
}
if (header === 'forwarded') {
const match = value.match(/for=(\[?[0-9a-fA-F:.]+]?)/);
return match ? resolveIp(match[1]) : undefined;
}
return resolveIp(value);
}
export function getIpAddress(headers: Headers) { export function getIpAddress(headers: Headers) {
const customHeader = process.env.CLIENT_IP_HEADER; const customHeader = process.env.CLIENT_IP_HEADER;
if (customHeader && headers.get(customHeader)) { if (customHeader && headers.get(customHeader)) {
return resolveIp(headers.get(customHeader)); return parseHeaderValue(customHeader.toLowerCase(), headers.get(customHeader));
} }
const header = IP_ADDRESS_HEADERS.find(name => headers.get(name)); const header = IP_ADDRESS_HEADERS.find(name => headers.get(name));
@@ -70,19 +84,7 @@ export function getIpAddress(headers: Headers) {
return undefined; return undefined;
} }
const ip = headers.get(header); return parseHeaderValue(header, headers.get(header));
if (header === 'x-forwarded-for') {
return resolveIp(ip?.split(',')?.[0]?.trim());
}
if (header === 'forwarded') {
const match = ip.match(/for=(\[?[0-9a-fA-F:.]+]?)/);
return match ? resolveIp(match[1]) : undefined;
}
return resolveIp(ip);
} }
export function stripPort(ip?: string | null) { export function stripPort(ip?: string | null) {