fix(openrouter): bound generation-cost JSON response reads#97490
Conversation
|
Codex review: needs maintainer review before merge. Reviewed June 28, 2026, 11:23 AM ET / 15:23 UTC. Summary PR surface: Source +6, Tests +51. Total +57 across 2 files. Reproducibility: yes. Current main has a direct unbounded Review metrics: 1 noteworthy metric.
Stored data model 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. Next step before merge
Security Review detailsBest possible solution: Land this focused helper reuse after normal maintainer review, keeping video submit/poll response bounding in its separate open PR. Do we have a high-confidence way to reproduce the issue? Yes. Current main has a direct unbounded 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 2f851ecfe9df. Label changesLabel justifications:
Evidence reviewedPR surface: Source +6, Tests +51. Total +57 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
|
What Problem This Solves
fetchOpenRouterGenerationTotalCostinextensions/openrouter/stream.tsreads the OpenRouter/generationmetadata endpoint with an unboundedawait response.json()on the success path. The error path was already protected —assertOkOrThrowHttpErrorroutes throughcreateProviderHttpErrorwhich uses the bounded reader — but the success path had no cap.This is the same asymmetric pattern fixed for sibling OpenRouter paths:
video-model-catalog.tsvideo catalog JSON reads (merged)provider-catalog.tsmodel-scan catalog body (merged)video-generation-provider.tsvideo submit/poll JSON (open; its PR body explicitly notes generation-cost is out of scope)The generation-cost lookup fires on every OpenRouter agent turn where
usage.costandresponseIdare present, making it the hottest remaining unbounded read in the extension. BecauseresolveOpenRouterGenerationUrlsubstitutesmodel.baseUrlwhen present, a misconfigured or hostile endpoint can stream an arbitrarily large body withoutContent-Lengthand force the process to buffer it before parsing — an OOM vector.Why This Change Was Made
The error body on this path was already capped; leaving the success body uncapped is an asymmetric gap.
readProviderJsonResponseapplies the same 16 MiB cap used across every other provider JSON success path, and the lookup failure is already handled gracefully — errors are caught, logged at debug level, and the original streamed cost estimate is preserved — so the risk of this change is minimal.User Impact
OpenRouter users with cost tracking enabled no longer risk OOM from an oversized generation-metadata response. Normal responses (well under 16 MiB) are unaffected.
Evidence
Proof script (
scripts/proof-openrouter-generation-cost-bound.mjs) uses a realnode:httpserver on127.0.0.1, Node v22.22.0, no Content-Length, realfetch:The new test
"falls back to streamed cost estimate when generation metadata response is oversized"streams a body exceeding the cap via a realReadableStream, verifies the bounded read rejects it, and confirmsapplyOpenRouterBilledCostfalls back to the original streamed estimate rather than propagating the error.What was not tested: live OpenRouter API calls.
AI-assisted.