{"record":{"id":"3b67674d7909dd48","repo":"langchain-ai/langchain","slug":"localhost-address","errorCode":null,"errorMessage":"localhost address","messagePattern":"localhost address","errorType":"exception","errorClass":"SSRFBlockedError","httpStatus":null,"severity":"error","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":"`\"localhost address\"` is the reason returned when the resolved IP equals or falls in the loopback range (127.0.0.0/8, ::1) and `block_localhost` is enabled — reported through the shared `raise SSRFBlockedError(reason)` in `validate_resolved_ip`. This blocks the classic SSRF vector of pointing a fetched URL at the machine's own loopback interface, where local-only services (metadata agents, admin ports) listen.","triggerScenarios":"`await validate_url('http://127.0.0.1:8000/health')` or a hostname resolving to 127.0.0.1 under a policy with `block_localhost=True`. Note the hostname-level twin at line ~224: `validate_hostname` raises the same message for literal names in `_LOCALHOST_NAMES` (e.g. 'localhost') before DNS even runs.","commonSituations":"Local development pointing a web loader or custom tool at a dev server (`http://localhost:3000`), or in CI where services are addressed on loopback. Also triggered by attacker-supplied URLs in agent workflows that try `http://localhost/` to reach the host's internal services — which is exactly what the guard is for.","solutions":["Add the dev hostname to `allowed_hosts`, or run under `LANGCHAIN_ENV=local...` so `_effective_allowed_hosts` automatically admits 'localhost' and 'testserver'.","Address the service via a non-loopback interface or container hostname that is explicitly allowed.","Keep the block on for any user-supplied URL — allowlisting loopback globally in production is a real SSRF exposure."],"exampleFix":"# before\nawait validate_url('http://localhost:3000/data', DEFAULT_SSRF_POLICY)\n# SSRFBlockedError: localhost address\n\n# after (local dev)\nimport os\nos.environ['LANGCHAIN_ENV'] = 'local'\nawait validate_url('http://localhost:3000/data', DEFAULT_SSRF_POLICY)","handlingStrategy":"try-catch","validationCode":"import socket, ipaddress\n\ndef resolves_to_loopback(host: str) -> bool:\n    try:\n        ip = ipaddress.ip_address(host)\n        return ip.is_loopback\n    except ValueError:\n        infos = socket.getaddrinfo(host, 443, type=socket.SOCK_STREAM)\n        return all(ipaddress.ip_address(i[4][0]).is_loopback for i in infos)","typeGuard":null,"tryCatchPattern":"from langchain_core._security._policy import SSRFBlockedError\n\ntry:\n    await validate_url(url, policy)\nexcept SSRFBlockedError as e:\n    if \"localhost address\" in str(e) and env == \"dev\":\n        return await validate_url(url, dev_policy)  # LANGCHAIN_ENV=local allowlist\n    raise","preventionTips":["Use LANGCHAIN_ENV=local (or add localhost to allowed_hosts) in dev; keep defaults strict in prod.","Address dev services via explicitly allowed hostnames, not raw loopback IPs, so policy intent stays auditable."],"tags":["ssrf","security","localhost","network"],"backgroundTag":null,"analyzedSha":"e32fa9a52eab3b61ad7a45399bfde59b3e580fc4","analyzedAt":"2026-08-14T18:42:09.092Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}