Graphify-Labs/graphify · error · ValueError

Blocked cloud metadata endpoint '{hostname}'. Got: {url!r}

Error message

Blocked cloud metadata endpoint '{hostname}'. Got: {url!r}

What it means

ValueError from validate_url when the URL's hostname is in _BLOCKED_HOSTS - known cloud metadata endpoint names (e.g. metadata.google.internal). This is tier two of the SSRF guard: even with an http(s) scheme, metadata hostnames are refused before DNS resolution or connection.

Source

Thrown at graphify/security.py:122

    """Raise ValueError if *url* is not http or https, or targets a private/internal IP.

    Blocks file://, ftp://, data:, and any other scheme that could be used
    for SSRF or local file access. Also blocks requests to private/reserved
    IP ranges (127.x, 10.x, 169.254.x, etc.) and cloud metadata endpoints
    to prevent SSRF in cloud environments.
    """
    parsed = urllib.parse.urlparse(url)
    if parsed.scheme.lower() not in _ALLOWED_SCHEMES:
        raise ValueError(
            f"Blocked URL scheme '{parsed.scheme}' - only http and https are allowed. "
            f"Got: {url!r}"
        )

    hostname = parsed.hostname
    if hostname:
        # Block known cloud metadata hostnames
        if hostname.lower() in _BLOCKED_HOSTS:
            raise ValueError(
                f"Blocked cloud metadata endpoint '{hostname}'. "
                f"Got: {url!r}"
            )

        # Resolve hostname and block private/reserved IP ranges
        try:
            infos = socket.getaddrinfo(hostname, None, socket.AF_UNSPEC, socket.SOCK_STREAM)
            for info in infos:
                addr = info[4][0]
                ip = ipaddress.ip_address(addr)
                if _ip_is_blocked(ip):
                    raise ValueError(
                        f"Blocked private/internal IP {addr} (resolved from '{hostname}'). "
                        f"Got: {url!r}"
                    )
        except socket.gaierror as exc:
            raise ValueError(
                f"DNS resolution failed for '{hostname}': {exc}. Got: {url!r}"

View on GitHub (pinned to 7fe58b0b0f)

Solutions

  1. If this is your own service: treat the block as correct - do not proxy metadata endpoints; remove the URL from config.
  2. If triggered by user input: return a 4xx and log the attempt (potential SSRF probe).
  3. For cloud config that genuinely needs metadata, use the cloud SDK/IMDS client on the instance itself, not the URL fetcher.

Example fix

# before
url = cfg['health_check_url']   # 'http://metadata.google.internal/computeMetadata/v1/'
fetch(url)                       # ValueError: Blocked cloud metadata endpoint

# after
url = 'https://real-service.internal/healthz'   # use a routable endpoint
fetch(validate_url(url))
Defensive patterns

Strategy: validation

Validate before calling

from urllib.parse import urlparse

BLOCKED = {"metadata.google.internal", "instance-data"}  # mirror your guard's set
if (urlparse(url).hostname or "").lower() in BLOCKED:
    raise HTTPBadRequest("metadata endpoints are not allowed")

Type guard

def is_safe_url(url: str) -> bool:
    try:
        validate_url(url)
        return True
    except ValueError:
        return False

Try / catch

try:
    safe = validate_url(url)
except ValueError as exc:
    if "Blocked cloud metadata" in str(exc):
        log.security("SSRF attempt? url=%r", url)
        return forbidden(str(exc))
    raise

Prevention

When it happens

Trigger: validate_url(url) where parsed.hostname.lower() is in the _BLOCKED_HOSTS set (security.py:118-122). Any http://metadata.google.internal/... style URL from user input or config hits this immediately.

Common situations: SSRF probing of an app that accepts URLs (attack traffic); misconfigured service templates pointing at metadata names; testing scripts copied from cloud docs that use metadata hostnames as examples; proxy configs that forward metadata names.

Related errors


AI-assisted analysis of Graphify-Labs/graphify@7fe58b0b0f (2026-08-14). Data as JSON: /api/errors/7b688811ce76db9d. Report an issue: GitHub.