Thanks to visit codestin.com
Credit goes to github.com

Skip to content

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

Open
goingforstudying-ctrl wants to merge 2 commits 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 2 commits 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 StackReview Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 07059679-b4cd-435f-93a9-9f0c9e7d9b8d

📥 Commits

Reviewing files that changed from the base of the PR and between 3227748 and 7c38346.

📒 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
🚧 Files skipped from review as they are similar to previous changes (4)
  • internal/webhook/validate.go
  • internal/httpgetter/html_meta.go
  • internal/httpgetter/html_meta_test.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

Priority: ➖ Normal

Merge Risk: ⚪ Minimal · up to 7c383

This change blocks CGNAT addresses in link-preview fetching and webhook validation, including mapped IPv6 forms. No remaining merge-blocking risk is identified.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 12 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 identifies the SSRF guard defect and the affected CGNAT range, which matches the primary changes.
Description check ✅ Passed The description directly explains the SSRF risk, the changes to both protection paths, the test coverage, and the verification performed.
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

@coderabbitai

coderabbitai Bot commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

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