Skip to content

fix(providers): route image generation through shared transport#59729

Merged
vincentkoc merged 5 commits into
openclaw:mainfrom
vincentkoc:refactor/provider-transport-semantics
Apr 2, 2026
Merged

fix(providers): route image generation through shared transport#59729
vincentkoc merged 5 commits into
openclaw:mainfrom
vincentkoc:refactor/provider-transport-semantics

Conversation

@vincentkoc

Copy link
Copy Markdown
Member

Summary

  • route OpenAI, MiniMax, and fal image generation requests through the shared provider HTTP transport path
  • reuse shared base URL normalization, guarded private-network handling, and request header/default merging for image providers
  • add regression coverage for MiniMax image generation and keep the user-facing changelog aligned

Verification

  • pnpm test -- extensions/openai/index.test.ts extensions/minimax/image-generation-provider.test.ts extensions/fal/image-generation-provider.test.ts src/media-understanding/shared.test.ts
  • pnpm check
  • pnpm build

@vincentkoc vincentkoc self-assigned this Apr 2, 2026
@vincentkoc
vincentkoc marked this pull request as ready for review April 2, 2026 14:50
@greptile-apps

greptile-apps Bot commented Apr 2, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR routes image generation requests from the OpenAI, MiniMax, and fal providers through the shared resolveProviderHttpRequestConfig + postJsonRequest transport layer, bringing custom base URL normalization, SSRF-guarded private-network routing, and provider header merging into alignment with the rest of the provider HTTP stack. It also makes timeoutMs optional in postTranscriptionRequest / postJsonRequest and threads an auditContext parameter through the same functions.

Key changes:

  • OpenAI and MiniMax image providers replace manual fetch + AbortController timeout logic with postJsonRequest, and delegate URL normalization and header shaping to resolveProviderHttpRequestConfig.
  • fal image provider follows the same pattern; resolveFalNetworkPolicy is refactored to accept pre-resolved { baseUrl, allowPrivateNetwork } instead of re-reading config itself.
  • shared.ts makes timeoutMs optional (backward-compatible) and adds an auditContext option to both postTranscriptionRequest and postJsonRequest.
  • A new regression test file covers MiniMax image generation end-to-end.

The previously flagged issue (MiniMax discarding the baseUrl returned by resolveProviderHttpRequestConfig) has been addressed — resolvedBaseUrl is correctly destructured and used.

One issue found: the new auditContext parameter added to postJsonRequest and postTranscriptionRequest is silently dropped whenever allowPrivateNetwork is false and dispatcherPolicy is undefined (the common case), because the entire options object collapses to undefined under that condition. The guard condition needs to include auditContext as a third disjunct.

Confidence Score: 4/5

  • Safe to merge after fixing the auditContext guard condition in postJsonRequest and postTranscriptionRequest; no current callers are affected but the broken API contract should be corrected before the parameter is used.
  • The core routing change is correct and the previous critical bug (discarded baseUrl in MiniMax) has been fixed. The one remaining P1 is that the newly-introduced auditContext parameter in postJsonRequest/postTranscriptionRequest is silently dropped on the common non-private-network path due to a missing disjunct in the options guard. No current callers are impacted yet, but the broken API surface warrants a fix before the PR lands.
  • src/media-understanding/shared.ts — the auditContext guard condition in both postJsonRequest and postTranscriptionRequest
Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/media-understanding/shared.ts
Line: 141-147

Comment:
**`auditContext` silently dropped when `allowPrivateNetwork` and `dispatcherPolicy` are both falsy**

The `auditContext` parameter is added to the function signature but will be silently ignored whenever `allowPrivateNetwork` is `false` **and** `dispatcherPolicy` is `undefined` — which is the common (non-private-network) path. The ternary condition selects `undefined` as the entire options object in that case, so `auditContext` never reaches `fetchWithSsrFGuard`.

Any future caller that passes `auditContext` to a standard (non-private-network) `postJsonRequest` call will get no audit trail without any error or warning.

The same issue exists in the parallel block of `postTranscriptionRequest` (lines 112–118).

Fix both by including `auditContext` in the guard condition:

```suggestion
    params.allowPrivateNetwork || params.dispatcherPolicy || params.auditContext
      ? {
          ...(params.allowPrivateNetwork ? { ssrfPolicy: { allowPrivateNetwork: true } } : {}),
          ...(params.dispatcherPolicy ? { dispatcherPolicy: params.dispatcherPolicy } : {}),
          ...(params.auditContext ? { auditContext: params.auditContext } : {}),
        }
      : undefined,
```

The same one-line change is needed in `postTranscriptionRequest` at line 112.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (2): Last reviewed commit: "fix(providers): use normalized minimax i..." | Re-trigger Greptile

