Skip to content

fix(lmstudio): bound model load success response body to prevent OOM#96042

Merged
sallyom merged 1 commit into
openclaw:mainfrom
Alix-007:fix/bound-lmstudio-model-fetch
Jun 24, 2026
Merged

fix(lmstudio): bound model load success response body to prevent OOM#96042
sallyom merged 1 commit into
openclaw:mainfrom
Alix-007:fix/bound-lmstudio-model-fetch

Conversation

@Alix-007

Copy link
Copy Markdown
Contributor

What Problem This Solves

ensureLmstudioModelLoaded in extensions/lmstudio/src/models.fetch.ts POSTs to LM Studio's /api/v1/models/load and reads the success response with an unbounded await response.json(). LM Studio is a self-hosted/local server endpoint that the agent reaches over HTTP; a misbehaving, misconfigured, or compromised server (or anything sitting on the configured baseUrl, including an SSRF-redirected target) can return a success body with no Content-Length and stream an arbitrarily large JSON payload.

Because response.json() buffers the entire body before parsing, that unbounded body is fully read into memory on the provider/discovery path before any size check runs. That is a memory-pressure / hang vector on a code path that runs during model discovery and before first inference — exactly the kind of unbounded external-response read the response-limit campaign has been closing across the codebase.

The sibling error body on the same endpoint was already bounded (readResponseTextLimited, 8 KiB) in a prior change. This PR closes the remaining unbounded read: the success JSON body.

Changes

  • extensions/lmstudio/src/models.fetch.ts: replace the unbounded await response.json() on the /api/v1/models/load success path with the shared, already-bounded readProviderJsonResponse<LmstudioLoadResponse>(...) helper (re-exported from openclaw/plugin-sdk/provider-http, same helper the /api/v1/models discovery path already uses). It reads the body through readResponseWithLimit under the 16 MiB provider-JSON cap, cancels the stream on overflow, and wraps malformed JSON with the caller's label. No new abstraction is introduced and the redundant local try/catch is removed.
  • extensions/lmstudio/src/models.test.ts: migrate the model fetch/load mocks from bare { ok, json } placeholders to real Response objects (the bounded readers require a real body stream), and add a regression test that streams an oversized (>16 MiB) success body and asserts the load path throws a bounded error and cancels the stream instead of buffering it all. Updates the malformed-load assertion to the helper's owned message.

Real behavior proof

  • Behavior addressed: unbounded buffering of the LM Studio /api/v1/models/load success JSON body; after the fix the read is capped at 16 MiB and the stream is cancelled on overflow.
  • Real environment tested: a local node:http server (real sockets, chunked transfer-encoding, no Content-Length) driving the real exported ensureLmstudioModelLoaded / readProviderJsonResponse via the global fetch (real Response body streams). Run with node --import tsx proof.mts.
  • Exact steps: (1) normal small { "status": "loaded" } response, end-to-end ensureLmstudioModelLoaded; (2) oversized 20 MiB chunked success body, end-to-end; (3) a body that hangs forever after a prefix, driving readProviderJsonResponse with an explicit small cap; (4) negative control reading the same 20 MiB body with the pre-fix unbounded await response.text().
  • Evidence after fix: (1) returns "proof-model" (still parses normally); (2) throws LM Studio model load: JSON response exceeds 16777216 bytes and the server observed only ~17.5 MiB sent before the socket closed (vs 20 MiB total) — the stream was cancelled mid-flight; (3) throws ... exceeds 2048 bytes and the server socket was closed (cancelled) instead of hanging; (4) the unbounded read consumed the full 20 MiB, confirming the cap is load-bearing.
  • Observed result: oversized/hanging bodies are stopped at the cap with a bounded error and the upstream stream is cancelled; well-formed small bodies still parse.
  • What was not tested: a real third-party LM Studio binary returning a pathological body (used a faithful local HTTP server instead); behavior under genuine OS memory exhaustion (the goal is to prevent reaching it).

Evidence

