Repository navigation
fix(providers): repair qwen-web validation + stop mislabeling benign redirects as SSRF (#3288, #3758) - #3767
Conversation
…redirects as SSRF (#3288, #3758) qwen-web had no specialty validator, so validation fell through to the generic OpenAI-compatible path which probed a bogus /api/v2/models URL. That answers with a 307 redirect, the outbound guard blocked it, and the route surfaced it as provider.validation.ssrf_blocked. - Add a qwen-web specialty validator that probes the real session endpoint (GET /api/v2/user, like Chat2API) with the executor's anti-bot headers + cookie-jar replay, bypassing the addModelsSuffix path. - Harden toValidationErrorResult: a blocked redirect is only a security block when its target is a private/internal host; a benign 3xx to a public host is no longer mislabeled as SSRF (affected all web-cookie providers). Refs #3288 #3758
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
There was a problem hiding this comment.
Code Review
This pull request introduces a specialty validator for the qwen-web provider to resolve connection validation failures caused by redirects being mislabeled as SSRF blocks. It also hardens error handling with a new isSecurityBlockError helper to ensure only genuine private-host redirects or guard blocks are flagged as security events. The review feedback correctly points out that using the global fetch directly in the new validator bypasses the outbound URL guard and proxy configurations, and recommends passing isLocal and using fetchWithProxyFallback instead.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| // (`GET /api/v2/user`, the same one Chat2API uses), mirroring the executor's anti-bot | ||
| // headers + cookie-jar replay. It uses plain fetch (like the other web-cookie | ||
| // validators) so it never hits the addModelsSuffix/redirect path. | ||
| async function validateQwenWebProvider({ apiKey }: any) { |
| if (token) headers["Authorization"] = `Bearer ${token}`; | ||
| if (cookieHeader) headers["Cookie"] = cookieHeader; | ||
|
|
||
| const resp = await fetch("https://chat.qwen.ai/api/v2/user", { headers }); |
There was a problem hiding this comment.
Using the global fetch directly bypasses the outbound URL guard (outboundUrlGuard) and proxy configurations. This introduces a potential security risk (such as SSRF via redirects or DNS rebinding if the target domain is compromised or spoofed) and can cause validation to fail in environments that require a proxy for outbound connections.
Additionally, by using fetchWithProxyFallback, any blocked redirects will correctly throw a SafeOutboundFetchError, which allows the newly hardened isSecurityBlockError logic to be properly exercised and tested for this provider.
const resp = await fetchWithProxyFallback(
"https://chat.qwen.ai/api/v2/user",
{ headers },
SAFE_OUTBOUND_FETCH_PRESETS.validationWrite,
isLocal
);… v3.8.24 merges These 5 files exceeded the frozen baseline solely because of already-merged, already-reviewed v3.8.24 PRs that landed after this branch froze its baseline: - src/lib/providers/validation.ts 4209→4302 (#3767 qwen-web fix) - src/shared/components/RequestLoggerV2.tsx 1232→1276 (#3760 logs light-mode) - open-sse/executors/antigravity.ts 1553→1572 (#3766 antigravity refresh) - open-sse/executors/base.ts 1199→1205 (#3756 xhigh effort) - open-sse/translator/response/openai-responses.ts 873→878 (#3762 tool-call integrity) None are touched by this branch; the bump reflects current release reality.
…redirects as SSRF (cheaper-inference#3288, cheaper-inference#3758) (cheaper-inference#3767) qwen-web had no specialty validator, so validation fell through to the generic OpenAI-compatible path which probed a bogus /api/v2/models URL. That answers with a 307 redirect, the outbound guard blocked it, and the route surfaced it as provider.validation.ssrf_blocked. - Add a qwen-web specialty validator that probes the real session endpoint (GET /api/v2/user, like Chat2API) with the executor's anti-bot headers + cookie-jar replay, bypassing the addModelsSuffix path. - Harden toValidationErrorResult: a blocked redirect is only a security block when its target is a private/internal host; a benign 3xx to a public host is no longer mislabeled as SSRF (affected all web-cookie providers). Refs cheaper-inference#3288 cheaper-inference#3758
Refs #3288, #3758
Problem
Validating a qwen-web (chat.qwen.ai) connection failed with the audit error
provider.validation.ssrf_blocked(Redirect blocked for GET https://chat.qwen.ai/api/v2/models (307)).Root cause: qwen-web has no specialty validator, so it fell through to the generic OpenAI-compatible validator. With no
modelsUrlin its registry entry,addModelsSuffixderived a probe URL ofhttps://chat.qwen.ai/api/v2/models— a non-existent path that answers with a 307 redirect. The outbound guard blocked the (unfollowed) redirect → 503, andtoValidationErrorResultflagged any 503 assecurityBlocked, so the route emitted an SSRF audit event. (The qwen-web executor itself is already on the v2 API + cookie-jar replay from #3723 — only validation was broken.)Fix
validateQwenWebProviderspecialty validator — probes the real session endpointGET /api/v2/user(the same one Chat2API uses), with the executor's anti-bot headers (source: web,bx-v, UA) +Authorization: Bearer+ cookie-jar. Uses plainfetchlike the other web-cookie validators, so it never hits theaddModelsSuffix/redirect path. 401/403 → invalid session; HTML/504 → WAF re-login hint; 200 → valid.isSecurityBlockErrorhardening — a blocked redirect is onlysecurityBlockedwhen itslocationresolves to a private/internal host (isPrivateHost). A benign 3xx to a public host (qwen's 307) is no longer mislabeled as an SSRF attempt.URL_GUARD_BLOCKED/INVALID_URLbehavior is unchanged. This fixes the class for every web-cookie provider.Validation (Hard Rule #18 — TDD)
tests/unit/provider-validation-specialty.test.ts— 6 new tests (RED→GREEN verified):/api/v2/user(NOT/api/v2/models), sends Bearer+cookie+source:web, valid on 200.securityBlocked.isSecurityBlockError: public-host redirect → false; private-host (169.254.169.254) → true; URL_GUARD_BLOCKED → true.Full file 105/105 pass, typecheck:core clean, eslint 0 errors.