From e68ebfef6313780e635450ed8d249d0dac82633d Mon Sep 17 00:00:00 2001 From: Pablo Pettinari Date: Sat, 21 Feb 2026 09:17:33 +0100 Subject: [PATCH] fix(ab-test): extract client IP from x-forwarded-for header The x-forwarded-for header contains a comma-separated list of IPs: "client_ip, proxy1, proxy2, cdn_edge". With Cloudflare in front, the proxy IPs change between requests causing different fingerprints and non-deterministic variant assignment. Fix: Extract only the first IP (the actual client) for stable fingerprinting. --- src/lib/ab-testing/server.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lib/ab-testing/server.ts b/src/lib/ab-testing/server.ts index 8dd9032787f..51577136a63 100644 --- a/src/lib/ab-testing/server.ts +++ b/src/lib/ab-testing/server.ts @@ -28,8 +28,11 @@ export const getABTestAssignment = async ( const headers = await import("next/headers").then((m) => m.headers()) // Get IP and user agent (primary identifier) + // x-forwarded-for contains: "client_ip, proxy1, proxy2, ..." - extract only client IP const forwardedFor = - headers.get("x-forwarded-for") || headers.get("x-real-ip") || "unknown" + headers.get("x-forwarded-for")?.split(",")[0]?.trim() || + headers.get("x-real-ip") || + "unknown" const userAgent = headers.get("user-agent") || "" // Add privacy-preserving entropy sources