[proof] 本地 server 启动 http://127.0.0.1:36821
PASS  normal-small 端到端解析不破 — ensureLmstudioModelLoaded 返回 proof-model
PASS  oversized 抛 bounded error — error="LM Studio model load: JSON response exceeds 16777216 bytes"
PASS  oversized server 发送量 < 全量 20MiB(stream 被提前 cancel) — server 实发 17.50MiB (cap 16MiB,远小于 20MiB 全量)
PASS  hang body 到 cap 即抛 bounded error(不无限挂起) — error="LM Studio model load: JSON response exceeds 2048 bytes"
PASS  hang body cap 命中后 server 端 socket 被 cancel/close — server 实发 720922 bytes 后 socket close=true
PASS  negative control:无界 await .text() 全量读入 20MiB(证明 cap load-bearing) — 无界读到 20.00MiB 文本 / server 实发 20.00MiB(对照:bounded 仅读到 cap)
[proof] ALL PASS

Unit tests: node scripts/run-vitest.mjs extensions/lmstudio/src/models.test.ts --run → 24 passed (24), including the new bounds oversized model load success bodies. oxlint and tsgo (extensions source + test) clean on the changed files.

Label: security


This is the symmetric companion to the response-limit campaign (e.g. #95103 / #95108 / #95218): the LM Studio discovery /api/v1/models path and the /api/v1/models/load error body were already bounded; this PR finishes the set by bounding the /api/v1/models/load success body with the same shared helper and cap.

AI-assisted: implemented and proof-tested with AI assistance; reviewed by a human before submission.

The /api/v1/models/load success path read the response with an unbounded
await response.json(), so a misbehaving or compromised LM Studio server
could stream an arbitrarily large JSON body that is fully buffered into
memory before any size check. Read it through the shared byte-capped
readProviderJsonResponse helper instead (16 MiB provider-JSON cap, cancels
the stream on overflow, wraps malformed JSON), matching the discovery path
and the already-bounded error body.

Migrate the model fetch/load test mocks to real Response objects (the
bounded readers need a real body stream) and add a regression test that
streams an oversized success body and asserts a bounded error plus stream
cancellation.

Label: security
@Alix-007

Copy link
Copy Markdown
Contributor Author

@clawsweeper review

@clawsweeper

clawsweeper Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper

clawsweeper Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed June 23, 2026, 5:09 PM ET / 21:09 UTC.

Summary
The PR replaces LM Studio model-load success response.json() with the shared bounded provider JSON reader and updates tests to use real Response bodies plus an oversized-stream cancellation regression.

PR surface: Source +2, Tests +27. Total +29 across 2 files.

Reproducibility: yes. Source inspection shows current main still buffers the LM Studio model-load success body with response.json(), and the PR body provides a real-socket harness with a negative control for oversized stream behavior; I did not rerun it in this read-only review.

Review metrics: none identified.

Stored data model
Persistent data-model change detected: serialized state: extensions/lmstudio/src/models.test.ts. Confirm migration or upgrade compatibility proof before merge.

Merge readiness
Overall: 🦞 diamond lobster
Proof: 🦞 diamond lobster
Patch quality: 🦞 diamond lobster
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Next step before merge

  • [P2] No repair lane is needed; this contributor PR is focused, proof-backed, and has no actionable findings from this review.

Security
Cleared: Cleared: the diff only routes an existing external response body through an established byte-capped reader and adds tests, with no new dependencies, workflows, package scripts, permissions, or secret handling.

Review details

Best possible solution:

Land the narrow helper reuse after normal maintainer checks so LM Studio load success bodies use the same 16 MiB provider JSON cap as other provider JSON reads.

Do we have a high-confidence way to reproduce the issue?

Yes. Source inspection shows current main still buffers the LM Studio model-load success body with response.json(), and the PR body provides a real-socket harness with a negative control for oversized stream behavior; I did not rerun it in this read-only review.

Is this the best way to solve the issue?

Yes. Reusing the existing readProviderJsonResponse helper is the narrowest maintainable fix because the helper already owns the 16 MiB provider JSON cap, overflow error, malformed JSON label, and stream cancellation semantics.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 654544b6b7c4.

Label changes

Label changes:

  • add P2: This is a focused provider-plugin security/availability hardening for an OOM-capable response body path with limited blast radius.
  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes terminal output from a local real-socket HTTP harness showing normal parsing, oversized success-body rejection, hanging-body cancellation at a cap, and a pre-fix unbounded negative control.
  • add rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body includes terminal output from a local real-socket HTTP harness showing normal parsing, oversized success-body rejection, hanging-body cancellation at a cap, and a pre-fix unbounded negative control.

Label justifications:

  • P2: This is a focused provider-plugin security/availability hardening for an OOM-capable response body path with limited blast radius.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body includes terminal output from a local real-socket HTTP harness showing normal parsing, oversized success-body rejection, hanging-body cancellation at a cap, and a pre-fix unbounded negative control.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes terminal output from a local real-socket HTTP harness showing normal parsing, oversized success-body rejection, hanging-body cancellation at a cap, and a pre-fix unbounded negative control.
Evidence reviewed

PR surface:

Source +2, Tests +27. Total +29 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 8 6 +2
Tests 1 104 77 +27
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 112 83 +29

What I checked:

Likely related people:

  • vincentkoc: The current checkout history shows Vincent Koc introducing the present LM Studio model fetch/load file and tests, including the unbounded load success read that this PR changes. (role: recent area contributor; confidence: high; commits: fa263affd584; files: extensions/lmstudio/src/models.fetch.ts, extensions/lmstudio/src/models.test.ts)
  • Alix-007: Alix-007 authored the merged provider JSON response cap in fix(agents): bound provider JSON response reads #95218, which supplies the shared helper this PR now applies to LM Studio. (role: recent shared-helper contributor; confidence: high; commits: 2592f8a51a4e; files: src/agents/provider-http-errors.ts, src/agents/provider-http-errors.test.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P2 Normal backlog priority with limited blast radius. labels Jun 23, 2026
@sallyom sallyom self-assigned this Jun 24, 2026
@sallyom

sallyom commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

LGTM/merge-ready:

  • Local autoreview in the PR worktree against origin/main: clean, no accepted/actionable findings. I also reviewed upgrade/compatibility risk and found no blocking concerns: no config, persisted state, migration, plugin SDK, or LM Studio API compatibility blocker. The only user-visible behavior change is the intended bounded-success-body failure path/error text for malformed or oversized JSON.
  • CI/check rollup is green, and focused local proof passed: node scripts/run-vitest.mjs extensions/lmstudio/src/ models.test.ts --run.
  • Best-fix verdict: this is the right narrow fix because it reuses the existing shared bounded provider JSON reader instead of adding LM Studio-local parsing.

@sallyom
sallyom merged commit 7844b08 into openclaw:main Jun 24, 2026
132 of 139 checks passed
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jun 25, 2026
…penclaw#96042)

The /api/v1/models/load success path read the response with an unbounded
await response.json(), so a misbehaving or compromised LM Studio server
could stream an arbitrarily large JSON body that is fully buffered into
memory before any size check. Read it through the shared byte-capped
readProviderJsonResponse helper instead (16 MiB provider-JSON cap, cancels
the stream on overflow, wraps malformed JSON), matching the discovery path
and the already-bounded error body.

Migrate the model fetch/load test mocks to real Response objects (the
bounded readers need a real body stream) and add a regression test that
streams an oversized success body and asserts a bounded error plus stream
cancellation.

Label: security
vincentkoc pushed a commit to wangmiao0668000666/openclaw that referenced this pull request Jun 26, 2026
…sonResponse

Replace the local readGoogleChatJsonResponse and
readGoogleChatCertsResponse wrappers with the existing SDK helper
readProviderJsonResponse (from openclaw/plugin-sdk/provider-http) so the
Google Chat API JSON responses are bounded at 16 MiB, matching the
non-streaming cap already used by 15+ other extensions.

What changed:
- extensions/googlechat/src/api.ts: readGoogleChatJsonResponse now
  delegates to readProviderJsonResponse. Removed the local try/catch
  wrapper.
- extensions/googlechat/src/auth.ts: readGoogleChatCertsResponse now
  delegates to readProviderJsonResponse. Error message preserved.
  Removed the local try/catch wrapper.

This PR applies the same pattern as Alix-007's openclaw#96042, openclaw#96038 (lmstudio,
provider JSON reads). No SDK promotion needed — readProviderJsonResponse
is already available in openclaw/plugin-sdk/provider-http.
vincentkoc pushed a commit to wangmiao0668000666/openclaw that referenced this pull request Jun 26, 2026
…sonResponse

