Skip to content

[Bug] SSRF guards still allow 100.64.0.0/10 (CGNAT) destinations - #6256

Open
goingforstudying-ctrl wants to merge 1 commit into
usememos:mainfrom
goingforstudying-ctrl:fix/block-cgnat-ssrf
Open

[Bug] SSRF guards still allow 100.64.0.0/10 (CGNAT) destinations#6256
goingforstudying-ctrl wants to merge 1 commit into
usememos:mainfrom
goingforstudying-ctrl:fix/block-cgnat-ssrf

Conversation

@goingforstudying-ctrl

Copy link
Copy Markdown

The link preview fetcher and the webhook delivery path both guard against SSRF by rejecting loopback, RFC 1918, and link-local addresses, but neither covers 100.64.0.0/10 (RFC 6598). Go's net.IP.IsPrivate() doesn't include that range either, so any host in CGNAT space gets treated as public.

That's a problem because GetLinkMetadata and BatchGetLinkMetadata are unauthenticated (they're in PublicMethods), and a server deployed on a network where CGNAT space is routable (Tailscale, Alibaba Cloud, some carrier networks) will happily dial an attacker-chosen destination and reflect the page title/description back. 100.100.100.200 is Alibaba Cloud's instance metadata endpoint, which serves RAM credentials. It's the same class of hole as CVE-2024-29028 and CVE-2025-22952, just for the range the earlier fix missed. More detail in #6099.

I added the range to both guards: isInternalIP in internal/httpgetter/html_meta.go now rejects 100.64.0.0/10, including IPv4-mapped IPv6 forms, and internal/webhook/validate.go gets the prefix in reservedNetworks.

Tests cover the range boundaries, the metadata address, the mapped IPv6 form, and public addresses just outside the range for both guards, plus a dial-time rejection test. There was an earlier attempt in #6101 that only touched the httpgetter side, so I made sure the webhook path is covered here too.

Verified with go test -race ./internal/httpgetter/... ./internal/webhook/..., both packages green.

@goingforstudying-ctrl
goingforstudying-ctrl requested a review from a team as a code owner September 1, 2026 06:33
@coderabbitai

coderabbitai Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 8f3b0972-e0c1-4184-b504-c180d51eb8a8

📥 Commits

Reviewing files that changed from the base of the PR and between de843f6 and 53742e7.

📒 Files selected for processing (4)
  • internal/httpgetter/html_meta.go
  • internal/httpgetter/html_meta_test.go
  • internal/webhook/validate.go
  • internal/webhook/webhook_test.go

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.


Walkthrough

The change classifies RFC-6598 CGNAT addresses as internal in HTTP metadata fetching and as reserved in webhook URL validation. Tests cover range boundaries, Alibaba metadata addresses, IPv4-mapped IPv6 addresses, secure dialing, and URL rejection.

Suggested reviewers: bluedbird, boojack

Merge Risk: ⚪ Minimal · up to 53742

The change blocks CGNAT destinations in both server-side request paths without expanding access or weakening authorization; no actionable merge-blocking risk remains after normal checks and review.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.18% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 11 functions across 4 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: blocking SSRF destinations in the RFC 6598 CGNAT range.
Description check ✅ Passed The description directly explains the SSRF vulnerability, identifies both affected paths, describes the code and test changes, and records verification results.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Sep 1, 2026

Copy link
Copy Markdown

Greptile Summary

The PR closes an SSRF gap by treating RFC 6598 shared address space (100.64.0.0/10) as internal in both link-preview and webhook outbound-request guards.

  • Adds CGNAT detection for literal, DNS-resolved, and IPv4-mapped addresses in the link-preview fetcher.
  • Adds the CGNAT prefix to webhook validation and dial-time destination checks while preserving explicit allowlist behavior.
  • Adds boundary, metadata-endpoint, mapped-address, and dial-time regression coverage.

Confidence Score: 5/5

The PR appears safe to merge and consistently closes the identified CGNAT SSRF path in both affected outbound HTTP flows.

The added range check precisely covers 100.64.0.0/10, preserves adjacent public addresses, handles mapped IPv4 forms, and is enforced at the DNS-aware dial boundaries that cover redirects and hostname resolution.

Important Files Changed

Filename Overview
internal/httpgetter/html_meta.go Correctly extends the authoritative link-preview IP classifier to reject exactly 100.64.0.0/10, including IPv4-mapped IPv6 representations.
internal/httpgetter/html_meta_test.go Adds focused CGNAT boundary, metadata-address, mapped-address, literal-URL, and resolved-address regression coverage.
internal/webhook/validate.go Adds RFC 6598 space to the shared reserved-prefix list used consistently by webhook validation and dial-time enforcement.
internal/webhook/webhook_test.go Verifies webhook CGNAT classification boundaries and default rejection of the Alibaba metadata address.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  U[User-controlled URL] --> V{Initial URL validation}
  V --> R[Resolve destination]
  R --> C{Address in blocked range?}
  C -->|Yes, no explicit webhook exception| X[Reject request]
  C -->|No| D[Dial resolved address]
  C -->|Explicit webhook allowlist| D
  D --> H[External HTTP destination]
Loading

Reviews (1): Last reviewed commit: "fix(security): block RFC 6598 addresses ..." | Re-trigger Greptile

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