Fix: allow any host for url for development (#16459)

This commit is contained in:
Wang Qi
2026-06-30 10:19:04 +08:00
committed by GitHub
parent 540acb4892
commit 2018eec0dc
3 changed files with 46 additions and 2 deletions

View File

@@ -151,6 +151,15 @@ def assert_url_is_safe(
logger.warning("SSRF guard blocked URL with missing host: url=%r", url)
raise ValueError("URL is missing a host.")
allow_any_host = _allow_any_host()
if allow_any_host:
logger.warning(
"SSRF guard bypass enabled via %s; allowing URL host without validation: hostname=%r url=%r",
_ALLOW_ANY_HOST_ENV,
hostname,
url,
)
try:
addr_infos = socket.getaddrinfo(hostname, None)
except socket.gaierror as exc:
@@ -161,7 +170,7 @@ def assert_url_is_safe(
for _family, _type, _proto, _canonname, sockaddr in addr_infos:
raw_ip = ipaddress.ip_address(sockaddr[0])
eff_ip = _effective_ip(raw_ip)
if not eff_ip.is_global:
if not allow_any_host and not eff_ip.is_global:
logger.warning(
"SSRF guard blocked URL: hostname=%r resolved to non-public address=%s",
hostname,

View File

@@ -21,6 +21,7 @@ import (
"fmt"
"net"
"net/url"
"os"
"strings"
)
@@ -83,6 +84,20 @@ func ResolveAndValidate(rawURL string) (originalHost string, pinnedIP net.IP, er
return "", nil, fmt.Errorf("ssrf: empty host")
}
if allowAnyHost() {
if ip := net.ParseIP(host); ip != nil {
return host, ip, nil
}
ips, lerr := net.LookupIP(host)
if lerr != nil {
return "", nil, fmt.Errorf("ssrf: resolve %s: %w", host, lerr)
}
if len(ips) == 0 {
return "", nil, fmt.Errorf("ssrf: %s has no A/AAAA records", host)
}
return host, ips[0], nil
}
// Short-circuit the well-known host aliases that DNS lookups may
// also catch, but defending against the literal name is cheap and
// saves a syscall on the common probe path.
@@ -136,6 +151,15 @@ func isPrivateOrLoopback(ip net.IP) bool {
return false
}
func allowAnyHost() bool {
switch strings.ToLower(strings.TrimSpace(os.Getenv("ALLOW_ANY_HOST"))) {
case "1", "true", "yes", "on":
return true
default:
return false
}
}
// SanitizeURL strips query parameters whose names match a small set of
// well-known credential names so error messages and logs that echo the
// request URL do not leak API keys. Anything else is preserved. The

View File

@@ -22,6 +22,7 @@ import (
"net"
"net/http"
"net/url"
"os"
"sort"
"strings"
"time"
@@ -58,6 +59,7 @@ func AssertURLSafe(rawURL string) (hostname, resolvedIP string, err error) {
return "", "", fmt.Errorf("URL is missing a host.")
}
allowAny := allowAnyHost()
addrs, err := LookupHost(hostname)
if err != nil {
return "", "", fmt.Errorf("Could not resolve hostname '%s': %v", hostname, err)
@@ -71,7 +73,7 @@ func AssertURLSafe(rawURL string) (hostname, resolvedIP string, err error) {
if ip == nil {
return "", "", fmt.Errorf("Could not parse resolved address '%s' for hostname '%s'.", addr, hostname)
}
if !isGlobalIP(effectiveIP(ip)) {
if !allowAny && !isGlobalIP(effectiveIP(ip)) {
return "", "", fmt.Errorf("URL resolves to a non-public address (%s), which is not allowed.", ip.String())
}
if resolvedIP == "" {
@@ -81,6 +83,15 @@ func AssertURLSafe(rawURL string) (hostname, resolvedIP string, err error) {
return hostname, resolvedIP, nil
}
func allowAnyHost() bool {
switch strings.ToLower(strings.TrimSpace(os.Getenv("ALLOW_ANY_HOST"))) {
case "1", "true", "yes", "on":
return true
default:
return false
}
}
func schemeAllowed(scheme string) bool {
for _, s := range AllowedURLSchemes {
if s == scheme {