Replace the local readGoogleChatJsonResponse and
readGoogleChatCertsResponse wrappers with the existing SDK helper
readProviderJsonResponse (from openclaw/plugin-sdk/provider-http) so the
Google Chat API JSON responses are bounded at 16 MiB, matching the
non-streaming cap already used by 15+ other extensions.

What changed:
- extensions/googlechat/src/api.ts: readGoogleChatJsonResponse now
  delegates to readProviderJsonResponse. Removed the local try/catch
  wrapper.
- extensions/googlechat/src/auth.ts: readGoogleChatCertsResponse now
  delegates to readProviderJsonResponse. Error message preserved.
  Removed the local try/catch wrapper.

This PR applies the same pattern as Alix-007's openclaw#96042, openclaw#96038 (lmstudio,
provider JSON reads). No SDK promotion needed — readProviderJsonResponse
is already available in openclaw/plugin-sdk/provider-http.
vincentkoc pushed a commit to wangmiao0668000666/openclaw that referenced this pull request Jun 27, 2026
…sonResponse

Replace the local readGoogleChatJsonResponse and
readGoogleChatCertsResponse wrappers with the existing SDK helper
readProviderJsonResponse (from openclaw/plugin-sdk/provider-http) so the
Google Chat API JSON responses are bounded at 16 MiB, matching the
non-streaming cap already used by 15+ other extensions.

