Skip to content

fix(providers): repair qwen-web validation + stop mislabeling benign redirects as SSRF (#3288, #3758) - #3767

Merged
diegosouzapw merged 1 commit into
release/v3.8.24from
fix/3288-qwen-web-validate-ssrf
Jun 13, 2026
Merged

diegosouzapw merged 1 commit into
release/v3.8.24from
fix/3288-qwen-web-validate-ssrf

Conversation

@diegosouzapw

Copy link
Copy Markdown
Collaborator

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 modelsUrl in its registry entry, addModelsSuffix derived a probe URL of https://chat.qwen.ai/api/v2/models — a non-existent path that answers with a 307 redirect. The outbound guard blocked the (unfollowed) redirect → 503, and toValidationErrorResult flagged any 503 as securityBlocked, 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

  1. validateQwenWebProvider specialty validator — probes the real session endpoint GET /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 plain fetch like the other web-cookie validators, so it never hits the addModelsSuffix/redirect path. 401/403 → invalid session; HTML/504 → WAF re-login hint; 200 → valid.
  2. isSecurityBlockError hardening — a blocked redirect is only securityBlocked when its location resolves 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_URL behavior 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):

  • qwen-web probes /api/v2/user (NOT /api/v2/models), sends Bearer+cookie+source:web, valid on 200.
  • 401 → invalid, no securityBlocked.
  • HTML/WAF → re-login hint.
  • 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.

Note: the live WAF/cookie success (does a real pasted cookie pass Alibaba's WAF on /api/v2/user) is upstream-dependent and could not be exercised offline — the endpoint choice follows the Chat2API reference. The architectural fix (correct endpoint + no SSRF mislabel) is fully unit-tested.

…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
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@diegosouzapw
diegosouzapw merged commit 0e07eb0 into release/v3.8.24 Jun 13, 2026
2 checks passed

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

To support proxy configurations and the outbound URL guard, we should pass isLocal to validateQwenWebProvider so it can be forwarded to fetchWithProxyFallback.

async function validateQwenWebProvider({ apiKey, isLocal }: any) {

if (token) headers["Authorization"] = `Bearer ${token}`;
if (cookieHeader) headers["Cookie"] = cookieHeader;

const resp = await fetch("https://chat.qwen.ai/api/v2/user", { headers });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-high high

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
    );

diegosouzapw added a commit that referenced this pull request Jun 13, 2026
… 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.
@diegosouzapw
diegosouzapw deleted the fix/3288-qwen-web-validate-ssrf branch June 13, 2026 14:18
tkgo11 pushed a commit to tkgo11/OmniRoute that referenced this pull request Sep 23, 2026
…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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant