After upgrading from API Gateway 2.3.x to 2.4.5/2.4.6, the X-Forwarded-For header received by applications behind the Gateway no longer contains the original client IP — only a single, incorrect address (typically the immediate upstream peer, e.g. a router/NAT IP) is present.
Before (2.3.x):
x_forwarded_for:"<CLIENT_IP>, <NAT_IP>,<CLIENT_IP>, <NAT_IP>"
After (2.4.6):
x_forwarded_for:"<NAT_IP>"
The real client IP is dropped entirely; only the NAT/LB IP of the immediate upstream hop remains.
This is a known, unintended side effect of the fix for CVE-2025-41235 ("Spring Cloud Gateway Server Forwards Headers from Untrusted Proxies"), which landed in API Gateway 2.3.3 and was tightened further in 2.4.5 (see commit 9041b549).
Before the fix, X-Forwarded-For/Forwarded headers from any upstream hop were trusted and forwarded unconditionally. The fix makes this secure-by-default: headers are only trusted/forwarded when the connecting peer matches a configured spring.cloud.gateway.server.webflux.trusted-proxies regex, and requires spring.cloud.gateway.server.webflux.httpserver.customizer-enabled=true to even enable this evaluation.
However, the fix introduced a conflict between two independent trust checks in the request pipeline:
This is documented in the upstream thread spring-cloud-gateway#3818, including a community root-cause writeup confirming the conflict between the Netty customizer and the header filter.
There is no supported configuration-only fix. Any config change permissive enough to restore the full forwarded chain (e.g. trusted-proxies=.* or trusted-proxies=[\s\S]*) re-widens the trust check to match anything, which reintroduces the same untrusted-header-forwarding exposure that CVE-2025-41235 was fixed to close — and even then, may only produce duplicated/malformed values rather than a fully correct chain, since the underlying conflict between the two trust checks isn't actually resolved by widening the regex.
This will be fixed in the upcoming releases.