What changed:
- extensions/googlechat/src/api.ts: readGoogleChatJsonResponse now
  delegates to readProviderJsonResponse. Removed the local try/catch
  wrapper.
- extensions/googlechat/src/auth.ts: readGoogleChatCertsResponse now
  delegates to readProviderJsonResponse. Error message preserved.
  Removed the local try/catch wrapper.

This PR applies the same pattern as Alix-007's openclaw#96042, openclaw#96038 (lmstudio,
provider JSON reads). No SDK promotion needed — readProviderJsonResponse
is already available in openclaw/plugin-sdk/provider-http.
vincentkoc added a commit that referenced this pull request Jun 27, 2026
…sonResponse (#96772)

* fix(googlechat): replace unbounded response.json() with readProviderJsonResponse

Replace the local readGoogleChatJsonResponse and
readGoogleChatCertsResponse wrappers with the existing SDK helper
readProviderJsonResponse (from openclaw/plugin-sdk/provider-http) so the
Google Chat API JSON responses are bounded at 16 MiB, matching the
non-streaming cap already used by 15+ other extensions.

What changed:
- extensions/googlechat/src/api.ts: readGoogleChatJsonResponse now
  delegates to readProviderJsonResponse. Removed the local try/catch
  wrapper.
- extensions/googlechat/src/auth.ts: readGoogleChatCertsResponse now
  delegates to readProviderJsonResponse. Error message preserved.
  Removed the local try/catch wrapper.

This PR applies the same pattern as Alix-007's #96042, #96038 (lmstudio,
provider JSON reads). No SDK promotion needed — readProviderJsonResponse
is already available in openclaw/plugin-sdk/provider-http.

* fix(googlechat): add inline bounded-read regression tests

Co-Authored-By: Claude <[email protected]>

* fix(googlechat): remove unused variable flagged by oxlint

Co-Authored-By: Claude <[email protected]>

* fix(googlechat): bound api error body reads

---------

Co-authored-by: Claude <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>
wangmiao0668000666 added a commit to wangmiao0668000666/openclaw that referenced this pull request Jun 27, 2026
…sonResponse (openclaw#96772)

* fix(googlechat): replace unbounded response.json() with readProviderJsonResponse

Replace the local readGoogleChatJsonResponse and
readGoogleChatCertsResponse wrappers with the existing SDK helper
readProviderJsonResponse (from openclaw/plugin-sdk/provider-http) so the
Google Chat API JSON responses are bounded at 16 MiB, matching the
non-streaming cap already used by 15+ other extensions.

What changed:
- extensions/googlechat/src/api.ts: readGoogleChatJsonResponse now
  delegates to readProviderJsonResponse. Removed the local try/catch
  wrapper.
- extensions/googlechat/src/auth.ts: readGoogleChatCertsResponse now
  delegates to readProviderJsonResponse. Error message preserved.
  Removed the local try/catch wrapper.

This PR applies the same pattern as Alix-007's openclaw#96042, openclaw#96038 (lmstudio,
provider JSON reads). No SDK promotion needed — readProviderJsonResponse
is already available in openclaw/plugin-sdk/provider-http.

* fix(googlechat): add inline bounded-read regression tests

Co-Authored-By: Claude <[email protected]>

* fix(googlechat): remove unused variable flagged by oxlint

Co-Authored-By: Claude <[email protected]>

* fix(googlechat): bound api error body reads

---------

