langchain-ai/langchain · critical · SSRFBlockedError

cloud metadata endpoint

Error message

cloud metadata endpoint

What it means

`"cloud metadata endpoint"` is the reason raised via `validate_resolved_ip`'s `raise SSRFBlockedError(reason)` when the resolved IP is the link-local cloud instance-metadata address (169.254.169.254, or `fd00:ec2::254` for IPv6) and `block_cloud_metadata` is on. That endpoint hands out cloud credentials (IAM roles on AWS/GCP/Azure), making it the highest-value SSRF target; the guard blocks any attempt to fetch it.

Source

Thrown at libs/core/langchain_core/_security/_policy.py:212

def validate_resolved_ip(ip_str: str, policy: SSRFPolicy) -> None:
    """Validate a resolved IP address against the SSRF policy.

    Raises SSRFBlockedError if the IP is blocked.
    """
    try:
        addr = ipaddress.ip_address(ip_str)
    except ValueError as exc:
        msg = "invalid IP address"
        raise SSRFBlockedError(msg) from exc

    if isinstance(addr, ipaddress.IPv6Address):
        inner = _extract_embedded_ipv4(addr)
        if inner is not None:
            addr = inner

    reason = _ip_in_blocked_networks(addr, policy)
    if reason is not None:
        raise SSRFBlockedError(reason)


def validate_hostname(hostname: str, policy: SSRFPolicy) -> None:
    """Validate a hostname against the SSRF policy.

    Raises SSRFBlockedError if the hostname is blocked.
    """
    lower = hostname.lower()

    if policy.block_localhost and lower in _LOCALHOST_NAMES:
        msg = "localhost address"
        raise SSRFBlockedError(msg)

    if policy.block_cloud_metadata and lower in _CLOUD_METADATA_HOSTNAMES:
        msg = "cloud metadata endpoint"
        raise SSRFBlockedError(msg)

    if policy.block_k8s_internal and lower.endswith(_K8S_SUFFIX):

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Never disable `block_cloud_metadata` for user- or model-supplied URLs.
  2. If a legitimate hostname resolves to 169.254.169.254, fix the DNS/VPC configuration — that resolution itself is the anomaly.
  3. For tests, use `allowed_hosts` with a benign name rather than the literal metadata address.

Example fix

# before
await validate_url('http://169.254.169.254/latest/meta-data/', DEFAULT_SSRF_POLICY)
# SSRFBlockedError: cloud metadata endpoint

# after — never allowlist this; restrict fetch sources by scheme/host instead
policy = SSRFPolicy(allowed_hosts={'api.trusted.example'})
await validate_url('https://api.trusted.example/data', policy)
Defensive patterns

Strategy: try-catch

Validate before calling

# Defensive pre-check: never let metadata IPs near the fetch layer
import ipaddress

METADATA_IPS = {ipaddress.ip_address("169.254.169.254")}

def looks_like_metadata(url: str) -> bool:
    host = urlparse(url).hostname or ""
    try:
        return ipaddress.ip_address(host) in METADATA_IPS
    except ValueError:
        return host in {"metadata.google.internal", "metadata"}

Try / catch

from langchain_core._security._policy import SSRFBlockedError

try:
    await validate_url(url, policy)
except SSRFBlockedError as e:
    if "cloud metadata" in str(e):
        alert_security(url)  # treat as attempted credential access
    raise

Prevention

When it happens

Trigger: `await validate_url('http://169.254.169.254/latest/meta-data/iam/...')`, or any hostname that DNS-resolves to 169.254.169.254, under the default policy with `block_cloud_metadata=True`. Also hit indirectly when a misconfigured internal DNS wildcard resolves an arbitrary name to the link-local address.

Common situations: Agent/tool workflows that accept model-chosen URLs: a prompt-injected model tries to read the instance metadata to exfiltrate credentials. Benign collisions are rare but happen with link-local network diagnostics or when testing SSRF rules themselves. In production this error on a legitimate fetch almost always means DNS is resolving your service name to the metadata IP — investigate, don't bypass.

Related errors


AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14). Data as JSON: /api/errors/72413f00c7e82f49. Report an issue: GitHub.