[Bug] SSRF guards still allow 100.64.0.0/10 (CGNAT) destinations - #6256
[Bug] SSRF guards still allow 100.64.0.0/10 (CGNAT) destinations#6256goingforstudying-ctrl wants to merge 1 commit into
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Team Run ID: 📒 Files selected for processing (4)
Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review. WalkthroughThe 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: Merge Risk: ⚪ Minimal · up to 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)
✅ Passed checks (4 passed)
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. Comment |
Greptile SummaryThe PR closes an SSRF gap by treating RFC 6598 shared address space (
Confidence Score: 5/5The 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
|
| 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]
Reviews (1): Last reviewed commit: "fix(security): block RFC 6598 addresses ..." | Re-trigger Greptile
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'snet.IP.IsPrivate()doesn't include that range either, so any host in CGNAT space gets treated as public.That's a problem because
GetLinkMetadataandBatchGetLinkMetadataare unauthenticated (they're inPublicMethods), 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.200is 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:
isInternalIPin internal/httpgetter/html_meta.go now rejects100.64.0.0/10, including IPv4-mapped IPv6 forms, and internal/webhook/validate.go gets the prefix inreservedNetworks.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.