lfnovo/open-notebook · critical · ValueError

Link-local addresses (169.254.x.x) are not allowed for secur

Error message

Link-local addresses (169.254.x.x) are not allowed for security reasons. These addresses are used for cloud metadata endpoints.

What it means

The URL contained a literal link-local IP (169.254.x.x, fe80::/10, or an IPv4-mapped form like ::ffff:169.254.169.254) rather than a hostname. Because these addresses serve cloud metadata endpoints, they are unconditionally rejected regardless of how they were written. The 'resolved' variant of the message is used when the value came from DNS; this one fires for direct literals.

Source

Thrown at open_notebook/utils/url_validation.py:231

    hostname: str,
    resolved: bool = False,
) -> None:
    """Raise ValueError if `ip` is a link-local or cloud-metadata address."""
    is_ipv4_mapped_link_local = (
        hasattr(ip, "ipv4_mapped") and ip.ipv4_mapped and ip.ipv4_mapped.is_link_local
    )

    # Block link-local addresses (169.254.x.x / fe80::/10) - used for cloud
    # metadata - including IPv4-mapped IPv6 addresses pointing to link-local
    # (e.g. ::ffff:169.254.169.254 bypasses IPv6 is_link_local check).
    if ip.is_link_local or is_ipv4_mapped_link_local:
        if resolved:
            raise ValueError(
                f"Hostname '{hostname}' resolves to a link-local address (169.254.x.x) "
                "which is not allowed for security reasons. These addresses are used "
                "for cloud metadata endpoints."
            )
        raise ValueError(
            "Link-local addresses (169.254.x.x) are not allowed for security reasons. "
            "These addresses are used for cloud metadata endpoints."
        )

    # Block AWS's IMDSv6 metadata address - a Unique Local Address, not
    # link-local, so it needs its own explicit check. Compare without scope
    # ID so scoped forms (fd00:ec2::254%eth0) cannot bypass the sentinel.
    is_aws_imds_v6 = (
        isinstance(ip, ipaddress.IPv6Address)
        and int(ip) == int(_AWS_IMDS_V6_ADDRESS)
    )
    if is_aws_imds_v6:
        if resolved:
            raise ValueError(
                f"Hostname '{hostname}' resolves to the AWS IMDSv6 metadata address "
                "(fd00:ec2::254), which is not allowed for security reasons."
            )
        raise ValueError(

View on GitHub (pinned to a7de90d38a)

Solutions

  1. Use the real service endpoint instead of the link-local metadata address
  2. If writing tests, assert that ValueError is raised — don't try to make the call succeed
Defensive patterns

Strategy: validation

Validate before calling

import ipaddress
from urllib.parse import urlparse

def is_literal_link_local(url: str) -> bool:
    host = urlparse(url).hostname or ""
    try:
        ip = ipaddress.ip_address(host)
    except ValueError:
        return False
    return ip.is_link_local or (ip.version == 6 and int(ip) == int(ipaddress.IPv6Address("::ffff:169.254.169.254")))

Try / catch

try:
    validate_url(url)
except ValueError as e:
    if "Link-local" in str(e):
        return {"allowed": False, "reason": "cloud-metadata-blocked"}
    raise

Prevention

When it happens

Trigger: Passing 'http://169.254.169.254/latest/meta-data/' or 'http://[fe80::1]/' directly as a base_url to validate_url or prepare_pinned_http_target (and thus to any discover/connection-test call).

Common situations: SSRF probing of instance metadata; debugging scripts that copied the metadata endpoint; test suites deliberately probing the guardrail.

Related errors


AI-assisted analysis of lfnovo/open-notebook@a7de90d38a (2026-08-27). Data as JSON: /api/errors/0e385601b601dafb. Report an issue: GitHub.