Skip to content

v0.0.18 ​

🔒 Security ​

  • Fixed Server-Side Request Forgery (SSRF) in vision API image_url (common/image/image.go):
    • GetImageFromUrl now resolves the URL host before any HTTP request and rejects targets that resolve to any private / reserved IP range: IPv4 loopback, RFC1918, link-local (169.254.169.254 cloud metadata), CGNAT 100.64.0.0/10, IPv6 ULA fc00::/7, IPv6 link-local fe80::/10, IPv4-mapped IPv6 ::ffff:127.0.0.1, and so on.
    • Replaced the bare http.Get(url) with client.UserContentRequestHTTPClient.Get(url) so the image fetch honors USER_CONTENT_REQUEST_PROXY and USER_CONTENT_REQUEST_TIMEOUT like the other two URL fetches in the same file — closing a small audit-bypass where this one call would otherwise bypass the configured outbound proxy.
    • Only http / https schemes are allowed; other schemes (file://, gopher://, etc.) are rejected.
  • New IsPrivateIP(ip net.IP) bool helper (common/network/ip.go):
    • Covers IPv4 loopback / RFC1918 / link-local / CGNAT / 0.0.0.0/8 / multicast / reserved; IPv6 loopback / ULA / link-local / multicast; and IPv4-mapped IPv6.
    • Branched on ip.To4() so that a plain IPv4 input is not accidentally matched against the IPv4-mapped IPv6 CIDR (::ffff:0:0/96) — that mistake would have wrongly flagged 172.15.255.255 (public) as private.
  • New IsPrivateIP unit tests (common/network/ip_test.go): cover loopback, RFC1918, link-local (cloud metadata), CGNAT, IPv6 ULA, IPv4-mapped IPv6 private ranges, and confirm that public IPs and boundary addresses (172.15.x, 172.32.x, 100.63.x) are allowed.

⚠️ Upgrade Notes ​

  • Zero database migration: backend-only logic fix; no schema changes.
  • A backend restart is required: GetImageFromUrl and IsPrivateIP only take effect after the binary is rebuilt and the one-api-pro process is restarted.
  • Behavior change:
    • Any vision-API call (Anthropic / Ollama / Gemini adaptors etc.) whose image_url resolves to an internal / private address (127.0.0.1, 10.x.x.x, 192.168.x.x, 172.16-31.x.x, 169.254.169.254, IPv6 ULA, IPv4-mapped IPv6 of these, etc.) is now silently rejected, consistent with the existing _ , _ , _ := image.GetImageFromUrl(...) error-discarding convention used by all callers.
    • If you have a legitimate image source on an internal network (e.g. a self-hosted CDN), the default policy will block it. An allow-list configuration is intentionally not part of this release (kept minimal per upstream PR #2390). Reach out if you need one.
  • Build & test:
    • go build ./... passes.
    • go test ./common/network/... ./common/image/... is green (26 new IsPrivateIP assertions; pre-existing TestIsIpInSubnet still green).
  • Blast radius: four callers consume GetImageFromUrl / GetImageSize — relay/adaptor/anthropic/main.go:136, relay/adaptor/provider/ollama/main.go:48, relay/adaptor/provider/gemini/main.go:118, relay/adaptor/openai/token.go:206. None of their signatures change; rejections are transparent to them thanks to the existing silent-discard semantics.

参考 / References: