Skip to content

fix(provider-utils): harden SSRF protection with missing RFC-defined private IP ranges#14132

Open
Diode11-Alt wants to merge 1 commit intovercel:mainfrom
Diode11-Alt:fix/ssrf-missing-private-ranges
Open

fix(provider-utils): harden SSRF protection with missing RFC-defined private IP ranges#14132
Diode11-Alt wants to merge 1 commit intovercel:mainfrom
Diode11-Alt:fix/ssrf-missing-private-ranges

Conversation

@Diode11-Alt
Copy link
Copy Markdown

Summary

Hardens the SSRF protection in validateDownloadUrl() by adding coverage for several RFC-defined private/reserved IPv4 ranges and cloud-internal hostnames that were missing from the blocklist.

Security Impact

The current implementation blocks common private ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8, 169.254.0.0/16) but misses several additional ranges defined in IANA's Special-Purpose Address Registry that could be exploited in cloud environments:

Missing IPv4 Ranges (Now Blocked)

Range RFC Risk
100.64.0.0/10 RFC 6598 HIGH — Shared Address Space used in AWS VPCs, cloud CGNAT gateways. Attacker-controlled URLs could reach internal cloud services via this range.
198.18.0.0/15 RFC 2544 MEDIUM — Reserved for network benchmarking. Should never be externally routable.
192.0.0.0/24 RFC 6890 LOW — IETF Protocol Assignments.
192.0.2.0/24 RFC 5737 LOW — TEST-NET-1, documentation range.
198.51.100.0/24 RFC 5737 LOW — TEST-NET-2, documentation range.
203.0.113.0/24 RFC 5737 LOW — TEST-NET-3, documentation range.
240.0.0.0/4 RFC 1112 MEDIUM — Reserved for future use, includes 255.255.255.255 broadcast.

Missing Hostname Pattern (Now Blocked)

Pattern Risk
.internal HIGH — GCP cloud metadata endpoint (metadata.google.internal) resolves to 169.254.169.254. While the IP is already blocked, hostname-based requests bypass IP checks when DNS resolution happens after validation (TOCTOU).

Root Cause

The isPrivateIPv4() function only covered the "classic" RFC 1918 ranges plus link-local. The IANA Special-Purpose Address Registry (RFC 6890) defines additional ranges that are not globally reachable and should be blocked in SSRF contexts.

The 100.64.0.0/10 range is particularly dangerous because it's actively used by cloud providers (AWS, GCP, Azure) for internal networking — an attacker could use it to probe VPC-internal services, NAT gateways, or other shared infrastructure.

Changes

packages/provider-utils/src/validate-download-url.ts

  • Added 100.64.0.0/10, 198.18.0.0/15, 192.0.0.0/24, 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24, and 240.0.0.0/4 to isPrivateIPv4()
  • Added .internal to the blocked hostname patterns (alongside existing .local, .localhost)

packages/provider-utils/src/validate-download-url.test.ts

  • Added tests for all new blocked ranges with boundary checks
  • Added tests for .internal domain blocking
  • Added test for ::ffff:100.64.x.x (CGNAT via IPv4-mapped IPv6 bypass)

Verification

  • All existing tests pass unchanged
  • New tests cover both positive (blocked) and negative (allowed) cases at range boundaries
  • Example boundary checks:
    • 100.64.0.1 → BLOCKED (inside CGNAT)
    • 100.63.255.255 → ALLOWED (below CGNAT range)
    • 100.128.0.1 → ALLOWED (above CGNAT range)
    • 198.18.0.1 → BLOCKED (benchmarking)
    • 198.17.0.1 → ALLOWED (below benchmarking range)

Checklist

  • Tests have been added / updated
  • No breaking changes — only adds new blocked ranges
  • Follows existing code patterns exactly
  • Self-reviewed

…anges

Add coverage for several RFC-defined private/reserved IPv4 ranges that
were missing from the SSRF validation, which could allow attackers to
reach internal cloud infrastructure:

- 100.64.0.0/10 (Shared Address Space / CGNAT - RFC 6598)
  Used in AWS VPCs and cloud provider NAT gateways. An attacker could
  use this range to reach internal cloud services.

- 198.18.0.0/15 (Benchmarking - RFC 2544)
  Reserved for network benchmarking, should never be routable externally.

- 192.0.0.0/24 (IETF Protocol Assignments - RFC 6890)
- 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24 (Documentation - RFC 5737)

- 240.0.0.0/4 (Reserved for Future Use - RFC 1112)
  Includes 255.255.255.255 (broadcast).

Also blocks .internal domains (e.g., metadata.google.internal) which
are used by GCP for cloud metadata access.

Added comprehensive tests for all new ranges including boundary checks.
@tigent tigent bot added ai/provider related to a provider package. Must be assigned together with at least one `provider/*` label maintenance CI, internal documentation, automations, etc labels Apr 4, 2026
Copy link
Copy Markdown
Contributor

@vercel vercel bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Additional Suggestion:

Tests assert 203.0.113.1 is a public IP but the implementation now blocks it as TEST-NET-3 (RFC 5737), causing two test failures.

Fix on Vercel

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ai/provider related to a provider package. Must be assigned together with at least one `provider/*` label maintenance CI, internal documentation, automations, etc

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant