fix(files): cap per-entry decompressed size during zip extraction#321
Open
DeryFerd wants to merge 1 commit into
Open
fix(files): cap per-entry decompressed size during zip extraction#321DeryFerd wants to merge 1 commit into
DeryFerd wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
There was already a total size cap in the zip extraction logic -
extractWithinLimittracksextractedBytesacross all entries and stops once the combined output exceeds the configured limit (default 100MB). But it was missing a per-entry check. That means a single file inside the archive could grow without restraint as long as the total stayed under the limit. If someone packs a 99MB entry into a zip alongside a bunch of tiny files, the extractor would happily decompress the whole thing in one shot before the total cap trips.This becomes a problem when the individual entry is a compressed stream that decompresses to something massive - zip bombs with one oversized entry being the obvious case. The total cap would eventually catch it, but not before the entire entry was fully buffered in memory.
What changed in
backend/files/file-archive.tsInside the
extractWithinLimitfunction, there is a data callback that receives decompressed chunks per entry. The original code appended every chunk unconditionally, then checked the overall total after. The fix adds a guard right after updating the per-entry byte counter:Key detail: the check happens before
chunks.push, so if the entry exceeds the limit, we never store its data in the accumulator array. This avoids wasting memory on a file that is about to be rejected anyway.The
fileBytesvariable was already being tracked per-entry - it existed but was only used to allocate the concatenated buffer at the end. I just added the threshold check against it.Why this matters
Without this, a user could upload a zip containing a single entry that decompresses to 99.9MB and the system would happily keep it all in memory until extraction finishes. With the per-entry cap, it bails as soon as that specific file crosses the limit - which for an aggressively compressed entry could happen just a few kilobytes into the stream.
The behavior is consistent with the total cap: same error message pattern, same limit value, same early-exit strategy.
Validation
bun build --no-bundle backend/files/file-archive.ts- compiles fine