fix(download): cap fetch_json decoded bytes - #117
Conversation
Copy gzip-decoded JSON through copy_capped into a 64 MiB buffer before serde_json parse so a huge or gzip-expanded body fails closed. Signed-off-by: Sebastien Tardif <[email protected]>
|
🦞👀 Pull request received. I will update this pull request when review starts. |
|
Codex review: needs maintainer review before merge. Reviewed August 29, 2026, 6:52 PM ET / 22:52 UTC. ClawSweeper reviewWhat this changesThe PR limits gzip-decoded runtime manifest and npm metadata JSON to 64 MiB before parsing, with a regression test for an oversized compressed response. Merge readinessKeep this PR open for normal maintainer review. It closes a source-proven unbounded decoded-JSON path and includes direct CLI proof; the remaining choice is whether the new 64 MiB hard limit is the intended compatibility policy for custom manifest and registry URLs. Priority: P2 Review scores
Verification
How this fits togetherOCM fetches runtime manifests and npm package metadata to list and install OpenClaw runtimes. This limit is applied after HTTP decoding and before JSON parsing, so oversized decoded responses fail before unbounded buffering. flowchart LR
A[Runtime command] --> B[Manifest or npm URL]
B --> C[HTTP response decoding]
C --> D[64 MiB decoded limit]
D --> E[JSON parsing]
E --> F[Runtime selection or install]
Decision needed
Why: The change deliberately prevents unbounded memory use but rejects previously accepted well-formed custom inputs above the limit. Before merge
Agent review detailsSecurityNone. Review metrics
Merge-risk optionsMaintainer options:
Technical reviewBest possible solution: Adopt a documented 64 MiB decoded-JSON limit for runtime metadata, retaining the exact-bound behavior and clear size error for custom sources. Do we have a high-confidence way to reproduce the issue? Yes, at source level: the current base streams decoded data directly into serde_json without a byte limit, and the reviewed branch supplies after-fix CLI evidence for the gzip-expanded case. Is this the best way to solve the issue? Unclear until maintainers accept the compatibility policy; the bounded shared fetch path is the narrowest implementation, but the fixed 64 MiB maximum deliberately changes custom-input behavior. AGENTS.md: not found in the target repository. Codex review notes: model internal, reasoning high; reviewed against b5df48d9a8ad. LabelsLabel changes:
Label justifications:
EvidenceWhat I checked:
Likely related people:
Rank-up movesOptional improvements that raise the rating; they are not merge blockers.
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
|
What Problem This Solves
Fixes an issue where users running
ocm runtime releases,ocm runtime install --manifest-url, or an official npm packument fetch would hang or run the process out of memory when the URL returned a huge, streaming, or gzip-expanded JSON body.download_to_filealready rejects bodies over 512 MiB (#92).fetch_jsonandfetch_json_with_acceptstill request gzip and parse the decoded stream withserde_json::from_readerand no decoded-byte cap. A 65 KB gzip payload in this session expanded to 64 MiB plus 11 bytes of JSON.Why This Change Was Made
Copy the decoded JSON through the existing
copy_cappedhelper into a bounded buffer, then parse that buffer. JSON is kept in memory, so the cap is 64 MiB, which is above today's officialopenclawnpm packument (about 16 MiB) and far below the 512 MiB artifact cap.User Impact
A runtime manifest or npm packument that expands past 64 MiB now fails with
download exceeded 67108864 bytesinstead of growing without bound. Officialocm runtime releasesstill lists published OpenClaw versions.Evidence
terminal output from the patched
ocmbinary against a local gzip-expanded JSON URL, then against registry.npmjs.org:A 65,265-byte gzip body decoded to 67,108,875 bytes (11 bytes past the 64 MiB cap). The CLI rejected it:
The same binary still loaded the official catalog (248 releases) and the stable channel (
2026.7.1-2).Real behavior proof
Behavior or issue addressed:
fetch_jsonaccepted unbounded decoded JSON (including gzip-expanded bodies) onocm runtime releasesand--manifest-urlinstalls. Those commands now reject a body past 64 MiB decoded bytes.Real environment tested: macOS Darwin 25.6.0 arm64, rustc 1.98.0, ocm 0.2.33 built from this branch at
/tmp/oc-pr-ocm-F003. IsolatedOCM_HOMEunder/tmp/ocm-f003-proof-ocm.Exact steps or command run after this patch:
Built
./target/debug/ocm. Served a gzip JSON body of 67,108,875 decoded bytes (65,265 bytes on the wire) from127.0.0.1:18765. Then ranocm runtime releases --manifest-url http://127.0.0.1:18765/manifest.json, thenocm runtime releases --jsonandocm runtime releases --channel stable --jsonagainst registry.npmjs.org.Evidence after fix: terminal output from the patched CLI:
Observed result after fix: The gzip-expanded manifest URL exits 1 with the decoded-byte cap. The official npm catalog still returns 248 releases.
What was not tested: A live attacker-controlled HTTPS host on the public internet.
ocm self updateGitHub release JSON (that path does not usefetch_json).Related: #92 added ureq timeouts and the
download_to_filesize cap. Gzip request wrapping landed inf0b7f2d.fetch_jsonitself dates to768baf1. Same class of bound as rust-lang/cargo#11151 (unpacked crate size).