Safeguard
Security Guides•

How do Fastify trustProxy and rate limit keys work behind a proxy?

Fastify rate limits key on request.ip, which depends on trustProxy. Get it wrong and everyone shares one bucket or clients forge their own. Fix it here.

Safeguard Security Team
3 min read

The Fastify rate limit plugin keys each client on request.ip by default. That value depends on the server's trustProxy option, which defaults to false. Behind a proxy with trustProxy off, all users share one bucket. With it set too loosely, clients can forge their address and reset their own limit.

How the pieces connect

The @fastify/rate-limit README says the default keyGenerator normalizes request.ip, and that Fastify resolves the IP from the socket address, or from X-Forwarded-For if the trustProxy option is enabled. It also maps IPv4 mapped IPv6 addresses to IPv4 and masks IPv6 addresses to a configurable prefix, which defaults to 64.

That IPv6 mask is worth knowing. A single user with a /64 allocation has a huge number of addresses, so keying on each full address would let them rotate for free. The plugin groups them.

trustProxy values in Fastify

The server reference lists these options for trustProxy:

ValueMeaning
false (default)Do not trust forwarded headers
trueTrust all proxies
String or arrayIP addresses or CIDRs to trust
FunctionReceives address and hop

A bare number is not supported, because hop count only trust is disabled. The docs warn that ip, ips, host and protocol are untrusted unless you validate the proxy chain.

Steps

  1. Decide your real proxy addresses or CIDR ranges.
  2. Set trustProxy to that list, not to true.
  3. Register the rate limit plugin after the server options are set.
  4. Pick limits per route. Login and password reset deserve tighter values than reads.
  5. Test with a forged X-Forwarded-For from outside and confirm the limit still applies to the true client.
const fastify = require('fastify')({ trustProxy: '10.0.0.0/8' });

await fastify.register(require('@fastify/rate-limit'), {
  max: 100,
  timeWindow: '1 minute'
});

Choosing a better key

For authenticated APIs, a user or API key identifier is a more honest key than an IP, since many people share offices and mobile networks. The plugin lets you supply your own keyGenerator, and also a groupId so that groups of routes get separate limits. Combine both when it fits, for example IP for login attempts and account identifier for everything after.

If you run more than one instance, also read Fastify rate limit stores, since the default store is local to each process.

For the Express equivalent of this setting, see Express trust proxy.

Safeguard's asset discovery and dependency scanning can help you see which Fastify plugins run across your services. Free scan: gold.safeguard.sh/scan.

Quick check

Does Fastify let me trust a hop count?

No. Per the server reference, a number is not supported because hop count only trust is disabled. Use addresses, CIDRs or a function.

Is IP the best rate limit key?

Not always. IP works for anonymous endpoints like login. For signed in traffic, an account or key identifier is usually fairer.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.