Skip to content

Commit ee88a55

Browse files
fix(website): preserve client IP when proxying
removeCFHeaders drops every cf-* header, including cf-connecting-ip, so proxied origins saw only the pod's IP. Capture it before the strip and forward it as x-forwarded-for/x-real-ip. Affects every site using website/handlers/proxy.ts, including the VTEX proxy routes and A/B testing via the abTesting prop, where the origin otherwise loses geo, rate limiting, analytics and fraud signals. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 3670ea3 commit ee88a55

1 file changed

Lines changed: 12 additions & 0 deletions

File tree

website/handlers/proxy.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,19 @@ export default function Proxy({
145145
if (isFreshCtx<DecoSiteState>(_ctx)) {
146146
_ctx?.state?.monitoring?.logger?.log?.("proxy received headers", headers);
147147
}
148+
// cf-connecting-ip carries the real client IP, and removeCFHeaders is about
149+
// to drop it. Forward it as x-forwarded-for/x-real-ip so the proxied origin
150+
// still sees who the visitor is (geo, rate limiting, analytics, fraud).
151+
const clientIp = headers.get("cf-connecting-ip");
148152
removeCFHeaders(headers); // cf-headers are not ASCII-compliant
153+
if (clientIp) {
154+
const forwardedFor = headers.get("x-forwarded-for");
155+
headers.set(
156+
"x-forwarded-for",
157+
forwardedFor ? `${clientIp}, ${forwardedFor}` : clientIp,
158+
);
159+
headers.set("x-real-ip", clientIp);
160+
}
149161
if (removeDirtyCookies) {
150162
removeDirtyCookiesFn(headers);
151163
}

0 commit comments

Comments
 (0)