Co-authored-by: Claude <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jun 27, 2026
…sonResponse (openclaw#96772)

* fix(googlechat): replace unbounded response.json() with readProviderJsonResponse

Replace the local readGoogleChatJsonResponse and
readGoogleChatCertsResponse wrappers with the existing SDK helper
readProviderJsonResponse (from openclaw/plugin-sdk/provider-http) so the
Google Chat API JSON responses are bounded at 16 MiB, matching the
non-streaming cap already used by 15+ other extensions.

What changed:
- extensions/googlechat/src/api.ts: readGoogleChatJsonResponse now
  delegates to readProviderJsonResponse. Removed the local try/catch
  wrapper.
- extensions/googlechat/src/auth.ts: readGoogleChatCertsResponse now
  delegates to readProviderJsonResponse. Error message preserved.
  Removed the local try/catch wrapper.

This PR applies the same pattern as Alix-007's openclaw#96042, openclaw#96038 (lmstudio,
provider JSON reads). No SDK promotion needed — readProviderJsonResponse
is already available in openclaw/plugin-sdk/provider-http.

* fix(googlechat): add inline bounded-read regression tests

Co-Authored-By: Claude <[email protected]>

* fix(googlechat): remove unused variable flagged by oxlint

Co-Authored-By: Claude <[email protected]>

* fix(googlechat): bound api error body reads

---------

Co-authored-by: Claude <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>
xydigit-zt pushed a commit to xydigit-zt/xydigit-zt-openclaw that referenced this pull request Jun 28, 2026
…sonResponse (openclaw#96772)

* fix(googlechat): replace unbounded response.json() with readProviderJsonResponse

Replace the local readGoogleChatJsonResponse and
readGoogleChatCertsResponse wrappers with the existing SDK helper
readProviderJsonResponse (from openclaw/plugin-sdk/provider-http) so the
Google Chat API JSON responses are bounded at 16 MiB, matching the
non-streaming cap already used by 15+ other extensions.

What changed:
- extensions/googlechat/src/api.ts: readGoogleChatJsonResponse now
  delegates to readProviderJsonResponse. Removed the local try/catch
  wrapper.
- extensions/googlechat/src/auth.ts: readGoogleChatCertsResponse now
  delegates to readProviderJsonResponse. Error message preserved.
  Removed the local try/catch wrapper.

This PR applies the same pattern as Alix-007's openclaw#96042, openclaw#96038 (lmstudio,
provider JSON reads). No SDK promotion needed — readProviderJsonResponse
is already available in openclaw/plugin-sdk/provider-http.

* fix(googlechat): add inline bounded-read regression tests

Co-Authored-By: Claude <[email protected]>

* fix(googlechat): remove unused variable flagged by oxlint

Co-Authored-By: Claude <[email protected]>

* fix(googlechat): bound api error body reads

---------

Co-authored-by: Claude <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>
QiuYuang pushed a commit to QiuYuang/openclaw that referenced this pull request Jul 1, 2026
…penclaw#96042)

The /api/v1/models/load success path read the response with an unbounded
await response.json(), so a misbehaving or compromised LM Studio server
could stream an arbitrarily large JSON body that is fully buffered into
memory before any size check. Read it through the shared byte-capped
readProviderJsonResponse helper instead (16 MiB provider-JSON cap, cancels
the stream on overflow, wraps malformed JSON), matching the discovery path
and the already-bounded error body.

Migrate the model fetch/load test mocks to real Response objects (the
bounded readers need a real body stream) and add a regression test that
streams an oversized success body and asserts a bounded error plus stream
cancellation.

Label: security
QiuYuang pushed a commit to QiuYuang/openclaw that referenced this pull request Jul 1, 2026
…sonResponse (openclaw#96772)

* fix(googlechat): replace unbounded response.json() with readProviderJsonResponse

Replace the local readGoogleChatJsonResponse and
readGoogleChatCertsResponse wrappers with the existing SDK helper
readProviderJsonResponse (from openclaw/plugin-sdk/provider-http) so the
Google Chat API JSON responses are bounded at 16 MiB, matching the
non-streaming cap already used by 15+ other extensions.

What changed:
- extensions/googlechat/src/api.ts: readGoogleChatJsonResponse now
  delegates to readProviderJsonResponse. Removed the local try/catch
  wrapper.
- extensions/googlechat/src/auth.ts: readGoogleChatCertsResponse now
  delegates to readProviderJsonResponse. Error message preserved.
  Removed the local try/catch wrapper.

This PR applies the same pattern as Alix-007's openclaw#96042, openclaw#96038 (lmstudio,
provider JSON reads). No SDK promotion needed — readProviderJsonResponse
is already available in openclaw/plugin-sdk/provider-http.

