fix(copilot-oauth): bound OAuth and API endpoint response reads#96877
fix(copilot-oauth): bound OAuth and API endpoint response reads#96877solodmd wants to merge 1 commit into
Conversation
|
Codex review: needs maintainer review before merge. Reviewed June 26, 2026, 1:24 AM ET / 05:24 UTC. Summary PR surface: Source +13, Tests +22. Total +35 across 2 files. Reproducibility: yes. for source-level review: current main and Review metrics: 1 noteworthy metric.
Stored data model 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 narrow core helper cap after maintainer acceptance of the 16 MiB auth-provider boundary, and keep adjacent OAuth/provider response-read sweeps separate unless maintainers want a coordinated batch. Do we have a high-confidence way to reproduce the issue? Yes for source-level review: current main and Is this the best way to solve the issue? Yes. Applying the existing bounded reader at the shared Copilot AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 751a6c23f098. Label changesLabel justifications:
Evidence reviewedPR surface: Source +13, Tests +22. Total +35 across 2 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
|
2f9fa1a to
f76caf0
Compare
|
@clawsweeper review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
What Problem This Solves
fetchJsoninsrc/llm/utils/oauth/github-copilot.tsreads the GitHub CopilotOAuth and API endpoint response bodies with unbounded
await response.text()and
await response.json(). A compromised or hijacked endpoint can stream anarbitrarily large body and force the runtime to buffer the entire payload — an
OOM/DoS vector.
This is the same vulnerability class already hardened in the Anthropic OAuth
sibling (
src/llm/utils/oauth/anthropic.ts, PR #96644).Changes
src/llm/utils/oauth/github-copilot.ts— importreadResponseWithLimitfrom
@openclaw/media-core/read-response-with-limit; replace bothawait response.text()andawait response.json()withreadResponseWithLimitat 16 MiB cap +new TextDecoder().decode(buffer)+JSON.parse. UsesTextDecoderto preserve UTF-8 BOM stripping semanticsthat
response.text()provides.Evidence
Real behavior proof
A real
node:httpserver was started on127.0.0.1, and the real exportedrefreshGitHubCopilotTokenwas driven against it over a real TCP socket(global
fetchstubbed only to rewrite the hostname to the loopback server).Node v22.22.0.
refreshGitHubCopilotTokenthrewGitHub Copilot token refresh request response too large: 16794740 bytes;the server write was cancelled (
ECANCELED) after the client stopped reading,confirming the stream was cancelled, not drained.
response.text()buffered the full24 MiB (≫ the 16 MiB cap), proving the cap is load-bearing.
{token, expires_at}JSON parsed intact(
access=pro-copilot-token).Tests
rejects an oversized Copilot token refresh responsecreates a ReadableStream whose first chunk exceeds the 16 MiB cap and proves
the bounded read cancels the body (
cancelcalled once,pullcount ≤ 2)and throws an error containing
"too large".listing, timeout, and unsafe lifetime rejection all pass.
pnpm test src/llm/utils/oauth/github-copilot.test.ts→ 11 passed (11)