fix(providers): pin vLLM provider endpoint to validated IP#5077
Conversation
Validate the user-supplied vLLM endpoint (request.azureEndpoint) against the central SSRF guard and pin the connection to the resolved IP before issuing any request, mirroring the Azure OpenAI/Anthropic providers. The operator-configured VLLM_BASE_URL stays trusted and unvalidated.
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
|
@greptile |
|
@cursor review |
PR SummaryHigh Risk Overview When a user-supplied endpoint is present, the provider now runs Tests in Reviewed by Cursor Bugbot for commit 2656dc5. Configure here. |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 2656dc5. Configure here.
Greptile SummaryThis PR patches an SSRF vulnerability in the vLLM provider where the user-supplied
Confidence Score: 4/5Safe to merge; the SSRF guard is correct and the pinning wiring mirrors the already-landed Azure providers exactly. The fix is well-structured and the test suite thoroughly covers the new code paths. The only open question is whether user-supplied HTTP vLLM endpoints should be allowed — the current code blocks them, which is consistent with the Azure provider pattern but may be a breaking change for self-hosted deployments using plain HTTP inside private networks. Worth an explicit decision before merge. apps/sim/providers/vllm/index.ts — the Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Client
participant vllmProvider
participant validateUrlWithDNS
participant createPinnedFetch
participant OpenAI SDK
Client->>vllmProvider: "executeRequest({ azureEndpoint: "https://my-vllm.example.com", ... })"
alt azureEndpoint is provided (user-controlled)
vllmProvider->>validateUrlWithDNS: validateUrlWithDNS(endpoint, "vLLM endpoint")
validateUrlWithDNS-->>vllmProvider: "{ isValid: false, error: "..." }"
vllmProvider-->>Client: throw Error("Invalid vLLM endpoint: ...")
validateUrlWithDNS-->>vllmProvider: "{ isValid: true, resolvedIP: "203.0.113.10" }"
vllmProvider->>createPinnedFetch: createPinnedFetch("203.0.113.10")
createPinnedFetch-->>vllmProvider: pinnedFetch (IP-pinned undici agent)
vllmProvider->>OpenAI SDK: new OpenAI({ baseURL, apiKey, fetch: pinnedFetch })
else no azureEndpoint (env VLLM_BASE_URL used)
vllmProvider->>OpenAI SDK: new OpenAI({ baseURL: env.VLLM_BASE_URL, apiKey })
Note over vllmProvider,OpenAI SDK: No validation or pinning (trusted path)
end
OpenAI SDK->>OpenAI SDK: All HTTP calls use pinnedFetch (IP locked to 203.0.113.10)
OpenAI SDK-->>Client: Response
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Client
participant vllmProvider
participant validateUrlWithDNS
participant createPinnedFetch
participant OpenAI SDK
Client->>vllmProvider: "executeRequest({ azureEndpoint: "https://my-vllm.example.com", ... })"
alt azureEndpoint is provided (user-controlled)
vllmProvider->>validateUrlWithDNS: validateUrlWithDNS(endpoint, "vLLM endpoint")
validateUrlWithDNS-->>vllmProvider: "{ isValid: false, error: "..." }"
vllmProvider-->>Client: throw Error("Invalid vLLM endpoint: ...")
validateUrlWithDNS-->>vllmProvider: "{ isValid: true, resolvedIP: "203.0.113.10" }"
vllmProvider->>createPinnedFetch: createPinnedFetch("203.0.113.10")
createPinnedFetch-->>vllmProvider: pinnedFetch (IP-pinned undici agent)
vllmProvider->>OpenAI SDK: new OpenAI({ baseURL, apiKey, fetch: pinnedFetch })
else no azureEndpoint (env VLLM_BASE_URL used)
vllmProvider->>OpenAI SDK: new OpenAI({ baseURL: env.VLLM_BASE_URL, apiKey })
Note over vllmProvider,OpenAI SDK: No validation or pinning (trusted path)
end
OpenAI SDK->>OpenAI SDK: All HTTP calls use pinnedFetch (IP locked to 203.0.113.10)
OpenAI SDK-->>Client: Response
Reviews (2): Last reviewed commit: "fix(providers): pin vLLM provider endpoi..." | Re-trigger Greptile |
|
@greptile |
|
@cursor review |
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 2656dc5. Configure here.
|
@greptile review |
|
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 2656dc5. Configure here.
Summary
request.azureEndpoint) was used as the OpenAI-compatible base URL with no validation, letting an authenticated user point the backend at internal hosts / cloud-metadata (169.254.169.254, RFC-1918, etc.).validateUrlWithDNSguard and pin the connection to the resolved IP viacreatePinnedFetch, wired into the OpenAI client'sfetchoption — defeating private-IP access and DNS rebinding.VLLM_BASE_URLstays trusted/unvalidated; only the attacker-controllable per-request endpoint is validated + pinned.Type of Change
Testing
apps/sim/providers/vllm/index.test.ts— added SSRF coverage (no-endpoint env fallback, validate+pin, blocked-IP reject without issuing a request, unresolvable-IP reject). 15/15 pass.tsc --noEmit,biome check, andbun run check:api-validationall clean.Checklist