zed-industries/zed · error
OAuth endpoint must not point to reserved IPv6 address: {}
Error message
OAuth endpoint must not point to reserved IPv6 address: {} What it means
The IPv6 branch of validate_oauth_url rejects endpoint URLs whose host is the unspecified address (::) or a multicast address (ff00::/8), after the IPv4-mapped check has passed. An unspecified host has no real destination, and a multicast host would make the HTTP client send token traffic to a group of listeners, so both are treated as reserved and unsafe for OAuth.
Source
Thrown at crates/context_server/src/oauth.rs:107
}
url::Host::Ipv6(ip) => {
// Check for IPv4-mapped IPv6 addresses (::ffff:a.b.c.d) which
// could bypass the IPv4 checks above.
if let Some(mapped_v4) = ip.to_ipv4_mapped() {
if mapped_v4.is_private()
|| mapped_v4.is_link_local()
|| mapped_v4.is_broadcast()
|| mapped_v4.is_unspecified()
{
bail!(
"OAuth endpoint must not point to private/reserved IP: ::ffff:{}",
mapped_v4
);
}
}
if ip.is_unspecified() || ip.is_multicast() {
bail!(
"OAuth endpoint must not point to reserved IPv6 address: {}",
ip
);
}
// IPv6 Unique Local Addresses (fc00::/7). is_unique_local() is
// nightly-only, so check the prefix manually.
if (ip.segments()[0] & 0xfe00) == 0xfc00 {
bail!(
"OAuth endpoint must not point to IPv6 unique-local address: {}",
ip
);
}
}
url::Host::Domain(_) => {
// Domain-based SSRF prevention requires resolver-level checks.
// See known limitation in the doc comment above.
}
}View on GitHub (pinned to f4178619ac)
Solutions
- Advertise a concrete reachable host or DNS name in the server's metadata, never the bind address
- Fix the server config so the public-facing URL (scheme + host + port) is distinct from the listen specification
- If local, use localhost/127.0.0.1 which are explicitly permitted
Example fix
# before (bind address used as URL) "authorization_servers": ["https://[::]:8443"] # after "authorization_servers": ["https://auth.example.com:8443"]
Defensive patterns
Strategy: validation
Validate before calling
use url::Url;
fn ipv6_host_allowed(url: &Url) -> bool {
match url.host() {
Some(url::Host::Ipv6(ip)) => !ip.is_unspecified() && !ip.is_multicast(),
_ => true,
}
}
if !ipv6_host_allowed(&endpoint) {
bail_user_config!("endpoint uses reserved IPv6 (unspecified/multicast): {}", endpoint);
} Type guard
fn is_concrete_ipv6_literal(url: &Url) -> Option<bool> {
match url.host() {
Some(url::Host::Ipv6(ip)) => Some(!ip.is_unspecified() && !ip.is_multicast()),
_ => None,
}
} Try / catch
match validate_oauth_url(&endpoint) {
Err(err) if err.to_string().contains("reserved IPv6") => {
// bind-address used as URL — fix the server's advertised origin
report_metadata_bug(&endpoint, err);
Err(err)
}
other => other,
} Prevention
- Keep listen addresses (0.0.0.0, ::) strictly separate from advertised URLs in server configs
- Lint generated metadata documents for IP-literal hosts of any kind before shipping
- Prefer DNS names even for IPv6-only deployments
When it happens
Trigger: An endpoint URL with host :: (e.g. https://[::]:8080/token, typically produced by binding-address strings mistakenly copied into a URL) or a multicast literal such as https://[ff02::1]/oauth/token passed to validate_oauth_url().
Common situations: A server config that lists its bind address (0.0.0.0 or ::) as its advertised URL instead of a reachable host; malformed metadata documents generated by templating that inject the listener address; security probes that enumerate reserved IPv6 forms.
Related errors
- OAuth endpoint must not point to private/reserved IP: ::ffff
- OAuth endpoint must not point to IPv6 unique-local address:
- OAuth endpoint must not point to private/reserved IP: {}
- OAuth endpoint must use HTTPS (got {}://{})
- WWW-Authenticate header does not use Bearer scheme
AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20).
Data as JSON: /api/errors/cf72c92e76a0a880.
Report an issue: GitHub.