langchain-ai/langchain · error · SSRFBlockedError
blocked CIDR
Error message
blocked CIDR
What it means
`"blocked CIDR"` is the reason emitted by `_ip_in_blocked_networks` when the resolved IP matches a network explicitly listed in the policy's `blocked_cidrs` (as opposed to the built-in private/localhost/metadata categories). It propagates as `SSRFBlockedError` from the same `raise SSRFBlockedError(reason)` line in `validate_resolved_ip`, reached both from `validate_url` (per resolved addrinfo entry) and `validate_url_sync` (for IP-literal hostnames).
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
- Check the policy's `blocked_cidrs` and confirm the target IP genuinely should be allowed; if so, remove/adjust that network in the policy you construct.
- If the block is correct, switch the tool to an allowed mirror/CDN hostname or route via an approved proxy.
- Re-resolve the hostname — a stale DNS entry or rebinding may put it in the blocked range; pin the hostname to `allowed_hosts` only if it is trusted.
Example fix
# before
policy = SSRFPolicy(blocked_cidrs=[ipaddress.ip_network('203.0.113.0/24')])
await validate_url('http://203.0.113.5/docs', policy) # blocked CIDR
# after
policy = SSRFPolicy(blocked_cidrs=[ipaddress.ip_network('203.0.113.0/25')])
await validate_url('http://203.0.113.5/docs', policy) # outside /25 Defensive patterns
Strategy: try-catch
Validate before calling
import ipaddress
def in_blocked_cidr(host: str, cidrs: list[str]) -> bool:
try:
ip = ipaddress.ip_address(host)
except ValueError:
return False
return any(ip in ipaddress.ip_network(c) for c in cidrs) Try / catch
from langchain_core._security._policy import SSRFBlockedError
try:
await validate_url(url, policy)
except SSRFBlockedError as e:
if "blocked CIDR" in str(e):
raise PermanentlyBlockedURL(url) from e # do not retry; policy is deterministic
raise Prevention
- Keep the blocked_cidrs list in version control with an owner; surface it in error dashboards when fetches fail.
- Treat CIDR blocks as permanent (no retry) — only DNS-transient failures are worth retrying.
- Log the resolved IP alongside the block reason so on-call can distinguish policy hits from DNS rebinding.
When it happens
Trigger: A policy configured like `SSRFPolicy(blocked_cidrs=[ipaddress.ip_network('203.0.113.0/24')])` and a URL whose host resolves into 203.0.113.0/24; or using a shipped policy preset that blocklists a specific corporate/external range and the fetched URL lands in it.
Common situations: Org-level deployments where a security team blocklists specific egress ranges; after a policy file is tightened, previously working document-loader/tool URLs (web research tools, URL fetch utilities) suddenly fail with a bare 'blocked CIDR' message; or DNS rebinding changes a hostname's resolution into a blocked range overnight.
Related errors
- invalid IP address
- private IP range
- localhost address
- {exc}
- Failed to resolve hostname '{hostname}': {e}
AI-assisted analysis of langchain-ai/langchain@e32fa9a52e (2026-08-14).
Data as JSON: /api/errors/ce34e10366e35fcf.
Report an issue: GitHub.