fix(chutes-oauth): bound Chutes OAuth JSON response reads#96249
fix(chutes-oauth): bound Chutes OAuth JSON response reads#96249wangmiao0668000666 wants to merge 4 commits into
Conversation
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
|
Codex review: needs maintainer review before merge. Reviewed June 24, 2026, 11:39 AM ET / 15:39 UTC. Summary PR surface: Source +4, Tests +248, Other +530. Total +782 across 6 files. Reproducibility: yes. Current main has five raw Chutes OAuth success-body Review metrics: 2 noteworthy metrics.
Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest 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 Do we have a high-confidence way to reproduce the issue? Yes. Current main has five raw Chutes OAuth success-body Is this the best way to solve the issue? Yes. Reusing AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against fa2379dbc883. Label changesLabel changes:
Label justifications:
Evidence reviewedPR surface: Source +4, Tests +248, Other +530. Total +782 across 6 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
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
|
…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.
|
@clawsweeper re-review @clawsweeper — addressing the P2 finding on PR #96249 (commit
Verification (all green on commit
The merge-blocker P2 (test typecheck fail) should now be cleared. PR body unchanged. |
|
🦞🧹 I asked ClawSweeper to review this item again. |
…ProviderJsonResponse
|
@clawsweeper re-review Addressing the P1 sibling-coverage finding on PR #96249 (commit What changed
Net PR surface
Verification (all green on commit
P1 sibling coverage — both files now route through the same helper with consistent label |
|
🦞🧹 I asked ClawSweeper to review this item again. |
…er with bytes-sent proof
|
@clawsweeper re-review Upgrading PR #96249 proof to match the 🦞-grade pattern from the recently-merged Alix-007 PR family What changed in the repro The previous repro used a factory
Proof pattern (mirrors #96027): Verification (all green)
Sibling PR references (matches #96027 / #96035 body style):
What was not tested: Did not exercise a live external |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
@sallyom — this PR is the Chutes OAuth half of the same bound- Two notable points compared to the earlier Alix-007 batch:
🐚 platinum hermit + 👀 ready for maintainer look. Happy to address any |
|
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:
Both reuse |
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
loginChutespath can pull unlimited bytes into the agent process and trigger OOM
before the JSON.parse runs.
src/agents/chutes-oauth.tsextensions/chutes/oauth.tsopenclaw onboard --auth-choice chutesThis PR routes all five reads through the shared
readProviderJsonResponsehelper fromopenclaw/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
gap after ClawSweeper P1 finding on the original PR scope: fixing only
the deprecated core helper left
extensions/chutes/oauth.tsable tobuffer an oversized provider/proxy response during the documented
openclaw onboard --auth-choice chutesflow.plugin-sdk/provider-http, andalready proven on six upstream Alix-007 bound-stream PRs plus the
image-generation / video-generation / dashscope sites.
files. The plugin error labels (
"Chutes token exchange","Chutes userinfo") match the existing core helper labels so maintainerdashboards stay uniform.
No public API change, no schema change, no migration.
Changes
src/agents/chutes-oauth.ts—+6/-5— importreadProviderJsonResponsefrom./provider-http-errors.js; replacethree
(await response.json()) as Typecalls withawait readProviderJsonResponse<Type>(response, "<Chutes label>").extensions/chutes/oauth.ts—+6/-3— importreadProviderJsonResponsefromopenclaw/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-readerregression tests against the deprecated core helper.
extensions/chutes/oauth.test.ts—+129/-0— bounded-readerregression 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 — standalonerepro script that drives the core
readProviderJsonResponsedirectly.scripts/repro/issue-chutes-plugin-oauth-bounded-read.mjs— new —standalone repro script that drives the plugin
loginChutesend-to-endwith 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):
Real behavior proof
The two repro scripts drive the production code paths with no vitest mock:
scripts/repro/issue-chutes-oauth-bounded-read.mjsexercises thedeprecated core helper's three labels directly.
scripts/repro/issue-chutes-plugin-oauth-bounded-read.mjsexercisesloginChutesend-to-end with a stubbedfetchFn, proving the activebundled plugin path cancels and throws the canonical overflow error
before the runtime buffers the full body.
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 payloadand only fails on JSON parse, not on size.
Out of scope (separate follow-ups)
extensions/*/src/**files with the sameresponse.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.
assertOkOrThrowHttpError/readResponseTextLimitedcalls in thesame 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
readProviderJsonResponsehelper with consistent label prefixes,so any future Chutes success-body reads added to either file should
follow the same pattern.