Skip to content

fix: block SSRF in fetchSpec and GraphQL introspection#6

Open
karthikmudaliarX wants to merge 1 commit into
ShawnPana:mainfrom
karthikmudaliarX:fix/ssrf-url-validation
Open

fix: block SSRF in fetchSpec and GraphQL introspection#6
karthikmudaliarX wants to merge 1 commit into
ShawnPana:mainfrom
karthikmudaliarX:fix/ssrf-url-validation

Conversation

@karthikmudaliarX

Copy link
Copy Markdown

Summary

aurl add <name> <url> and aurl add --graphql <name> <endpoint> both fetched user-supplied URLs without any validation, making them vulnerable to SSRF. An attacker who controls the URL (e.g. via a malicious README, a CI pipeline that passes untrusted input, or an AI agent acting on a crafted prompt) could point them at internal services:

  • AWS/GCP/Azure instance metadata (169.254.169.254)
  • localhost / 127.0.0.1 (databases, admin panels, local services)
  • RFC 1918 ranges (10.x, 172.16–31.x, 192.168.x)
  • Other reserved ranges (shared address space, benchmarking nets, multicast)

Fix

Adds internal/urlutil.ValidatePublicURL(rawURL string) error which:

  1. Rejects any scheme that isn't http or https
  2. Resolves the hostname via DNS
  3. Rejects any resolved IP that falls in a private, loopback, link-local, or otherwise reserved range (covers both IPv4 and IPv6)

ValidatePublicURL is called before the HTTP fetch in fetchSpec() (cmd/add.go) and before the POST in Introspect() (internal/graphql/introspect.go).

Ranges blocked

Range Reason
127.0.0.0/8, ::1/128 Loopback
169.254.0.0/16 Link-local / AWS instance metadata
10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 RFC 1918 private
100.64.0.0/10 Shared address space (RFC 6598)
0.0.0.0/8 "This" network
192.0.0.0/24 IETF protocol assignments
198.18.0.0/15 Benchmarking (RFC 2544)
198.51.100.0/24, 203.0.113.0/24 Documentation TEST-NETs
224.0.0.0/4, ff00::/8 Multicast
240.0.0.0/4 Reserved
fc00::/7 IPv6 unique local
fe80::/10 IPv6 link-local

User-supplied URLs were fetched without validation, allowing requests
to reach internal services (AWS metadata at 169.254.169.254, localhost,
RFC 1918 ranges, etc.).

Adds internal/urlutil.ValidatePublicURL which:
- Rejects non-http/https schemes
- Resolves the hostname via DNS
- Rejects any address that falls within loopback, link-local, private
  RFC 1918, shared address space, multicast, or other reserved ranges

Called before the HTTP fetch in cmd/add.go (fetchSpec) and before the
POST in internal/graphql/introspect.go (Introspect).
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