Repository navigation
Pointing the OpenAI component at a local endpoint: loopback is blocked by default now, and what that changes #15059
Replies: 1 comment
|
the writeup is accurate and the fix is correct. one thing worth adding for docker users: if langflow is containerized and your ollama/vllm instance is on the host, the credential-exfiltration concern you flagged is real and undersold. the ssrf block helps but doesn't cover cases where the field value is an external host the operator controls, yet another tenant's key gets sent there. full fix for that is never letting the raw key reach the request at all, which is a different architectural problem. (i work on 1claw, which takes that approach via vault references, if that's relevant to anyone reading.) |
Uh oh!
There was an error while loading. Please reload this page.
I was recording a Langflow run against a local OpenAI-compatible endpoint and hit a wall that I think a lot of people running Ollama, vLLM, LM Studio or LiteLLM alongside Langflow will hit too. It is working as designed, the error message even names the fix, but it is a behaviour change worth surfacing.
The finding
Setting the OpenAI component's API Base to a loopback address fails:
localhostis blocked identically (::1, 127.0.0.1). The reason is documented right inlfx/base/models/provider_ssrf.py:And the rationale is sound: that field is tenant-editable, and the SDK sends the operator's stored API key to whatever host it names — so an unvalidated field is both an SSRF primitive and a credential-exfiltration primitive. Blocking loopback, RFC1918 and cloud metadata by default is the right call for a multi-tenant deployment.
Measured both directions on 1.12.1:
With the allowlist set, the component also gets DNS-pinned, redirect-free httpx clients rather than plain ones — so the local case is not just "unblocked", it is still hardened against rebinding.
Two things that surprised me
openai_chat_model.py:117passes"base_url": self.openai_api_base or DEFAULT_OPENAI_API_BASE— always explicit. SoOPENAI_BASE_URLandOPENAI_API_BASE(the latter of whichlangchain-openaiitself honours, and prefers over the former) have no effect in Langflow. The component field is the only lever. Worth knowing, because anyone arriving from rawlangchain-openaiwill expect otherwise.LANGFLOW_SSRF_ALLOWED_HOSTSin the component's error surface in the UI. Genuinely asking whether that is already somewhere I missed.What I was doing when I found it
Recording a Langflow run at the HTTP boundary to the provider — from outside the process, nothing installed into Langflow — so the run can be replayed later with no provider contacted.
With the allowlist set, this works end to end:
Record the run, kill the upstream endpoint, point the same component at the recording, and the component answers from it — same
base_url, same reply, nothing upstream alive. The SSRF-hardened client makes no difference here, because a recording proxy on an allowlisted loopback address is exactly the shape the policy permits.Practical use: a flow that produced a bad answer becomes a file a colleague can re-run without your key and without spending tokens, and the same file pins a flow's prompts in CI — which is otherwise awkward, since real calls cost money and do not answer the same way twice.
Limits worth stating
langflow1.12.1, Python 3.12, with the component driven directly rather than through the UI — the SSRF result is fromopenai_compatible_client_kwargsitself, so it applies wherever that seam is used, but I have not clicked through the visual editor to confirm the error surfaces legibly there.Tool is OrcaReplay (Apache-2.0); I maintain it, so weigh accordingly. The SSRF finding is about Langflow and holds regardless of what you put on the other end of that address.
All reactions