Skip to content

fix(mcp): skip loopback and IPv6 private IPs in getClientIp#2875

Merged
fahreddinozcan merged 2 commits into
upstash:masterfrom
syf2211:fix/mcp-client-ip-private-range-filter-2874
Jul 6, 2026
Merged

fix(mcp): skip loopback and IPv6 private IPs in getClientIp#2875
fahreddinozcan merged 2 commits into
upstash:masterfrom
syf2211:fix/mcp-client-ip-private-range-filter-2874

Conversation

@syf2211

@syf2211 syf2211 commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Summary

Extend getClientIp private/local IP filtering so reverse proxies that prepend loopback or health-check addresses no longer pollute mcp-client-ip analytics.

Fixes #2874

Motivation

getClientIp already skipped RFC1918 ranges when walking X-Forwarded-For, but still accepted loopback (127.*), IPv4 link-local (169.254.*), and common IPv6 private ranges. A header like 127.0.0.1, 8.8.8.8 incorrectly returned 127.0.0.1 instead of the public client IP.

Changes

  • Extract getClientIp into packages/mcp/src/lib/client-ip.ts
  • Add isPrivateOrLocalIp() covering RFC1918, 127.0.0.0/8, 169.254.0.0/16, ::1, fe80::/10, and fc00::/7
  • Import the helper from index.ts without changing fallback behavior when all forwarded IPs are private
  • Add regression tests in packages/mcp/test/client-ip.test.ts

Tests

cd packages/mcp
npx vitest run
npx tsc --noEmit
npx eslint src/lib/client-ip.ts src/index.ts test/client-ip.test.ts
  • 31/31 tests passed (19 new)
  • typecheck passed
  • eslint passed on changed files

Notes

  • Socket remoteAddress handling is unchanged (no X-Forwarded-For path)
  • Reviewed with composer-2.5 subagent before submission

syf2211 and others added 2 commits July 4, 2026 08:09
Extract getClientIp into lib/client-ip.ts and extend the private/local
IP filter to cover 127.0.0.0/8, 169.254.0.0/16, ::1, fe80::/10, and
fc00::/7 when walking X-Forwarded-For. Proxies that prepend loopback or
health-check addresses no longer pollute mcp-client-ip analytics.

Fixes upstash#2874
Anchor the fe80::/10 and fc00::/7 regexes to full 4-digit first hextets
so abbreviated hextets like fe8::1 or fc::1 are no longer misclassified
as private. Match IPv6 loopback in any textual form (0::1,
0:0:0:0:0:0:0:1), add CGNAT (100.64.0.0/10) to the skip list, and add a
patch changeset.
@fahreddinozcan fahreddinozcan merged commit 41878ec into upstash:master Jul 6, 2026
1 check failed
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.

[Bug]: getClientIp private-IP filter misses 127.*, 169.254.*, and IPv6 private ranges

2 participants