Skip to content

fix(client-api): parse single-IP X-Forwarded-For values#4839

Open
Ludv1gL wants to merge 1 commit intoclockworklabs:masterfrom
Ludv1gL:fix/xforwardedfor-single-ip
Open

fix(client-api): parse single-IP X-Forwarded-For values#4839
Ludv1gL wants to merge 1 commit intoclockworklabs:masterfrom
Ludv1gL:fix/xforwardedfor-single-ip

Conversation

@Ludv1gL
Copy link
Copy Markdown
Contributor

@Ludv1gL Ludv1gL commented Apr 17, 2026

Summary

XForwardedFor::decode requires a comma and fails to decode X-Forwarded-For: 1.2.3.4.
Under axum 0.8 this now surfaces as HTTP 400 on every single-hop-proxy request.

Fix

Accept comma-separated or single-IP values — take the first entry either way.

Reproducer

Any browser going through a proxy that does .insert("x-forwarded-for", client_ip)
(standard single-hop pattern) sees 400 Bad Request on WebSocket subscribe.

Version regression

Bug latent since the axum migration in 2023-06 (commit b4dae74). axum 0.7
silently dropped the decoder error via Option<TypedHeader<T>>; axum 0.8
(#2713) promotes it to a 400 rejection.

`XForwardedFor::decode` required a comma in the header value via
`split_once(',').ok_or_else(headers::Error::invalid)?`, so any client
coming through a single-hop proxy — which emits `X-Forwarded-For: <ip>`
with no comma — failed to decode.

Previously this was silent: `Option<TypedHeader<XForwardedFor>>` in
`crates/client-api/src/routes/subscribe.rs` resolved to `None` on
decode error under axum 0.7. axum 0.8 (landed in clockworklabs#2713) changed the
behavior: the same decoder `Err` now surfaces as a 400 Bad Request,
which breaks all WebSocket subscribe requests from single-hop proxy
clients — reproducible with:

```
curl -v -H 'Connection: Upgrade' -H 'Upgrade: websocket' \
  -H 'Sec-WebSocket-Version: 13' -H 'Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==' \
  -H 'Sec-WebSocket-Protocol: v2.bsatn.spacetimedb' \
  -H 'x-forwarded-for: 1.2.3.4' \
  "http://127.0.0.1:3000/v1/database/test/subscribe?token=..."
# => HTTP/1.1 400 Bad Request
# => invalid HTTP header (x-forwarded-for)
```

Accept both comma-separated and single-IP forms: take the first
entry (trimmed) regardless of whether a comma is present. This
matches how Nginx, Apache, HAProxy, etc. read the same header.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant