Aias00 opened a new issue, #6823:
URL: https://github.com/apache/shenyu/issues/6823

   ## Description
   `ForwardedRemoteAddressResolver` (the production default, wired as `new 
ForwardedRemoteAddressResolver(1)` in `ShenyuConfiguration`) has an inverted 
guard in `extractXForwardedValues`: after splitting `X-Forwarded-For` by `", 
"`, it does
   ```java
   if (values.size() == 1 && StringUtils.isNotEmpty(values.get(0))) {
       return Collections.emptyList();
   }
   ```
   `isNotEmpty` is the opposite of the intended check. The intent is to discard 
a single *empty* value (blank header), but the code discards a single 
*non-empty* value — i.e. a valid single client IP. `resolve()` then falls 
through to the TCP peer address (the proxy's IP), discarding the real client 
IP. Conversely, an empty-value header is *not* discarded and produces `new 
InetSocketAddress("", 0)` → wildcard `0.0.0.0`.
   
   Additionally `resolve()` constructs `new 
InetSocketAddress(xForwardedValues.get(index), 0)`; the 
`InetSocketAddress(String,int)` ctor performs a **blocking DNS lookup** when 
the value is not a literal IP. `X-Forwarded-For` is unvalidated client input; 
with the default `maxTrustedIndex=1` the leftmost (most spoofable) value is 
selected. When `shenyu.scheduler.enabled=false` (default), 
`HostAddressUtils.acquireIp` runs on the Netty event loop → blocking DNS stalls 
all connections on that thread (DoS) and enables DNS 
exfiltration/reconnaissance.
   
   ## Location
   - 
`shenyu-web/src/main/java/org/apache/shenyu/web/forward/ForwardedRemoteAddressResolver.java:89-108`
 (inverted guard :106-108; blocking DNS :89-90)
   - 
`shenyu-spring-boot-starter/shenyu-spring-boot-starter-gateway/src/main/java/org/apache/shenyu/springboot/starter/gateway/ShenyuConfiguration.java:158-160`
 (production default)
   
   ## Impact
   - Default deployment (single-hop trusted proxy appending one client IP — the 
most common case) silently ignores the client IP. 
`HostAddressUtils.acquireIp(exchange)` (consumed by `AbstractLoggingPlugin` for 
`clientIp`, and by any IP-based allow/deny/rate-limit feature) returns the 
proxy's IP. Access logs, rate limiting, and IP-based security all see the wrong 
IP.
   - DoS: crafted `X-Forwarded-For` hostnames trigger blocking DNS (up to 
system DNS timeout, 5–15s) on the event loop.
   - DNS exfiltration: gateway resolves attacker-controlled hostnames, leaking 
data to attacker's DNS server.
   
   ## Suggested fix
   - Change `StringUtils.isNotEmpty(values.get(0))` → 
`StringUtils.isEmpty(values.get(0))` so only empty single values are discarded.
   - Validate the selected value is a literal IP 
(`InetAddressUtils.isIPv4/IPv6` or try `InetAddress.getByAddress`) before 
constructing `InetSocketAddress`; otherwise fall back to the TCP remote 
address. Never call `new InetSocketAddress(String,int)` with unvalidated input 
on a reactive thread.
   
   ## Related existing
   None. Distinct from #6556 (WebSocket Upgrade header case-sensitivity in 
`DefaultShenyuContextBuilder`).
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to