{"record":{"id":"72413f00c7e82f49","repo":"langchain-ai/langchain","slug":"cloud-metadata-endpoint","errorCode":null,"errorMessage":"cloud metadata endpoint","messagePattern":"cloud metadata endpoint","errorType":"exception","errorClass":"SSRFBlockedError","httpStatus":null,"severity":"critical","filePath":"libs/core/langchain_core/_security/_policy.py","lineNumber":212,"sourceCode":"def validate_resolved_ip(ip_str: str, policy: SSRFPolicy) -> None:\n    \"\"\"Validate a resolved IP address against the SSRF policy.\n\n    Raises SSRFBlockedError if the IP is blocked.\n    \"\"\"\n    try:\n        addr = ipaddress.ip_address(ip_str)\n    except ValueError as exc:\n        msg = \"invalid IP address\"\n        raise SSRFBlockedError(msg) from exc\n\n    if isinstance(addr, ipaddress.IPv6Address):\n        inner = _extract_embedded_ipv4(addr)\n        if inner is not None:\n            addr = inner\n\n    reason = _ip_in_blocked_networks(addr, policy)\n    if reason is not None:\n        raise SSRFBlockedError(reason)\n\n\ndef validate_hostname(hostname: str, policy: SSRFPolicy) -> None:\n    \"\"\"Validate a hostname against the SSRF policy.\n\n    Raises SSRFBlockedError if the hostname is blocked.\n    \"\"\"\n    lower = hostname.lower()\n\n    if policy.block_localhost and lower in _LOCALHOST_NAMES:\n        msg = \"localhost address\"\n        raise SSRFBlockedError(msg)\n\n    if policy.block_cloud_metadata and lower in _CLOUD_METADATA_HOSTNAMES:\n        msg = \"cloud metadata endpoint\"\n        raise SSRFBlockedError(msg)\n\n    if policy.block_k8s_internal and lower.endswith(_K8S_SUFFIX):","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/langchain-ai/langchain/blob/e32fa9a52eab3b61ad7a45399bfde59b3e580fc4/libs/core/langchain_core/_security/_policy.py#L194-L230","documentation":"`\"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.","triggerScenarios":"`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.","commonSituations":"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.","solutions":["Never disable `block_cloud_metadata` for user- or model-supplied URLs.","If a legitimate hostname resolves to 169.254.169.254, fix the DNS/VPC configuration — that resolution itself is the anomaly.","For tests, use `allowed_hosts` with a benign name rather than the literal metadata address."],"exampleFix":"# before\nawait validate_url('http://169.254.169.254/latest/meta-data/', DEFAULT_SSRF_POLICY)\n# SSRFBlockedError: cloud metadata endpoint\n\n# after — never allowlist this; restrict fetch sources by scheme/host instead\npolicy = SSRFPolicy(allowed_hosts={'api.trusted.example'})\nawait validate_url('https://api.trusted.example/data', policy)","handlingStrategy":"try-catch","validationCode":"# Defensive pre-check: never let metadata IPs near the fetch layer\nimport ipaddress\n\nMETADATA_IPS = {ipaddress.ip_address(\"169.254.169.254\")}\n\ndef looks_like_metadata(url: str) -> bool:\n    host = urlparse(url).hostname or \"\"\n    try:\n        return ipaddress.ip_address(host) in METADATA_IPS\n    except ValueError:\n        return host in {\"metadata.google.internal\", \"metadata\"}","typeGuard":null,"tryCatchPattern":"from langchain_core._security._policy import SSRFBlockedError\n\ntry:\n    await validate_url(url, policy)\nexcept SSRFBlockedError as e:\n    if \"cloud metadata\" in str(e):\n        alert_security(url)  # treat as attempted credential access\n    raise","preventionTips":["Never allowlist 169.254.169.254 or metadata hostnames in any policy.","Fetch cloud credentials via the provider SDK credential chain, not HTTP fetch tools.","Alert on this block, don't just log it — it frequently indicates prompt injection."],"tags":["ssrf","security","cloud-metadata","credentials"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}