* fix(googlechat): add inline bounded-read regression tests

Co-Authored-By: Claude <[email protected]>

* fix(googlechat): remove unused variable flagged by oxlint

Co-Authored-By: Claude <[email protected]>

* fix(googlechat): bound api error body reads

---------

Co-authored-by: Claude <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>
chenyangjun-xy pushed a commit to chenyangjun-xy/openclaw that referenced this pull request Jul 1, 2026
…sonResponse (openclaw#96772)

* fix(googlechat): replace unbounded response.json() with readProviderJsonResponse

Replace the local readGoogleChatJsonResponse and
readGoogleChatCertsResponse wrappers with the existing SDK helper
readProviderJsonResponse (from openclaw/plugin-sdk/provider-http) so the
Google Chat API JSON responses are bounded at 16 MiB, matching the
non-streaming cap already used by 15+ other extensions.

What changed:
- extensions/googlechat/src/api.ts: readGoogleChatJsonResponse now
  delegates to readProviderJsonResponse. Removed the local try/catch
  wrapper.
- extensions/googlechat/src/auth.ts: readGoogleChatCertsResponse now
  delegates to readProviderJsonResponse. Error message preserved.
  Removed the local try/catch wrapper.

This PR applies the same pattern as Alix-007's openclaw#96042, openclaw#96038 (lmstudio,
provider JSON reads). No SDK promotion needed — readProviderJsonResponse
is already available in openclaw/plugin-sdk/provider-http.

* fix(googlechat): add inline bounded-read regression tests

Co-Authored-By: Claude <[email protected]>

* fix(googlechat): remove unused variable flagged by oxlint

Co-Authored-By: Claude <[email protected]>

* fix(googlechat): bound api error body reads

---------

Co-authored-by: Claude <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>
chenyangjun-xy pushed a commit to chenyangjun-xy/openclaw that referenced this pull request Jul 3, 2026
…sonResponse (openclaw#96772)

* fix(googlechat): replace unbounded response.json() with readProviderJsonResponse

Replace the local readGoogleChatJsonResponse and
readGoogleChatCertsResponse wrappers with the existing SDK helper
readProviderJsonResponse (from openclaw/plugin-sdk/provider-http) so the
Google Chat API JSON responses are bounded at 16 MiB, matching the
non-streaming cap already used by 15+ other extensions.

What changed:
- extensions/googlechat/src/api.ts: readGoogleChatJsonResponse now
  delegates to readProviderJsonResponse. Removed the local try/catch
  wrapper.
- extensions/googlechat/src/auth.ts: readGoogleChatCertsResponse now
  delegates to readProviderJsonResponse. Error message preserved.
  Removed the local try/catch wrapper.

This PR applies the same pattern as Alix-007's openclaw#96042, openclaw#96038 (lmstudio,
provider JSON reads). No SDK promotion needed — readProviderJsonResponse
is already available in openclaw/plugin-sdk/provider-http.

* fix(googlechat): add inline bounded-read regression tests

Co-Authored-By: Claude <[email protected]>

* fix(googlechat): remove unused variable flagged by oxlint

Co-Authored-By: Claude <[email protected]>

* fix(googlechat): bound api error body reads

---------

