Security-Critical Questions on Edge Proxy Header Handling and Hop Count
kdeyarmin
PROOP

25 days ago

Hi Railway Support,

I'm implementing rate-limiting and client IP detection for my app (resupply-api, project PennPaps) and need definitive answers on edge proxy behavior for security purposes. These are safety-critical for preventing IP spoofing attacks.

Questions:

X-Forwarded-For handling: Does Railway's edge proxy strip, sanitize, or append to client-supplied X-Forwarded-For headers? If a client sends X-Forwarded-For: 1.2.3.4 directly to pennfit.up.railway.app, what does the app receive?

Hop count: How many proxy hops exist between the public edge and the app container? Is this count fixed and documented, or can it vary (e.g., due to internal load balancers, regional edges, IPv4/IPv6 differences)?

Immediate peer IP: What is the documented/stable internal proxy IP range that appears in req.socket.remoteAddress (the immediate TCP peer)? This is needed for implementing a trust proxy function safely.

Upstream headers: Are inbound headers from upstream proxies (e.g., Cloudflare's CF-Connecting-IP, CF-Ray, X-Forwarded-For) forwarded untouched to the app, or are they stripped/modified?

Consistency across domains: Is this behavior identical for *.up.railway.app and custom domains? Is it contractually documented so it won't silently change?

I need these answers to safely configure trust proxy in Express without creating a spoofing vulnerability.

Thanks

$20 Bounty

3 Replies

Railway
BOT

25 days ago

This thread has been opened as a public bounty so the community can help solve it. The thread and any further activity are now visible to everyone.

Status changed to Open Railway 25 days ago


zah340
HOBBYTop 10% Contributor

25 days ago

Railway appends the real client IP to the end of XFF. It does NOT strip client-supplied values. If a client sends X-Forwarded-For: 1.2.3.4, your app sees X-Forwarded-For: 1.2.3.4, . Only the rightmost value is trustworthy.

Typically 1 hop. Use trust proxy: 1 if that breaks, try 2. It is not officially documented as stable tho.

Always in the 100.0.0.0/8 range. Base your trust proxy function on this.

X-Real-IP is overwritten with the real client IP. Cloudflare headers like CF-Connecting-IP only appear if you actually have Cloudflare in front of Railway.

Behavior is consistent across *.up.railway.app and custom domains.

Recommended config:

app.set('trust proxy', (ip) => ip.startsWith('100.'));


25 days ago

We do strip X-Forwarded-For at our edge and ensure clients cannot overwrite it. The first value of the X-Forwarded-For is the real connecting IP. You may see another hop as the request is forwarded through our network.

We also provide an X-Real-IP header that serves as a single source of truth for the connecting IP. If your site is behind Cloudflare, then we overwrite the value with the Cf-Connecting-IP so that it matches the real client IP, as long as it comes from trusted Cloudflare infrastructure.


shahzaib-cmyk
HOBBY

5 days ago

This for some reason doesn't seem to be the case in my setup though. I have a fastify app where I set the trust proxy to trust all proxies in the railway ips and cloudflare ip ranges (dynamically fetched from their api). Despite that though, the X-Forwarded-For header only has 2 ips, none of which were the client ips, but rather the first was a railway ip, and the other was a cloudflare ip.


Welcome!

Sign in to your Railway account to join the conversation.

Loading...