Describe the problem
Update::download() (plugins/updater/src/updater.rs, currently ~L724–L735) buffers the entire artifact into an unbounded Vec<u8> before verify_signature runs:
let mut buffer = Vec::new();
while let Some(chunk) = /* stream */ {
on_chunk(chunk.len(), content_length);
buffer.extend(chunk);
}
There is no way for the caller to bound the bytes actually read:
on_chunk(usize, Option<u64>) returns () — it can observe progress but cannot abort the download.
content_length comes from the response the attacker controls, so pre-checking it (or the size a custom feed advertises) authenticates nothing — a tampered manifest can omit the size or declare a small one while url points at a multi-GB blob.
Signature verification still protects integrity (minisign rejects tampered bytes), but it runs only after the full body is in memory, so availability is unprotected: an attacker who can tamper the update feed (or MITM a plain-HTTP feed) can make the app allocate until OOM, without ever needing the signing key.
Request
An enforceable, caller-set bound on bytes read in the download path. Any of these shapes would work:
- A builder option, e.g.
UpdaterBuilder::max_download_bytes(u64), aborting the request with a typed error once exceeded (checked against actual bytes read, not headers);
- Making the chunk callback fallible/controlling, e.g.
on_chunk: FnMut(usize, Option<u64>) -> ControlFlow<()>, so callers can abort mid-stream (with the plugin treating Break as a download error);
- Streaming the body to a temp file instead of RAM (bounds memory, though a disk cap would still be nice).
Option 1 is the smallest surface and keeps the verified-download path fully inside the plugin — important because working around this today means reimplementing download+verify outside the plugin, which turns a hand-rolled path into the sole authenticity control (exactly what one wants to avoid).
Context
tauri-plugin-updater 2.10.1 (current), behavior confirmed at repo HEAD.
- Not reporting as a vulnerability: it requires a compromised/MITM'd feed and is availability-only; filing as hardening so apps can enforce a pre-flight cap that actually holds.
Describe the problem
Update::download()(plugins/updater/src/updater.rs, currently ~L724–L735) buffers the entire artifact into an unboundedVec<u8>beforeverify_signatureruns:There is no way for the caller to bound the bytes actually read:
on_chunk(usize, Option<u64>)returns()— it can observe progress but cannot abort the download.content_lengthcomes from the response the attacker controls, so pre-checking it (or thesizea custom feed advertises) authenticates nothing — a tampered manifest can omit the size or declare a small one whileurlpoints at a multi-GB blob.Signature verification still protects integrity (minisign rejects tampered bytes), but it runs only after the full body is in memory, so availability is unprotected: an attacker who can tamper the update feed (or MITM a plain-HTTP feed) can make the app allocate until OOM, without ever needing the signing key.
Request
An enforceable, caller-set bound on bytes read in the download path. Any of these shapes would work:
UpdaterBuilder::max_download_bytes(u64), aborting the request with a typed error once exceeded (checked against actual bytes read, not headers);on_chunk: FnMut(usize, Option<u64>) -> ControlFlow<()>, so callers can abort mid-stream (with the plugin treatingBreakas a download error);Option 1 is the smallest surface and keeps the verified-download path fully inside the plugin — important because working around this today means reimplementing download+verify outside the plugin, which turns a hand-rolled path into the sole authenticity control (exactly what one wants to avoid).
Context
tauri-plugin-updater2.10.1 (current), behavior confirmed at repo HEAD.