Co-authored-by: Claude <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>
hugenshen added a commit to hugenshen/openclaw that referenced this pull request Jul 7, 2026
The fal music generation provider in extensions/fal/music-generation-provider.ts
parsed its HTTP success response with an unbounded await response.json(). A
hostile or buggy fal.ai endpoint — the base URL is user-configurable via
models.providers.fal.baseUrl (resolved by resolveFalHttpRequestConfig in
http-config.ts, defaulting to https://fal.run) — could stream an arbitrarily
large JSON body into memory before parsing, forcing the music generation handler
into OOM.

Route the read through the shared readProviderJsonResponse (from
openclaw/plugin-sdk/provider-http), which enforces the 16 MiB byte cap
(PROVIDER_JSON_RESPONSE_MAX_BYTES), cancels the stream on overflow, and wraps
malformed JSON with the caller label. The change is minimal — a single .json()
call replaced by readProviderJsonResponse<unknown> — and preserves the existing
downstream logic unchanged.

Update the test suite: replace fake { json: async () => ... } response stubs
with proper Response objects carrying JSON body streams via a new
jsonBodyResponse() helper, so the real readProviderJsonResponse implementation
actually exercises the byte-bounded reader under test. Preserve the real
readProviderJsonResponse in the provider-http mock (via importOriginal) so the
bounded reader streams and cancels oversized bodies. Add a focused regression
test: when the music generation stream exceeds the JSON byte cap (32 MiB body,
double the 16 MiB cap), generateMusic rejects with a
"fal-music-generation: JSON response exceeds" error and the reader cancels the
body mid-flight (ReadableStream.cancel fires, bytesPulled < 32 MiB). Existing
parse/HTTP-error cases keep passing.

Symmetric counterpart to the openclaw#96027/openclaw#96038/openclaw#96042/openclaw#96606/openclaw#96607 response-limit
campaign.
hugenshen added a commit to hugenshen/openclaw that referenced this pull request Jul 7, 2026
The fal music generation provider in extensions/fal/music-generation-provider.ts
parsed its HTTP success response with an unbounded await response.json(). A
hostile or buggy fal.ai endpoint — the base URL is user-configurable via
models.providers.fal.baseUrl (resolved by resolveFalHttpRequestConfig in
http-config.ts, defaulting to https://fal.run) — could stream an arbitrarily
large JSON body into memory before parsing, forcing the music generation handler
into OOM.

Route the read through the shared readProviderJsonResponse (from
openclaw/plugin-sdk/provider-http), which enforces the 16 MiB byte cap
(PROVIDER_JSON_RESPONSE_MAX_BYTES), cancels the stream on overflow, and wraps
malformed JSON with the caller label. The change is minimal — a single .json()
call replaced by readProviderJsonResponse<unknown> — and preserves the existing
downstream logic unchanged.

Update the test suite: replace fake { json: async () => ... } response stubs
with proper Response objects carrying JSON body streams via a new
jsonBodyResponse() helper, so the real readProviderJsonResponse implementation
actually exercises the byte-bounded reader under test. Preserve the real
readProviderJsonResponse in the provider-http mock (via importOriginal) so the
bounded reader streams and cancels oversized bodies. Add a focused regression
test: when the music generation stream exceeds the JSON byte cap (32 MiB body,
double the 16 MiB cap), generateMusic rejects with a
"fal-music-generation: JSON response exceeds" error and the reader cancels the
body mid-flight (ReadableStream.cancel fires, bytesPulled < 32 MiB). Existing
parse/HTTP-error cases keep passing.

Symmetric counterpart to the openclaw#96027/openclaw#96038/openclaw#96042/openclaw#96606/openclaw#96607 response-limit
campaign.
wheakerd pushed a commit to wheakerd/clawdbot that referenced this pull request Jul 15, 2026
…sonResponse (openclaw#96772)

* fix(googlechat): replace unbounded response.json() with readProviderJsonResponse

Replace the local readGoogleChatJsonResponse and
readGoogleChatCertsResponse wrappers with the existing SDK helper
readProviderJsonResponse (from openclaw/plugin-sdk/provider-http) so the
Google Chat API JSON responses are bounded at 16 MiB, matching the
non-streaming cap already used by 15+ other extensions.

What changed:
- extensions/googlechat/src/api.ts: readGoogleChatJsonResponse now
  delegates to readProviderJsonResponse. Removed the local try/catch
  wrapper.
- extensions/googlechat/src/auth.ts: readGoogleChatCertsResponse now
  delegates to readProviderJsonResponse. Error message preserved.
  Removed the local try/catch wrapper.

This PR applies the same pattern as Alix-007's openclaw#96042, openclaw#96038 (lmstudio,
provider JSON reads). No SDK promotion needed — readProviderJsonResponse
is already available in openclaw/plugin-sdk/provider-http.

* fix(googlechat): add inline bounded-read regression tests

Co-Authored-By: Claude <[email protected]>

* fix(googlechat): remove unused variable flagged by oxlint

Co-Authored-By: Claude <[email protected]>

* fix(googlechat): bound api error body reads

---------

Co-authored-by: Claude <[email protected]>
Co-authored-by: Vincent Koc <[email protected]>
(cherry picked from commit 4f3d81b)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

extensions: lmstudio P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. size: S status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants