langchain-ai/langchain · error · SSRFBlockedError
private IP range
Error message
private IP range
What it means
`"private IP range"` is the reason string returned by `_ip_in_blocked_networks` and raised as `SSRFBlockedError` at the `raise SSRFBlockedError(reason)` line in `validate_resolved_ip` when the resolved IP falls inside a private/reserved network (RFC1918 10/8, 172.16/12, 192.168/16, link-local 169.254/16, IPv6 ULA fc00::/7, etc.) and the policy blocks private ranges (the default). This is the core SSRF defense: an attacker-controlled URL must not be able to reach internal network space.
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
- If the private endpoint is trusted, pass `allow_private=True` to the API that builds the policy (`_policy_for(allow_private=...)` — e.g. the `allow_private`/`allow_http` flags on the public SSRF helper in `_ssrf_protection.py`) so private ranges are permitted.
- Add the specific hostname to `policy.allowed_hosts` (and note `_effective_allowed_hosts` auto-allows `localhost`/`testserver` when `LANGCHAIN_ENV` starts with 'local').
- Point at a public endpoint or an allowed proxy instead of the internal address.
- For local dev/tests, set `LANGCHAIN_ENV=local` (or `local_test` for testserver-style hostnames) so the policy relaxes localhost/test hosts.
Example fix
# before
result = await validate_url('http://192.168.1.20:11434/api/generate', DEFAULT_SSRF_POLICY)
# SSRFBlockedError: private IP range
# after
policy = SSRFPolicy(allowed_hosts={'192.168.1.20'})
result = await validate_url('http://192.168.1.20:11434/api/generate', policy) Defensive patterns
Strategy: try-catch
Validate before calling
import ipaddress
def is_private_target(host: str) -> bool:
try:
return ipaddress.ip_address(host).is_private
except ValueError:
return False # hostname: resolution decides later Try / catch
from langchain_core._security._policy import SSRFBlockedError
try:
await validate_url(url, policy)
except SSRFBlockedError as e:
if "private IP range" in str(e) and host_is_trusted_internal(url):
return await validate_url(url, SSRFPolicy(allowed_hosts={urlparse(url).hostname}))
raise Prevention
- Maintain an explicit allowed_hosts list for legitimate internal endpoints instead of disabling private-IP blocking wholesale.
- Reserve allow_private=True for user-configured base URLs, never model-chosen URLs.
- Set LANGCHAIN_ENV=local in dev/test so localhost-style hosts validate cleanly.
When it happens
Trigger: `await validate_url('http://192.168.1.10:8080/api')`, `await validate_url('http://10.0.0.5/metadata')`, or a hostname like `my-internal-service.internal` that DNS resolves to a private IP, under the default `SSRFPolicy(block_private_ip=True)`. IPv4-mapped IPv6 addresses (`::ffff:10.0.0.5`) are unwrapped via `_extract_embedded_ipv4` and hit the same block.
Common situations: Running langchain locally or in a container where a legitimate internal endpoint (local Ollama at `http://192.168.x.x`, an internal gateway, a docker-network service) is the target; or in tests using `http://localhost`-adjacent private addresses. Developers are surprised because the URL works in curl but the library's SSRF guard blocks it before any request is made.
Related errors
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/ab2cc427680cb9dc.
Report an issue: GitHub.