Problem
cache.fetch() returns Vec<u8> with no size cap. A guest requesting a multi-GB CID will load the entire content into host memory before writing to staging.
The ARC budget limits what stays pinned, but fetch() bypasses it — it calls pinner.fetch() directly.
Fix
Check the CID size (already known from the prior ensure() call) against a configurable maximum before fetching. Or better: stream content directly to disk instead of buffering in memory.
Context
Found by adversarial review on #263. The open_ipfs flow is:
cache.ensure(cid) — pins, stores size in ARC
cache.fetch(cid) — loads entire content into Vec<u8>
std::fs::write(&file_path, &bytes) — writes to staging
Step 2 is the problem. A streaming approach would pipe bytes from the IPFS node directly to a file on disk.
Severity
High — a malicious or careless guest can crash the host process.
Problem
cache.fetch()returnsVec<u8>with no size cap. A guest requesting a multi-GB CID will load the entire content into host memory before writing to staging.The ARC budget limits what stays pinned, but
fetch()bypasses it — it callspinner.fetch()directly.Fix
Check the CID size (already known from the prior
ensure()call) against a configurable maximum before fetching. Or better: stream content directly to disk instead of buffering in memory.Context
Found by adversarial review on #263. The
open_ipfsflow is:cache.ensure(cid)— pins, stores size in ARCcache.fetch(cid)— loads entire content intoVec<u8>std::fs::write(&file_path, &bytes)— writes to stagingStep 2 is the problem. A streaming approach would pipe bytes from the IPFS node directly to a file on disk.
Severity
High — a malicious or careless guest can crash the host process.