Skip to content

fix(core, node, bun, deno): Align server span client address with event IP - #24767

Open
isaacs wants to merge 3 commits into
developfrom
isaacs/fix-client-address-handling
Open

isaacs wants to merge 3 commits into
developfrom
isaacs/fix-client-address-handling

Conversation

@isaacs

@isaacs isaacs commented Sep 25, 2026 •

Copy link
Copy Markdown
Member

Server spans in Node, Bun and Deno took client.address from the first X-Forwarded-For entry, with no check that the value is an IP. Events use getClientIPAddress for user.ip_address. That function checks the value and also reads other forwarding headers (X-Real-IP, CF-Connecting-IP, Forwarded, and more). So a span and the event for the same request could report different client IPs. Spans now use getClientIPAddress too. It is exported from @sentry/core/server.

When the address comes from a forwarding header, the socket port belongs to the proxy, not to the client. client.port is now unset in that case. (It was previously the incorrect data, now it is blank, as it should be.) network.peer.* in Node still reports the socket values.

Bun and Deno now pass the socket address to sdkProcessingMetadata.ipAddress, as Node does. Error events get user.ip_address when no forwarding header is present, and the sentry.is_localhost check works for direct loopback requests.

The vendored getClientIPAddress (from remix-utils) accepts only bare addresses, and it stays unchanged. A wrapper in packages/core/src/utils/clientIPAddress.ts normalizes the IP header values first. It strips a port (203.0.113.7:4711, [2001:db8::1]:4711), which Azure App Service sends in X-Forwarded-For. In Forwarded, it removes quotes and matches for= in any case. Spans, events and the localhost check all use the wrapper, so they still agree.

Behavior changes:

  • Behind a proxy, server spans no longer have client.port.
  • A request with both X-Client-IP and X-Forwarded-For now reports the X-Client-IP value as client.address, the same as user.ip_address on events.

This addresses the follow-up comments raised in #24523.

…nt IP

Server spans in Node, Bun and Deno took `client.address` from the first
`X-Forwarded-For` entry, with no check that the value is an IP. Events
use `getClientIPAddress` for `user.ip_address`. That function checks the
value and also reads other forwarding headers (`X-Real-IP`,
`CF-Connecting-IP`, `Forwarded`, and more). So a span and the event for
the same request could report different client IPs. Spans now use
`getClientIPAddress` too. It is exported from `@sentry/core/server`.

When the address comes from a forwarding header, the socket port belongs
to the proxy, not to the client. `client.port` is now unset in that
case. (It was previously the incorrect data, now it is blank, as it
should be.) `network.peer.*` in Node still reports the socket values.

Bun and Deno now pass the socket address to
`sdkProcessingMetadata.ipAddress`, as Node does. Error events get
`user.ip_address` when no forwarding header is present, and the
`sentry.is_localhost` check works for direct loopback requests.

Behavior changes:

- Behind a proxy, server spans no longer have `client.port`.
- A request with both `X-Client-IP` and `X-Forwarded-For` now reports
  the `X-Client-IP` value as `client.address`, the same as
  `user.ip_address` on events.

This addresses the follow-up comments raised in #24523.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@isaacs
isaacs requested a review from a team as a code owner September 25, 2026 23:20
@isaacs
isaacs requested review from JPeer264 and mydea and removed request for a team September 25, 2026 23:20
@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size % Change Change
@sentry/browser 29.24 kB - -
@sentry/browser - with treeshaking flags 27.5 kB - -
@sentry/browser - with treeshaking flags tracing without tracing 27.4 kB - -
@sentry/browser (incl. Tracing) 51.15 kB - -
@sentry/browser (incl. Tracing + Span Streaming) 51.17 kB - -
@sentry/browser (incl. Tracing, Profiling) 54.18 kB - -
@sentry/browser (incl. Tracing, Replay) 90.76 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 79.86 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 95.46 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 108.41 kB - -
@sentry/browser (incl. Feedback) 46.76 kB - -
@sentry/browser (incl. sendFeedback) 34.3 kB - -
@sentry/browser (incl. FeedbackAsync) 39.41 kB - -
@sentry/browser (incl. Metrics) 30.25 kB - -
@sentry/browser (incl. Logs) 30.51 kB - -
@sentry/browser (incl. Metrics & Logs) 31.18 kB - -
@sentry/react 31 kB - -
@sentry/react (incl. Tracing) 53.45 kB - -
@sentry/vue 36.74 kB - -
@sentry/vue (incl. Tracing) 53.7 kB - -
@sentry/svelte 29.26 kB - -
CDN Bundle 30.93 kB - -
CDN Bundle (incl. Tracing) 51.69 kB - -
CDN Bundle (incl. Logs, Metrics) 33.2 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 53.66 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 73.92 kB - -
CDN Bundle (incl. Tracing, Replay) 89.28 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 91.25 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 95.45 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 97.42 kB - -
CDN Bundle - uncompressed 91.4 kB - -
CDN Bundle (incl. Tracing) - uncompressed 153.77 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 97.97 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 159.73 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 227.54 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 273.5 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 279.44 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 287.2 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 293.13 kB - -
@sentry/nextjs (client) 55.77 kB - -
@sentry/sveltekit (client) 51.59 kB - -
@sentry/core/server 40.54 kB +1.5% +599 B 🔺
@sentry/core/browser 13.63 kB - -
@sentry/node 136.76 kB +0.1% +132 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection) 82.66 kB +0.13% +101 B 🔺
@sentry/node - without tracing 90.74 kB +0.19% +172 B 🔺
@sentry/node - without channel injection 115.24 kB +0.14% +159 B 🔺
@sentry/aws-serverless 99.01 kB +0.16% +158 B 🔺
@sentry/cloudflare (withSentry) - minified 207.12 kB +0.31% +631 B 🔺
@sentry/cloudflare (withSentry) 514.9 kB +0.23% +1.17 kB 🔺

View base workflow run

This branch has not been deployed

No deployments
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.

1 participant