fix(vydra): bound control response reads#96875
Conversation
|
Codex review: needs maintainer review before merge. Reviewed June 26, 2026, 8:38 PM ET / 00:38 UTC. Summary PR surface: Source +6, Tests +79. Total +85 across 6 files. Reproducibility: yes. at source/proof level. Current main and Review metrics: 1 noteworthy metric.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land the plugin-scoped shared-reader change after required checks if maintainers accept the 16 MiB control-JSON cap for Vydra. Do we have a high-confidence way to reproduce the issue? Yes at source/proof level. Current main and 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 65fec9d787e3. Label changesLabel justifications:
Evidence reviewedPR surface: Source +6, Tests +79. Total +85 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
|
9750e3c to
88125a0
Compare
What Problem This Solves
Vydra success-path untrusted body handling read submit and job-poll control JSON with unbounded
await response.json(), so a hostile, misconfigured, or SSRF-reachable endpoint could stream a no-Content-Lengthbody indefinitely and force OpenClaw to buffer it before parsing, causing OOM pressure or a hang on image, video, and speech generation paths.The affected reads were:
extensions/vydra/image-generation-provider.tsimage submit JSONextensions/vydra/speech-provider.tsspeech submit JSONextensions/vydra/video-generation-provider.tsvideo submit JSONextensions/vydra/shared.tsshared job poll JSON used by image/video async jobsChanges
response.json()calls with the sharedreadProviderJsonResponsehelper fromopenclaw/plugin-sdk/provider-http.assertOkOrThrowHttpErrorbehavior, job id/status extraction, asset download path, andrelease()cleanup.Real behavior proof
Content-Lengthbodies must stop at the 16 MiB cap, cancel the stream, and throw a bounded...exceeds 16777216 byteserror. Small valid JSON must continue to parse normally.node:httpserver (createServer) bound to127.0.0.1, streaming JSON in 64 KiB chunks with noContent-Lengthheader and a would-stream size of about 64 MiB. The script drove the real exportedbuildVydraImageGenerationProvider().generateImage()over a real loopback socket through the realpostJsonRequest, guarded fetch path, andreadProviderJsonResponse. The shared poll helper was exercised by returning a queued submit payload and then streaming the oversized poll response from/jobs/<id>. Node v22.22.0.node --import tsx scratchpad/vydra-bound-proof.mts— start the streaming server → call real Vydra image submit and assert bounded throw + server-side socket abort near the cap → call real Vydra image job poll path and assert bounded throw + socket abort near the cap → run a negative control using old unboundedfetch().arrayBuffer()against the same streaming body → call the real provider against a small valid JSON response and asset response.Vydra image generation: JSON response exceeds 16777216 bytesand aborted after 20,119,564 bytes; shared poll JSON threwVydra job status: JSON response exceeds 16777216 bytesand aborted after 18,022,412 bytes. The negative control buffered the full 67,108,866 bytes, proving the cap is load-bearing. The small happy path returned the generated image payload and metadata.Evidence
Real
node:httpterminal proof (real loopback socket, real exported Vydra provider, real bounded reader):Focused Vitest after rebase:
Type and format checks after rebase:
Autoreview after rebase:
Label: security
AI-assisted.
Post-rebase scope update:
mainhas since landed the Vydra image submit bound, so this PR no longer changesimage-generation-provider.ts(only a focused image regression test remains). This PR now bounds the remaining success-path reads:shared.ts(shared job-poll JSON used by image/video async jobs),speech-provider.ts(speech submit), andvideo-generation-provider.ts(video submit) — all routed through the sharedreadProviderJsonResponse(16 MiB cap). Theimage-generation-provider.tssource line in the bullet list above can be disregarded.