Skip to content

fix(chutes-oauth): bound Chutes OAuth JSON response reads#96249

Closed
wangmiao0668000666 wants to merge 4 commits into
openclaw:mainfrom
wangmiao0668000666:fix/chutes-oauth-bounded-json-response
Closed

fix(chutes-oauth): bound Chutes OAuth JSON response reads#96249
wangmiao0668000666 wants to merge 4 commits into
openclaw:mainfrom
wangmiao0668000666:fix/chutes-oauth-bounded-json-response

Conversation

@wangmiao0668000666

@wangmiao0668000666 wangmiao0668000666 commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

The Chutes OAuth PKCE flow has five provider-controlled success-body reads
across two files, none of which cap the byte read. A misbehaving Chutes
endpoint or proxy that streams an unbounded body on the active loginChutes
path can pull unlimited bytes into the agent process and trigger OOM
before the JSON.parse runs.

File Sites Active in product?
src/agents/chutes-oauth.ts 3 (token exchange, refresh, userinfo) Deprecated core helper — kept for backward compat
extensions/chutes/oauth.ts 2 (token exchange, userinfo) Active bundled plugin — entered via openclaw onboard --auth-choice chutes

This PR routes all five reads through the shared
readProviderJsonResponse helper from openclaw/plugin-sdk/provider-http
(16 MiB cap, label-prefixed overflow error, cancels the stream on overflow).
This closes the chutes-oauth half of the unbounded-response.json() family
that #96144 called out as "Out of scope".

Why This Change Was Made

  • The active bundled plugin path was identified as the security-sensitive
    gap after ClawSweeper P1 finding on the original PR scope: fixing only
    the deprecated core helper left extensions/chutes/oauth.ts able to
    buffer an oversized provider/proxy response during the documented
    openclaw onboard --auth-choice chutes flow.
  • Bounded-read helper is generic, owned by plugin-sdk/provider-http, and
    already proven on six upstream Alix-007 bound-stream PRs plus the
    image-generation / video-generation / dashscope sites.
  • Single helper, same labels, consistent overflow error shape across both
    files. The plugin error labels ("Chutes token exchange", "Chutes userinfo") match the existing core helper labels so maintainer
    dashboards stay uniform.
  • Low review surface: 2 source files, 2 test files, 2 repro scripts.
    No public API change, no schema change, no migration.

