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

  1. Advertise a concrete reachable host or DNS name in the server's metadata, never the bind address
  2. Fix the server config so the public-facing URL (scheme + host + port) is distinct from the listen specification
  3. 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

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


AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20). Data as JSON: /api/errors/cf72c92e76a0a880. Report an issue: GitHub.