diff --git a/libs/core/langchain_core/_security/_ssrf_protection.py b/libs/core/langchain_core/_security/_ssrf_protection.py index 20632c9a949..cefd48465b6 100644 --- a/libs/core/langchain_core/_security/_ssrf_protection.py +++ b/libs/core/langchain_core/_security/_ssrf_protection.py @@ -49,10 +49,18 @@ PRIVATE_IP_RANGES = [ ] # Cloud provider metadata endpoints +CLOUD_METADATA_RANGES = [ + ipaddress.ip_network("169.254.0.0/16"), # IPv4 link-local (used by metadata services) +] + CLOUD_METADATA_IPS = [ "169.254.169.254", # AWS, GCP, Azure, DigitalOcean, Oracle Cloud "169.254.170.2", # AWS ECS task metadata + "169.254.170.23", # AWS EKS Pod Identity Agent "100.100.100.200", # Alibaba Cloud metadata + "fd00:ec2::254", # AWS EC2 IMDSv2 over IPv6 (Nitro instances) + "fd00:ec2::23", # AWS EKS Pod Identity Agent (IPv6) + "fe80::a9fe:a9fe", # OpenStack Nova metadata (IPv6 link-local equiv of 169.254.169.254) ] CLOUD_METADATA_HOSTNAMES = [ @@ -116,7 +124,12 @@ def is_cloud_metadata(hostname: str, ip_str: str | None = None) -> bool: # Check IP if ip_str: try: - if _normalize_ip(ip_str) in CLOUD_METADATA_IPS: + normalized_ip = _normalize_ip(ip_str) + if normalized_ip in CLOUD_METADATA_IPS: + return True + + ip = ipaddress.ip_address(normalized_ip) + if any(ip in range_ for range_ in CLOUD_METADATA_RANGES): return True except ValueError: pass diff --git a/libs/core/tests/unit_tests/test_ssrf_protection.py b/libs/core/tests/unit_tests/test_ssrf_protection.py index 8aa0de7b8a3..ea0768025bb 100644 --- a/libs/core/tests/unit_tests/test_ssrf_protection.py +++ b/libs/core/tests/unit_tests/test_ssrf_protection.py @@ -50,7 +50,16 @@ class TestIPValidation: """Test cloud metadata IP detection.""" assert is_cloud_metadata("example.com", "169.254.169.254") is True assert is_cloud_metadata("example.com", "169.254.170.2") is True + assert is_cloud_metadata("example.com", "169.254.170.23") is True assert is_cloud_metadata("example.com", "100.100.100.200") is True + assert is_cloud_metadata("example.com", "fd00:ec2::254") is True + assert is_cloud_metadata("example.com", "fd00:ec2::23") is True + assert is_cloud_metadata("example.com", "fe80::a9fe:a9fe") is True + + def test_is_cloud_metadata_link_local_range(self) -> None: + """Test that IPv4 link-local is flagged as cloud metadata.""" + assert is_cloud_metadata("example.com", "169.254.1.2") is True + assert is_cloud_metadata("example.com", "169.254.255.254") is True def test_is_cloud_metadata_hostnames(self) -> None: """Test cloud metadata hostname detection."""