Skip to content

feat(core): harden anti-ssrf#35960

Draft
Eugene Yurtsev (eyurtsev) wants to merge 5 commits intomasterfrom
eugene/harden_ssrf
Draft

feat(core): harden anti-ssrf#35960
Eugene Yurtsev (eyurtsev) wants to merge 5 commits intomasterfrom
eugene/harden_ssrf

Conversation

@eyurtsev
Copy link
Collaborator

@eyurtsev Eugene Yurtsev (eyurtsev) commented Mar 16, 2026

harden anti-ssrf

@github-actions github-actions bot added internal core `langchain-core` package issues & PRs size: S 50-199 LOC feature For PRs that implement a new feature; NOT A FEATURE REQUEST and removed internal feature For PRs that implement a new feature; NOT A FEATURE REQUEST labels Mar 16, 2026
@codspeed-hq
Copy link

codspeed-hq bot commented Mar 16, 2026

Merging this PR will improve performance by 35.4%

⚠️ Unknown Walltime execution environment detected

Using the Walltime instrument on standard Hosted Runners will lead to inconsistent data.

For the most accurate results, we recommend using CodSpeed Macro Runners: bare-metal machines fine-tuned for performance measurement consistency.

⚡ 11 improved benchmarks
✅ 2 untouched benchmarks
⏩ 23 skipped benchmarks1

Performance Changes

Mode Benchmark BASE HEAD Efficiency
WallTime test_import_time[LangChainTracer] 476.6 ms 426.7 ms +11.7%
WallTime test_async_callbacks_in_sync 25.1 ms 18.5 ms +35.4%
WallTime test_import_time[HumanMessage] 269.5 ms 242 ms +11.37%
WallTime test_import_time[PydanticOutputParser] 557.4 ms 492.7 ms +13.13%
WallTime test_import_time[InMemoryRateLimiter] 177.2 ms 160.4 ms +10.42%
WallTime test_import_time[CallbackManager] 327.4 ms 290 ms +12.93%
WallTime test_import_time[BaseChatModel] 554.8 ms 489.1 ms +13.42%
WallTime test_import_time[Document] 191.9 ms 174.3 ms +10.11%
WallTime test_import_time[Runnable] 510.1 ms 454.5 ms +12.24%
WallTime test_import_time[ChatPromptTemplate] 655.9 ms 566.2 ms +15.84%
WallTime test_import_time[tool] 561.3 ms 490 ms +14.55%

Comparing eugene/harden_ssrf (e65d0cd) with master (1d2916b)

Open in CodSpeed

Footnotes

  1. 23 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@jkennedyvz
Copy link
Contributor

Additional CLOUD_METADATA_IPS entries + range check

Tested the current post-PR blocklist against known cloud metadata endpoints. A few gaps found — all specifically affect the allow_private=True path, since that skips is_private_ip and relies solely on is_cloud_metadata to block metadata endpoints.

Missing from CLOUD_METADATA_IPS

These IPs fall within PRIVATE_IP_RANGES (so they're blocked when allow_private=False), but are reachable when allow_private=True because they're not in CLOUD_METADATA_IPS:

IP Provider Service
169.254.170.23 AWS EKS Pod Identity Agent
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)

Suggested fix

Rather than enumerating every 169.254.x.x address individually, block the entire link-local range in is_cloud_metadata. This covers all current entries and any future provider using this range:

CLOUD_METADATA_RANGES = [
    ipaddress.ip_network("169.254.0.0/16"),
]

# Add IPv6 metadata endpoints not covered by the range:
CLOUD_METADATA_IPS = [
    "169.254.169.254",   # AWS EC2/ECS, Azure VM, GCP, DigitalOcean, OCI, Hetzner, Vultr, Linode
    "169.254.170.2",     # AWS ECS task credential endpoint
    "169.254.170.23",    # AWS EKS Pod Identity Agent
    "100.100.100.200",   # Alibaba Cloud / Aliyun ECS (CGNAT range, not link-local)
    "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)
]

def is_cloud_metadata(hostname: str, ip_str: str | None = None) -> bool:
    if hostname.lower() in CLOUD_METADATA_HOSTNAMES:
        return True
    if ip_str:
        try:
            if ip_str in CLOUD_METADATA_IPS:
                return True
            ip = ipaddress.ip_address(ip_str)
            if any(ip in r for r in CLOUD_METADATA_RANGES):
                return True
        except ValueError:
            pass
    return False

Tested all cases — 11/11 pass including arbitrary 169.254.x.x addresses, the new IPv6 endpoints, and confirming RFC1918 private IPs (10.x, 192.168.x) are correctly not flagged as cloud metadata.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core `langchain-core` package issues & PRs feature For PRs that implement a new feature; NOT A FEATURE REQUEST size: S 50-199 LOC

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants