Safeguard
Security Guides•

Which client IP should you log when your app sits behind a proxy?

Log the IP added by a proxy you trust, not the leftmost X-Forwarded-For value. Here is how to pick it by proxy count or trusted list, and what to record.

Safeguard Security Team
4 min read

Log the IP address that your own trusted proxy observed, which is usually the rightmost entry it appended to X-Forwarded-For, not the leftmost value. The leftmost entry is supplied by the client and can be forged. Record the full header too, labelled as unverified, so investigators can see what was claimed.

Why the obvious choice is the wrong one

X-Forwarded-For is a comma separated list. Each proxy appends the address it saw, so the leftmost entry looks like the original client. MDN notes that the header is a de facto standard rather than part of a current specification, and that any part not added by a trusted proxy may be spoofed or malformed.

That matters for logs because the client IP is the field you will filter on during an investigation. If an attacker sends their own X-Forwarded-For header and you log the leftmost value, your logs name an address of the attacker's choosing. Rate limits and blocklists built on that field fail the same way.

MDN goes further: if the server can be reached directly from the internet, even though a proxy normally sits in front of it, no part of the list is safe to use for security decisions. Closing the direct path is part of the fix.

Three ways to pick the address

MDN describes three approaches. They differ in how much they trust.

ApproachHow it worksUse it for
Leftmost valid public IPTake the first entry that is a valid, non private addressAnalytics, coarse geography. Not security
Trusted proxy countConfigure N proxies, then take the entry at offset N minus 1 from the rightFixed topologies, such as one load balancer
Trusted proxy listScan from the right, skipping addresses on your proxy list, and take the first that is not listedChanging topologies, CDNs, multiple tiers

With one trusted proxy, the rightmost entry is the client as that proxy saw it. With three, the last two entries are your own infrastructure and the third from the right is the target.

Steps to set it up

  1. Draw the real path from the internet to your process, including CDN, load balancer and ingress.
  2. Make sure the application only accepts traffic from those proxies, using network rules or security groups.
  3. Configure your framework or web server with the proxy count or trusted list. Most frameworks have a setting for this, so use it instead of parsing the header by hand.
  4. Merge repeated X-Forwarded-For header lines before reading them. MDN warns that using only one of several header lines is insufficient.
  5. Log two fields: the verified client IP, and the raw header value, tagged as client supplied.
  6. Treat a header that is shorter than expected as untrusted rather than guessing.

What to watch for

A proxy that does not overwrite or append consistently will make your offset wrong. Test with a forged header in staging and confirm the logged address is your test machine, not the forged value.

IP addresses can also be personal data in some jurisdictions, so decide how long you keep them. The retention post linked below covers that angle.

For a sketch of the offset rule in code, take the list, split on commas, and return the entry at position minus N from the end, returning nothing when the list is shorter than N.

Quick check

Is the leftmost X-Forwarded-For value ever safe to use?

Only where spoofing has no negative effect, such as rough analytics. MDN says security uses must rely on addresses added by a trusted proxy.

Should I still log the raw header?

Yes, as a separate field marked unverified. It shows what the client claimed, which helps when you investigate forged requests.

What if my server is reachable without the proxy?

Then no part of the list can be trusted. Restrict inbound traffic so only the proxy can reach the app.

Related: Personal data in logs and structured log fields every line needs.

Safeguard scans your dependencies and code for known issues, including the web frameworks that handle this header. You can try a free scan at gold.safeguard.sh/scan.

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.