The trust proxy setting tells Express which X-Forwarded headers to believe. The default is false, so req.ip comes from the socket. Behind a reverse proxy you set it to match your real proxy chain. Set it too loosely and any client can claim any IP address.
Why it matters
Behind a load balancer, the socket address is the balancer, so every user looks like one IP. Teams then turn trust proxy on to get the real address back. That address often feeds rate limiting, audit logs and allow lists. If a client can forge it, all three break.
The documented value types
| Value | Meaning |
|---|---|
| false (default) | App faces the client directly, IP comes from the socket |
| true | Client IP is the left most X-Forwarded-For entry |
| IP, subnet or list | Trust those as proxies, take the nearest untrusted address |
| Number | Trust that many hops from the app |
| Function | Your own trust logic |
Express also ships named subnets: loopback, linklocal and uniquelocal.
The two warnings in the docs
First, when set to true, the last reverse proxy you trust must remove or overwrite X-Forwarded-For, X-Forwarded-Host and X-Forwarded-Proto. Otherwise the client can supply any value.
Second, with a hop count, make sure there are not multiple paths of different length to the app. If a client can reach the app by a shorter path, it may be fewer hops away than you configured and can then supply any value.
The guide's own advice is to understand your exact proxy setup, because the setting trusts values supplied in the request.
Steps to set it
- Draw the real path: client, CDN, load balancer, your app. Count the hops you control.
- Prefer a list of known proxy addresses or subnets over the plain true value.
- Make sure the outermost trusted proxy overwrites forwarded headers instead of appending client supplied ones.
- Test from outside. Send a request with a fake X-Forwarded-For and confirm the logged IP is not the fake one.
- Use the same trusted value in anything that reads the IP, such as your rate limiter.
// Only trust the proxy in your private network range
app.set('trust proxy', 'uniquelocal');
app.get('/whoami', (req, res) => {
res.json({ ip: req.ip, ips: req.ips, protocol: req.protocol });
});
Other effects of turning it on
The guide lists three consequences. req.hostname derives from X-Forwarded-Host, which can be set by the client or the proxy. req.protocol reflects X-Forwarded-Proto, which could even be an invalid name. req.ip and req.ips come from the socket address and X-Forwarded-For, starting at the first untrusted address. If you build absolute links or redirects from req.hostname, validate them. See the open redirect post.
For limiters, read four silent ways a rate limiter permits everything.
Safeguard's policies and gates can enforce checks like this in review, and a free scan at gold.safeguard.sh/scan covers your dependency side.
Quick check
Should I just set trust proxy to true?
Only if the last proxy in front of your app strips and rewrites the forwarded headers. A specific address or subnet list is the safer habit.
Why is every request showing the same IP?
Likely trust proxy is still false, so Express reports the proxy's socket address. Set it to match your proxy chain.
Sources
Last reviewed: 19 October 2026.