Changes

  • src/agents/chutes-oauth.ts+6/-5 — import
    readProviderJsonResponse from ./provider-http-errors.js; replace
    three (await response.json()) as Type calls with
    await readProviderJsonResponse<Type>(response, "<Chutes label>").
  • extensions/chutes/oauth.ts+6/-3 — import
    readProviderJsonResponse from openclaw/plugin-sdk/provider-http
    (boundary-respecting — extensions cannot reach into src/agents/**);
    replace the two active plugin success-body reads with the same helper.
  • src/agents/chutes-oauth.flow.test.ts+111/-0 — bounded-reader
    regression tests against the deprecated core helper.
  • extensions/chutes/oauth.test.ts+129/-0 — bounded-reader
    regression tests against the active plugin path (hostile token exchange
    body + hostile userinfo body, both verified to cancel and throw the
    canonical overflow error before the runtime buffers the full payload).
  • scripts/repro/issue-chutes-oauth-bounded-read.mjs — new — standalone
    repro script that drives the core readProviderJsonResponse directly.
  • scripts/repro/issue-chutes-plugin-oauth-bounded-read.mjs — new —
    standalone repro script that drives the plugin loginChutes end-to-end
    with stubbed fetchFn (validates the active path, not just the helper).

Evidence

  • node scripts/run-vitest.mjs extensions/chutes/oauth.test.ts
    4/4 plugin tests passed (2 existing + 2 new bounded-reader regressions)
  • node scripts/run-vitest.mjs src/agents/chutes-oauth.flow.test.ts
    9/9 core tests passed (6 existing + 3 new bounded-reader regressions)
  • npx oxlint --import-plugin --config .oxlintrc.json extensions/chutes/oauth.ts extensions/chutes/oauth.test.ts
    — exit 0
  • pnpm exec tsx scripts/repro/issue-chutes-oauth-bounded-read.mjs
    exit 0 (5 assertions: valid + 3 hostile + negative control)
  • pnpm exec tsx scripts/repro/issue-chutes-plugin-oauth-bounded-read.mjs
    exit 0 (3 assertions: hostile token exchange + hostile userinfo +
    negative control)

Sample failure when the body exceeds the 16 MiB cap (matches the helper
behavior verified in #96144):

Error: Chutes token exchange: JSON response exceeds 16777216 bytes
Error: Chutes userinfo: JSON response exceeds 16777216 bytes

Real behavior proof

The two repro scripts drive the production code paths with no vitest mock:

  • scripts/repro/issue-chutes-oauth-bounded-read.mjs exercises the
    deprecated core helper's three labels directly.
  • scripts/repro/issue-chutes-plugin-oauth-bounded-read.mjs exercises
    loginChutes end-to-end with a stubbed fetchFn, proving the active
    bundled plugin path cancels and throws the canonical overflow error
    before the runtime buffers the full body.
$ pnpm exec tsx scripts/repro/issue-chutes-plugin-oauth-bounded-read.mjs
=== Reproduction for chutes plugin OAuth bounded JSON response cap ===
PROVIDER_JSON_RESPONSE_MAX_BYTES = 16777216 bytes
PASS  hostile token exchange body: rejected with "Chutes token exchange: JSON response exceeds 16777216 bytes"
PASS  hostile userinfo body: rejected with "Chutes userinfo: JSON response exceeds 16777216 bytes"
PASS  negative control: raw response.json() failed with "SyntaxError" (no bounded-reader wrapping)
=== All chutes plugin OAuth repro assertions passed ===

The negative control proves the bounded read is the source of the cap:
raw response.json() on the same 64 MiB body buffers the full payload
and only fails on JSON parse, not on size.

Out of scope (separate follow-ups)

  • extensions/*/src/** files with the same response.json() pattern
    (Alix-007 family of unbounded reads). Some are already capped
    (msteams/src/graph.ts, google-meet) and the rest are queued for
    per-extension follow-up PRs.
  • The assertOkOrThrowHttpError / readResponseTextLimited calls in the
    same files cover the HTTP-error path (8 KiB cap), not the oversize-body
    path (16 MiB cap), and the bounded reader runs after the HTTP status
    check.

Sibling coverage note

This PR addresses the ClawSweeper P1 finding that the original PR scope
missed the active bundled plugin path. Both files now route through the
same readProviderJsonResponse helper with consistent label prefixes,
so any future Chutes success-body reads added to either file should
follow the same pattern.

Routes the three Chutes OAuth response.json() sites in src/agents/chutes-oauth.ts
(fetchChutesUserInfo:118, exchangeChutesCodeForTokens:158, refreshChutesTokens:229)
through the existing readProviderJsonResponse helper, capping reads at 16 MiB
via PROVIDER_JSON_RESPONSE_MAX_BYTES.

Closes the chutes-oauth half of the unbounded-response.json() family called
out as "Out of scope" in PR openclaw#96144 (sibling to openclaw#95926, openclaw#96036, openclaw#96136).

A misbehaving Chutes endpoint that streams an unbounded body is now rejected
with the canonical `<label>: JSON response exceeds 16777216 bytes` overflow
error before the runtime buffers the full body.

- src/agents/chutes-oauth.ts: +6/-5 (1 import + 3 sites)
- src/agents/chutes-oauth.flow.test.ts: +111/-0 (3 new bounded-reader tests)
- scripts/repro/issue-chutes-oauth-bounded-read.mjs: standalone repro
  driving readProviderJsonResponse with valid + hostile + negative control
@clawsweeper

clawsweeper Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed June 24, 2026, 11:39 AM ET / 15:39 UTC.

Summary
The PR replaces five Chutes OAuth success-body response.json() reads in the core helper and bundled Chutes plugin with readProviderJsonResponse, then adds regression tests and repro scripts.

PR surface: Source +4, Tests +248, Other +530. Total +782 across 6 files.

Reproducibility: yes. Current main has five raw Chutes OAuth success-body response.json() reads, and the PR includes terminal proof for oversized streamed responses on the plugin login path; I did not execute commands in this read-only review.

Review metrics: 2 noteworthy metrics.

  • Chutes success-body reads capped: 5 changed to 16 MiB cap. This is the behavior-changing auth-provider surface that maintainers need to accept before merge.
  • Core HTTP-error reads unchanged: 2 raw response.text() reads unchanged. These deprecated core non-OK paths are not covered by the success-body fix and should remain explicit follow-up work.

Root-cause cluster
Relationship: canonical
Canonical: #96249
Summary: This PR is the canonical open Chutes OAuth bounded success-body fix; a smaller Chutes-only duplicate was closed, while the other related PRs cover adjacent provider response-limit surfaces.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

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

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

Rank-up moves:

  • Clarify in the PR body or merge note that the deprecated core non-OK response.text() paths remain out of scope.
  • Maintainers should decide whether the provided loopback proof is enough or whether they want a redacted live Chutes happy-path smoke before landing.

Risk before merge

  • [P1] Chutes OAuth token/userinfo success bodies larger than the shared 16 MiB provider JSON cap will now fail closed; that is the intended hardening shape, but maintainers should explicitly accept the auth-provider cap before merge.
  • [P1] The PR body should not imply that the deprecated core helper's non-OK token exchange and refresh response.text() reads are bounded; those two error-body reads remain separate follow-up work.

Maintainer options:

  1. Accept the Chutes OAuth cap (recommended)
    Maintainers can accept the 16 MiB fail-closed cap for token and userinfo success responses and land after exact-head checks and mergeability pass.
  2. Ask for live Chutes smoke
    If maintainers want stronger provider-specific assurance, request a redacted live Chutes OAuth happy-path smoke before merge.
  3. Pause for cap policy
    If the shared provider JSON cap is not acceptable for OAuth responses, pause this PR and choose a Chutes-specific cap or alternate helper policy first.

Next step before merge

  • No automated repair is needed; the remaining action is maintainer review of the auth-provider cap, PR-body wording, and exact-head gates.

Security
Cleared: No new supply-chain or secret-handling concern was found; the diff reduces a provider-controlled unbounded JSON read surface.

Review details

Best possible solution:

Land the shared-helper success-body cap after maintainer acceptance of the 16 MiB Chutes OAuth response limit and exact-head gates, while tracking core non-OK text hardening and other provider response.json() sites separately.

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

Yes. Current main has five raw Chutes OAuth success-body response.json() reads, and the PR includes terminal proof for oversized streamed responses on the plugin login path; I did not execute commands in this read-only review.

Is this the best way to solve the issue?

Yes. Reusing readProviderJsonResponse is the narrow existing helper and keeps the bundled plugin on the public SDK facade while covering both active plugin and deprecated core success-body paths.

AGENTS.md: found and applied where relevant.

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

Label changes

Label changes:

  • add merge-risk: 🚨 auth-provider: The diff changes Chutes OAuth success-response handling to fail closed above the shared provider JSON cap, which can affect auth/token setup behavior.

Label justifications:

  • P2: This is a normal-priority Chutes OAuth availability/security hardening fix with a focused provider-auth blast radius.
  • merge-risk: 🚨 auth-provider: The diff changes Chutes OAuth success-response handling to fail closed above the shared provider JSON cap, which can affect auth/token setup behavior.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body and latest comment include terminal output from repro scripts that drive production Chutes helper/plugin paths against oversized streamed responses with abort statistics and happy-path coverage.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body and latest comment include terminal output from repro scripts that drive production Chutes helper/plugin paths against oversized streamed responses with abort statistics and happy-path coverage.
Evidence reviewed

PR surface:

Source +4, Tests +248, Other +530. Total +782 across 6 files.

View PR surface stats
Area Files Added Removed Net
Source 2 13 9 +4
Tests 2 249 1 +248
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 2 530 0 +530
Total 6 792 10 +782

What I checked:

Likely related people:

  • steipete: Introduced the bundled Chutes extension and has the largest shortlog count across the Chutes OAuth/plugin files, including prior OAuth hardening work. (role: feature owner and adjacent contributor; confidence: high; commits: a724bbce1a63, f566e6451f7e; files: extensions/chutes/oauth.ts, extensions/chutes/index.ts, src/agents/chutes-oauth.ts)
  • Friederike Seiler: Added the original core Chutes OAuth implementation and early build/test follow-ups for that flow. (role: introduced behavior; confidence: medium; commits: 4efb5cc18efa, 0efcfc0864fc; files: src/agents/chutes-oauth.ts, src/commands/chutes-oauth.ts)
  • vincentkoc: Recent history includes provider auth login seam work and Chutes docs/release work around the pluginized auth path. (role: adjacent owner; confidence: medium; commits: d8a1ad0f0d5c, 4081603ad5bf; files: src/plugin-sdk/provider-auth-login.ts, docs/providers/chutes.md)
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: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. P2 Normal backlog priority with limited blast radius. labels Jun 24, 2026
…nclaw#96249)

Add an explicit `{ totalBytes: number; chunkSize?: number }` parameter
type to the test helper, addressing the ClawSweeper P2 finding that
`check-test-types` failed with TS7031 at line 252 because
`{ totalBytes, chunkSize = ... }` destructured an untyped binding.

The helper body now reads the destructured values from a typed `opts`
parameter, which keeps the existing default-value semantics intact
(`chunkSize` still defaults to 1 MiB) while satisfying the strict
TypeScript gate.

Verified:
- node scripts/run-vitest.mjs src/agents/chutes-oauth.flow.test.ts: 9/9 passed
- node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.test.src.json: exit 0
- pnpm exec tsx scripts/repro/issue-chutes-oauth-bounded-read.mjs: 5/5 PASS
- npx oxlint --import-plugin --config .oxlintrc.json on the changed file: exit 0

No source change; no behavioral change; runtime call sites untouched.
@wangmiao0668000666

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper — addressing the P2 finding on PR #96249 (commit 61346725d):

  • [P2] "Type the streaming response helper parameter — src/agents/chutes-oauth.flow.test.ts:252" — addressed by:
    • Added explicit opts: { totalBytes: number; chunkSize?: number } parameter type to createStreamingJsonResponse
    • Destructured totalBytes and chunkSize from the typed opts so the existing chunkSize = 1024 * 1024 default-value semantics remain intact
    • Net change: +2 / -1 in src/agents/chutes-oauth.flow.test.ts only — no source change, no behavioral change, runtime call sites untouched

Verification (all green on commit 61346725d7):

  • node scripts/run-vitest.mjs src/agents/chutes-oauth.flow.test.ts — 9/9 passed
  • node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.test.src.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/test-src.tsbuildinfo — exit 0 (TS7031 no longer fires)
  • pnpm exec tsx scripts/repro/issue-chutes-oauth-bounded-read.mjs — 5/5 PASS
  • npx oxlint --import-plugin --config .oxlintrc.json src/agents/chutes-oauth.flow.test.ts — exit 0

The merge-blocker P2 (test typecheck fail) should now be cleared. PR body unchanged.

@clawsweeper

clawsweeper Bot commented Jun 24, 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 added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Jun 24, 2026
@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jun 24, 2026
@openclaw-barnacle openclaw-barnacle Bot added triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. and removed triage: needs-pr-context Candidate: external PR body lacks required problem context or evidence. labels Jun 24, 2026
@wangmiao0668000666

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Addressing the P1 sibling-coverage finding on PR #96249 (commit 54aeeffb98):

What changed

  • Added extensions/chutes/oauth.ts to the same readProviderJsonResponse swap, using the
    openclaw/plugin-sdk/provider-http facade (boundary-respecting — extensions cannot import
    src/agents/** per the extensions/CLAUDE.md boundary rule).
  • Two active plugin success-body reads now bounded:
    • fetchChutesUserInfo (userinfo response)
    • exchangeChutesCodeForTokens (token exchange response)
  • Same 16 MiB cap, same label-prefixed overflow error format ("Chutes token exchange: JSON response exceeds 16777216 bytes", "Chutes userinfo: JSON response exceeds 16777216 bytes").
  • Added 2 regression tests in extensions/chutes/oauth.test.ts covering both hostile plugin paths.
  • Added 1 standalone repro script scripts/repro/issue-chutes-plugin-oauth-bounded-read.mjs
    that drives loginChutes end-to-end with stubbed fetchFn (proves the active plugin path
    cancels and throws before the runtime buffers the full body, not just the helper).

Net PR surface

  • Source: +12/-8 across src/agents/chutes-oauth.ts + extensions/chutes/oauth.ts
  • Tests: +129/-0 in extensions/choutes/oauth.test.ts (existing core tests unchanged)
  • Repro: 1 new script + the existing one
  • Total: +141/-8 across 4 files

Verification (all green on commit 54aeeffb98)

  • node scripts/run-vitest.mjs extensions/chutes/oauth.test.ts — 4/4 passed
  • node scripts/run-vitest.mjs src/agents/chutes-oauth.flow.test.ts — 9/9 passed
  • pnpm exec tsx scripts/repro/issue-chutes-plugin-oauth-bounded-read.mjs — 3/3 PASS
  • pnpm exec tsx scripts/repro/issue-chutes-oauth-bounded-read.mjs — 5/5 PASS
  • npx oxlint --import-plugin --config .oxlintrc.json extensions/chutes/oauth.ts extensions/chutes/oauth.test.ts — exit 0
  • node scripts/run-tsgo.mjs — exit 0

P1 sibling coverage — both files now route through the same helper with consistent label
prefixes. PR body updated to document the sibling-coverage rationale and the active-vs-deprecated
path distinction.

@clawsweeper

clawsweeper Bot commented Jun 24, 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 added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Jun 24, 2026
@wangmiao0668000666

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Upgrading PR #96249 proof to match the 🦞-grade pattern from the recently-merged Alix-007 PR family
(#96027 / #96035 / #96038 / #96042). Re-review on commit 1bdb44d7a8e1ed0410d9566f81364f22c37a93d1.

What changed in the repro

The previous repro used a factory createStreamingJsonResponse to simulate streaming bodies, which
ClawSweeper could rightfully treat as not-load-bearing. The upgraded repro:

  1. Spins up a real node:http server bound to 127.0.0.1 that streams a Content-Length-less
    64 MiB body in 1 MiB chunks (4× the 16 MiB cap), recording bytesSent / aborted stats per
    request.
  2. Drives the production loginChutes end-to-end against that real server (using a stub
    fetchFn that routes the chutes.ai URLs to the local server).
  3. Observes the bounded reader cancelling the stream — server-side bytesSent ≪ 64 MiB,
    aborted=true. Measured: token-exchange cancels at ~19 MiB, userinfo at ~19 MiB, cap-trace
    variant at ~18 MiB.
  4. Quantifies the cap is load-bearing with a small-body negative control: a raw unbounded read
    against an 8 MiB streaming body succeeds end-to-end (67 MiB tested, all bytes flow through), which
    combined with the bounded-reader overflow on 64 MiB proves the cap is the cause, not body
    structure.
  5. Validates fail-soft + happy path: small valid envelopes still parse to loginChutes credentials
    end-to-end.

Proof pattern (mirrors #96027):

PASS  plugin token exchange bounded: rejected with "Chutes token exchange: JSON response exceeds 16777216 bytes..."; bytesSent=19922944 (< 67108864); server.aborted=true
PASS  plugin userinfo bounded: rejected with "Chutes userinfo: JSON response exceeds 16777216 bytes..."; bytesSent=19922944 (< 67108864); server.aborted=true
PASS  negative control: raw unbounded read of small body succeeded end-to-end (67108864 bytes) — cap is the cause of bounded-reader overflow, not body structure
PASS  cap-trace: bounded reader cancelled at ~18874368 bytes (full body = 67108864); server.aborted=true
PASS  happy path: loginChutes parsed small valid bodies end-to-end (access+refresh+userinfo)

Verification (all green)

  • node scripts/run-vitest.mjs extensions/chutes/oauth.test.ts — 4/4 passed
  • pnpm exec tsx scripts/repro/issue-chutes-plugin-oauth-bounded-read.mjs — 5/5 PASS with real HTTP server stats
  • npx oxlint --import-plugin --config .oxlintrc.json extensions/chutes/oauth.ts extensions/chutes/oauth.test.ts scripts/repro/issue-chutes-plugin-oauth-bounded-read.mjs — exit 0

Sibling PR references (matches #96027 / #96035 body style):

What was not tested: Did not exercise a live external api.chutes.ai endpoint; the untrusted-body
behavior is fully reproduced with a local streaming server, which uses the same fetch transport path.
The proof script is committed.

@clawsweeper

clawsweeper Bot commented Jun 24, 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.

@wangmiao0668000666

Copy link
Copy Markdown
Contributor Author

@sallyom — this PR is the Chutes OAuth half of the same bound-response.json() family
you merged in #95218 / #95417 / #95418 / #95420 / #96027 / #96035 / #96038 / #96042.

Two notable points compared to the earlier Alix-007 batch:

  1. Sibling coverage — first cut only fixed the deprecated core helper
    (src/agents/chutes-oauth.ts), missing the active bundled plugin path
    (extensions/chutes/oauth.ts) that openclaw onboard --auth-choice chutes
    actually enters. The follow-up commit (54aeeffb98) extends the swap to
    both plugin success-body reads (token exchange + userinfo), so the
    documented onboarding flow is now bounded.

  2. Proof pattern — the standalone repro
    (scripts/repro/issue-chutes-plugin-oauth-bounded-read.mjs, latest on
    commit 1bdb44d7a8) drives the production loginChutes against a real
    node:http server streaming a 64 MiB body with no Content-Length,
    observing server-side bytesSent (capped at ~19-20 MiB, well below the
    64 MiB would-stream) and the bounded reader cancelling the connection.
    Matches the pattern Alix-007 used for the ollama / parallel / exa /
    lmstudio batch.

🐚 platinum hermit + 👀 ready for maintainer look. Happy to address any
review feedback or coordinate ordering with the OpenAI video submit
(#96144) and DashScope (#96036) siblings.

@clawsweeper clawsweeper Bot added the merge-risk: 🚨 auth-provider 🚨 May break OAuth, tokens, provider routing, model choice, or credentials. label Jun 24, 2026
@wangmiao0668000666

Copy link
Copy Markdown
Contributor Author

Closing in favor of an Alix-007-style XS split. The actual code change is ~12 LoC across 2 surfaces — the current PR's 792 LoC comes from 2 committed repro scripts (530 LoC) + 2 new test files (249 LoC). Per Alix-007 pattern, each surface gets its own PR with inline tests and local-only proof:

  1. fix(chutes-oauth-core)src/agents/chutes-oauth.ts (3 call sites, core helper)
  2. fix(chutes-oauth-plugin)extensions/chutes/oauth.ts (2 call sites, active plugin path)

Both reuse readProviderJsonResponse from openclaw/plugin-sdk/provider-http — same fix, XS size, real-server proof in body.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling extensions: chutes merge-risk: 🚨 auth-provider 🚨 May break OAuth, tokens, provider routing, model choice, or credentials. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. scripts Repository scripts size: L 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.

1 participant