Skip to content

Commit 73966ef

Browse files
fix(website): do not duplicate client IP in x-forwarded-for
Measured on a live pod: x-forwarded-for already reaches the handler with the client IP as its first entry, so unconditionally prepending it produced a duplicate. Only seed the header when absent, and always set x-real-ip, which was the header actually missing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent ee88a55 commit 73966ef

1 file changed

Lines changed: 8 additions & 7 deletions

File tree

website/handlers/proxy.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -145,17 +145,18 @@ 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).
148+
// cf-connecting-ip carries the real client IP and removeCFHeaders is about
149+
// to drop it, leaving the proxied origin without x-real-ip. x-forwarded-for
150+
// usually already arrives with the client IP first, so only fill the gaps.
151151
const clientIp = headers.get("cf-connecting-ip");
152152
removeCFHeaders(headers); // cf-headers are not ASCII-compliant
153153
if (clientIp) {
154154
const forwardedFor = headers.get("x-forwarded-for");
155-
headers.set(
156-
"x-forwarded-for",
157-
forwardedFor ? `${clientIp}, ${forwardedFor}` : clientIp,
158-
);
155+
if (!forwardedFor) {
156+
headers.set("x-forwarded-for", clientIp);
157+
} else if (forwardedFor.split(",")[0].trim() !== clientIp) {
158+
headers.set("x-forwarded-for", `${clientIp}, ${forwardedFor}`);
159+
}
159160
headers.set("x-real-ip", clientIp);
160161
}
161162
if (removeDirtyCookies) {

0 commit comments

Comments
 (0)