Skip to content

fix(fastify): detect proxy trust from request.ip, not trustProxy - #210

Merged
Bccorb merged 1 commit into
mainfrom
fix/fastify-trust-proxy-hop-count
Oct 8, 2026
Merged

Bccorb merged 1 commit into
mainfrom
fix/fastify-trust-proxy-hop-count

Conversation

@Bccorb

@Bccorb Bccorb commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Closes #208.

Why

#208 reported that the README recommends a trustProxy hop count, which Fastify 5.12.1 and later ignore. Fixing it turned up a second, more serious problem.

The blanket-trustProxy guard never fired. The adapter is meant to refuse to forward the client IP when the app trusts every proxy (trustProxy: true). With that setting, request.ip is the leftmost X-Forwarded-For entry, which any client can set. The check read trustProxy from request.server.initialConfig, but Fastify 5 does not put trustProxy there; it lives only in a closure. So the check was always false. Any Fastify adopter using trustProxy: true, a common setting, let callers choose the client IP the auth API rate limits and audits against.

The hop-count advice. getTrustProxyFn changed in Fastify 5.12.1 so that a numeric trustProxy trusts nothing. request.ip is then the proxy, and every user behind it shares one rate-limit bucket and one audit address on the auth API.

What changes

  • Detecting trust-everything. Since trustProxy cannot be read, the adapter asks Fastify's own request.ip getter about a synthetic request: a peer and forwarded addresses from the RFC 5737 documentation ranges, which no real proxy has. If Fastify takes the leftmost forwarded address, the app trusts every address. The adapter then drops the client IP and warns once, as originally intended. The answer is cached per request class. If the getter cannot be found, behaviour falls back to forwarding request.ip, as before.
  • Untrusted proxy. When a request carries X-Forwarded-For but request.ip is still the connecting peer, the adapter warns once that a proxy appears to be in front and nothing trusts it.
  • README. Recommends the proxy's address or subnet, or resolveClientIp, and explains both failure modes.

I tried a startup warning first, but it cannot work for the same reason: trustProxy is not readable.

The probe gives the expected answer on Fastify 5.10.0 (the workspace) and 5.12.5 (latest):

trustProxy Trusts every address request.ip for peer 10.0.0.5, X-Forwarded-For: 6.6.6.6, 203.0.113.50
unset no 10.0.0.5
true yes 6.6.6.6
1 (5.12.5) no 10.0.0.5
"10.0.0.0/8" no 203.0.113.50
(a, hop) => hop < 1 no 203.0.113.50
() => true yes 6.6.6.6

Checks

  • pnpm test: core 403, express 210, fastify 166, nextjs 165, all passing.
  • tests/trustProxy.test.js sends requests through the plugin and asserts the x-seamless-client-ip sent upstream:
    • it is dropped (with a warning) under true and a catch-all function;
    • it is the real client behind a trusted subnet or a one-hop function, ignoring a spoofed leftmost entry;
    • it is the peer, with a warning, when X-Forwarded-For arrives untrusted;
    • it is the peer, with no warning, when there is no proxy.

Patch changeset for @seamless-auth/fastify.

The check that refused to forward a client-controlled address under
trustProxy: true read trustProxy from initialConfig, which Fastify 5 does not
expose, so it never fired and a caller could choose the client IP the auth
API rate limits and audits against. It now asks Fastify's own request.ip
about a request from documentation addresses (RFC 5737), and drops the
address and warns when every address is trusted.

The README recommended a hop count, which Fastify 5.12.1 and later ignore,
leaving every user behind the proxy on one address. It now recommends the
proxy's address or subnet, and the adapter warns once when requests carry
X-Forwarded-For that nothing trusts.

Closes #208.
@Bccorb
Bccorb merged commit 88ae99c into main Oct 8, 2026
4 checks passed
@Bccorb
Bccorb deleted the fix/fastify-trust-proxy-hop-count branch October 8, 2026 15:11
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.

docs(fastify): an explicit trustProxy hop count no longer forwards the client IP

1 participant