langchain-ai/langchain · error · SSRFBlockedError

invalid IP address

Error message

invalid IP address

What it means

Raised by `validate_resolved_ip` in langchain_core's SSRF policy engine when the string handed to it cannot be parsed by `ipaddress.ip_address()`. This is a defensive guard: DNS-resolved addresses normally parse, so an unparseable value means the caller fed it a hostname, a malformed IP, or garbage. It is wrapped in `SSRFBlockedError` (fail-closed) rather than passed through as ValueError.

Source

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

    return None


# ---------------------------------------------------------------------------
# Public validation functions
# ---------------------------------------------------------------------------


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()

View on GitHub (pinned to e32fa9a52e)

Solutions

  1. Resolve the hostname first (e.g. `socket.getaddrinfo`) and pass `sockaddr[0]` — the parsed IP string — to `validate_resolved_ip`.
  2. Sanitize/normalize the IP string before validation (strip zone index, brackets from `[::1]`, port suffixes).
  3. In tests, use real IP literals (`127.0.0.1`, `::1`) rather than placeholder strings in fake addrinfo.

Example fix

# before
validate_resolved_ip(request.host, policy)  # host is 'example.com'

# after
infos = socket.getaddrinfo(request.host, 443, type=socket.SOCK_STREAM)
for info in infos:
    validate_resolved_ip(info[4][0], policy)
Defensive patterns

Strategy: validation

Validate before calling

import ipaddress

def is_valid_ip(value: str) -> bool:
    try:
        ipaddress.ip_address(value)
        return True
    except ValueError:
        return False

assert is_valid_ip("127.0.0.1") and not is_valid_ip("example.com")

Type guard

import ipaddress

def is_ip_literal(value: str) -> bool:
    """True only for strings ipaddress can parse (v4 or v6, no zone index)."""
    try:
        ipaddress.ip_address(value)
        return True
    except ValueError:
        return False

Try / catch

from langchain_core._security._policy import SSRFBlockedError

try:
    validate_resolved_ip(ip_str, policy)
except SSRFBlockedError as e:
    if str(e) == "invalid IP address":
        log.error("caller passed a non-IP %r to validate_resolved_ip", ip_str)
    raise

Prevention

When it happens

Trigger: `validate_resolved_ip('not-an-ip', policy)`, `validate_resolved_ip('192.168.1', policy)` (truncated IPv4), or passing a hostname like `'example.com'` directly instead of a resolved address. Also reachable via `validate_url` if a hostname that is neither in allowed_hosts nor DNS-resolvable reaches the IP check path, or via `validate_url_sync` which calls `validate_resolved_ip(hostname, policy)` after a successful `ipaddress.ip_address(hostname)` — where exotic IPv6 forms can slip through urlparse and fail here.

Common situations: Custom integrations calling the SSRF validators with raw user input instead of socket-resolved addresses; unit tests that synthesize fake addrinfo tuples with placeholder strings; or IPv6 literals with zone indices (`fe80::1%eth0`) that `ip_address` rejects on some Python versions.

Related errors


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