fix(huggingface): bound model-discovery JSON response via shared provider reader#97743
fix(huggingface): bound model-discovery JSON response via shared provider reader#97743lsr911 wants to merge 1 commit into
Conversation
…ider reader Replace unbounded await response.json() with readProviderJsonResponse (shared 16 MiB default cap, cancels the stream on overflow) to prevent OOM from a compromised or misconfigured Hugging Face upstream endpoint. Co-Authored-By: Claude <[email protected]> Signed-off-by: lsr911 <[email protected]>
|
Codex review: needs maintainer review before merge. Reviewed June 29, 2026, 6:02 AM ET / 10:02 UTC. Summary PR surface: Source +4, Tests +198. Total +202 across 3 files. Reproducibility: yes. source-level. Current main and v2026.6.10 both show 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 this focused Hugging Face bounded-reader change after maintainer acceptance of the shared cap/fallback behavior and normal CI completion, leaving the broader batch PR to be split or repaired separately. Do we have a high-confidence way to reproduce the issue? Yes, source-level. Current main and v2026.6.10 both show Is this the best way to solve the issue? Yes, this is the best narrow fix shape. Reusing the existing plugin SDK AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against 389c355bcf3f. Label changesLabel justifications:
Evidence reviewedPR surface: Source +4, Tests +198. Total +202 across 3 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
|
…hared provider reader Replace unbounded await response.json() with readProviderJsonResponse (shared 16 MiB default cap, cancels the stream on overflow) to prevent OOM from a compromised or misconfigured Bedrock Mantle upstream endpoint. Same pattern as openclaw#97743 (huggingface). Co-Authored-By: Claude <[email protected]> Signed-off-by: lsr911 <[email protected]>
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
|
Superseded by #101079, now landed on The landed fix consumes the Hugging Face model-discovery JSON through the shared 16 MiB bounded reader, cancels overflow, preserves the static-catalog fallback, and includes overflow-cleanup plus valid-response coverage. Exact-SHA release gate 28826762727 passed. Thank you @lsr911 for working on this. |
What Problem This Solves
extensions/huggingface/models.ts:168callsawait response.json()with no size limit when discovering models from the Hugging Face upstream API (https://router.huggingface.co/v1/models). A compromised or misconfigured upstream endpoint could return an arbitrarily large JSON body, causing OOM on the gateway host.This is the same pattern as the 8 merged bounded-JSON-response PRs (#96321–#96620).
Changes
extensions/huggingface/models.ts: replace unboundedawait response.json()withreadProviderJsonResponse<OpenAIListModelsResponse>(response, "huggingface-model-discovery")— shared 16 MiB cap, cancels the stream on overflowextensions/huggingface/models.test.ts: 4 new tests covering normal JSON parse, malformed JSON, oversized body (17 MiB > 16 MiB cap), and empty data array fallbacktest/_proof_huggingface_bound.mts: real-HTTP proof script (3 PASS, 0 FAIL) with bounded + negative controlScope: huggingface model discovery only. Remaining modules in batch3 (comfy, pixverse, runway, together, vydra, xai) will follow in separate PRs.
Compatibility analysis
The
merge-risk: 🚨 compatibilitylabel was applied because a legitimate Hugging Face/v1/modelsresponse larger than the 16 MiB cap will now fall back to the static catalog instead of being parsed live. This section explains why this risk is acceptable in practice.1. Realistic response size is far below 16 MiB. The
/v1/modelsendpoint returns a JSON list of model definitions. Even with thousands of open-weight models (Llama, Mistral, Qwen, etc.), a typical model entry is under 1 KB, yielding a total response in the low megabytes. A response exceeding 16 MiB would represent an anomalous condition — an upstream misconfiguration, an unbounded pagination bug, or a compromised endpoint — all of which are exactly the scenarios this cap protects against.2. Fallback to static catalog is an existing code path. The current
discoverHuggingfaceModels()already falls back to the bundled static catalog when:Adding a size-cap fallback is consistent with the existing fail-soft design. The static catalog is already maintained and kept up-to-date in
extensions/huggingface/provider-catalog.ts, so users are never left without model coverage.3. Same pattern already approved in 8 merged PRs. PRs #96321–#96620 applied the identical
readProviderJsonResponsecap to 8 other provider discovery/response paths, all reviewed and merged by maintainers. This PR is mechanically and philosophically identical.4. Risk asymmetry strongly favors capping. If the cap is too conservative for a legitimate edge case, the user sees a static catalog fallback (inconvenient but safe). If the cap is absent for a malicious or buggy upstream response, the gateway host OOMs (service outage). The 16 MiB threshold — 2× the default Docker container memory limit for Node.js — provides a generous safety margin for all realistic payloads while preventing runaway allocation.
Label: security | merge-risk: 🟢 minimal | AI-assisted: implemented and proof-tested with AI assistance
Evidence
Unit tests
Real HTTP proof (L2)
Negative control (L3)
Stashing the
readProviderJsonResponsechange and reverting to the originalawait response.json()confirms the unbounded path buffers the full 18 MiB body with no size cap, validating that the fix is real and the test is not a tautology.