CVE-2026-29609
OpenClaw affected by denial of service via unbounded URL-backed media fetch
How AI Introduced This
Denial of Service (Memory Exhaustion)The blamed commit added the `fetchWithGuard` function to fetch media from URLs. While it included some SSRF protections and a timeout, it did not stream the response body with a hard limit, allowing an attacker to exhaust memory by returning an excessively large payload that bypasses the Content-Length check.
Root Cause
The application fetches media from user-provided URLs without enforcing limits on the response size or streaming the content, allowing an attacker to cause memory exhaustion by providing a URL that returns an excessively large payload.
▶Bug-Introducing Commits(1)
feat(gateway): implement OpenResponses /v1/responses endpoint phase 2
Tribunal Analysis
3 agents▶UNLIKELYGPT-5.483%
The vulnerability was introduced when URL-backed media fetching was added, and this commit does add that code path via a local `fetchWithGuard` in `src/gateway/openresponses-http.ts`. However, the blamed file for the CVE fix is `src/media/input-files.ts`, and that file did not exist in this commit; the later refactor/move into `src/media/input-files.ts` is where the vulnerable code in the fixed location actually originated. So this commit is clearly related and contains the same unbounded `response.arrayBuffer()` pattern, but it is not the commit that introduced the vulnerable code in the blamed file.
- •`a5afe7bc2b088ec08d868cd7175352c2db6fc329` added URL-backed `input_image`/`input_file` support and introduced `fetchWithGuard` in `src/gateway/openresponses-http.ts`.
- •That new `fetchWithGuard` checked `content-length` but then still did `const buffer = await response.arrayBuffer();`, which can fully buffer an oversized response before rejecting.
- •The fix commit replaces this pattern with bounded streaming reads (`readResponseWithLimit`) and adds base64 payload size estimation checks in `src/media/input-files.ts`.
- •At commit `a5afe7bc2b088ec08d868cd7175352c2db6fc329`, `src/media/input-files.ts` did not exist, so this specific commit cannot be the direct introducer of the vulnerable code in the blamed file.
▶CONFIRMEDClaude Opus 4.692%
The BIC (a5afe7bc) introduced the `fetchWithGuard` function in `src/gateway/openresponses-http.ts` that fetches URL-backed media content. This function contains the vulnerable pattern: it calls `await response.arrayBuffer()` to buffer the entire HTTP response into memory before checking `buffer.byteLength > maxBytes`. This allows an attacker to cause denial of service by providing a URL that serves an unbounded response (e.g., with no Content-Length header or a lying one), consuming arbitrary memory. The fix commit replaces this with `readResponseWithLimit` which reads the response incrementally via streaming and aborts as soon as the limit is exceeded. The code was later refactored from `openresponses-http.ts` into `src/media/input-files.ts`, but the vulnerable pattern originated in this BIC.
- •BIC introduced fetchWithGuard in src/gateway/openresponses-http.ts with: `const buffer = await response.arrayBuffer(); if (buffer.byteLength > maxBytes) { throw... }`
- •This pattern downloads the entire response into memory before checking size - the core DoS vulnerability (CWE-400)
- •Fix commit replaces `Buffer.from(await response.arrayBuffer())` with `readResponseWithLimit(response, params.maxBytes)` which streams and aborts early
- •Fix also adds `rejectOversizedBase64Payload` for inline base64 data and `estimateBase64DecodedBytes` - both addressing unbounded payload processing
- •The fetchWithGuard function was later moved from openresponses-http.ts to src/media/input-files.ts where the fix was applied
▶UNLIKELYGemini 3.1 Pro30%
Fallback verdict: Agent exhausted max turns without submitting a verdict.
fetch(url).then(res => res.blob())▶AI Signals(1)
| Claude Code | PR body keyword | Generated with [Claude Code] | 90% |