Comment thread extensions/minimax/image-generation-provider.ts Outdated
@vincentkoc

Copy link
Copy Markdown
Member Author

@greptileai review

@vincentkoc
vincentkoc merged commit 0ad2dbd into openclaw:main Apr 2, 2026
7 checks passed

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 726deee8ae

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@@ -137,14 +163,49 @@ export async function postJsonRequest(params: {
? {

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.

P2 Badge Pass auditContext even when no SSRF policy is set

postJsonRequest only forwards an options object when allowPrivateNetwork or dispatcherPolicy is truthy, so calls that provide only auditContext silently drop it. In that case fetchWithTimeoutGuarded never receives the context, and SSRF block logs fall back to the generic context instead of the caller-specific one. This affects observability/security triage for default-network requests and makes the new audit-context sanitization path ineffective for this helper shape.

Useful? React with 👍 / 👎.

@aisle-research-bot

aisle-research-bot Bot commented Apr 2, 2026

Copy link
Copy Markdown

🔒 Aisle Security Analysis

We found 1 potential security issue(s) in this PR:

# Severity Title
1 🔵 Low Terminal escape / log injection via untrusted HTTP error body in assertOkOrThrowHttpError
1. 🔵 Terminal escape / log injection via untrusted HTTP error body in assertOkOrThrowHttpError
Property Value
Severity Low
CWE CWE-117
Location src/media-understanding/shared.ts:228-235

Description

assertOkOrThrowHttpError incorporates up to 300 characters of the remote server's HTTP error response body into a thrown Error message.

  • Input: attacker-controlled HTTP response body from a provider endpoint (or a compromised/MITM'd endpoint)
  • Processing: readErrorResponse() collapses whitespace but does not remove non-whitespace control characters (e.g., ANSI escape \x1b)
  • Sink: resulting string is concatenated into the exception message, which is likely to be logged/printed by callers

This allows terminal escape injection (and potentially log manipulation in terminals that interpret ANSI sequences) when the error is surfaced in logs/CLI output.

Vulnerable code:

const detail = await readErrorResponse(res);
const suffix = detail ? `: ${detail}` : "";
throw new Error(`${label} (HTTP ${res.status})${suffix}`);

Recommendation

Sanitize provider error bodies before including them in error messages/logs.

At minimum, strip C0/C1 control characters (including ESC) from the decoded text, similar to sanitizeAuditContext().

Example fix:

function sanitizeErrorDetail(detail: string): string {
  return detail
    .replace(/\p{Cc}+/gu, " ")  // remove control chars (includes \x1b)
    .replace(/\s+/g, " ")
    .trim();
}// ...
const rawDetail = await readErrorResponse(res);
const detail = rawDetail ? sanitizeErrorDetail(rawDetail) : undefined;

Optionally, also consider only including error details when running in debug mode, or logging structured fields separately from the main message.


Analyzed PR: #59729 at commit 726deee

Last updated on: 2026-04-02T15:54:30Z

ngutman pushed a commit that referenced this pull request Apr 3, 2026
* fix(providers): route image generation through shared transport

* fix(providers): use normalized minimax image base url

* fix(providers): fail closed on image private routes

* fix(providers): bound shared HTTP fetches
steipete pushed a commit to duncanita/openclaw that referenced this pull request Apr 4, 2026
…claw#59729)

* fix(providers): route image generation through shared transport

* fix(providers): use normalized minimax image base url

* fix(providers): fail closed on image private routes

* fix(providers): bound shared HTTP fetches
lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
…claw#59729)

* fix(providers): route image generation through shared transport

* fix(providers): use normalized minimax image base url

* fix(providers): fail closed on image private routes

* fix(providers): bound shared HTTP fetches
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
…claw#59729)

* fix(providers): route image generation through shared transport

* fix(providers): use normalized minimax image base url

* fix(providers): fail closed on image private routes

* fix(providers): bound shared HTTP fetches
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
…claw#59729)

* fix(providers): route image generation through shared transport

* fix(providers): use normalized minimax image base url

* fix(providers): fail closed on image private routes

* fix(providers): bound shared HTTP fetches
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
…claw#59729)

* fix(providers): route image generation through shared transport

* fix(providers): use normalized minimax image base url

* fix(providers): fail closed on image private routes

* fix(providers): bound shared HTTP fetches
Nachx639 pushed a commit to Nachx639/clawdbot that referenced this pull request Jun 17, 2026
…claw#59729)

* fix(providers): route image generation through shared transport

* fix(providers): use normalized minimax image base url

* fix(providers): fail closed on image private routes

* fix(providers): bound shared HTTP fetches
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant