Repository navigation
fix: reject an empty archive whose central directory offset is past the EOCD - #1025
Merged
Pr0methean merged 4 commits intoOct 9, 2026
Merged
Conversation
…he EOCD An end-of-central-directory record with zero entries skipped every consistency check, including the one that the central directory starts before the EOCD. A 22-byte EOCD claiming the central directory starts at 0x7fffffff was accepted with archive_offset 0, and `ZipWriter::new_append` then wrote the next entry at that offset: `finish` returned Ok and the output grew to 2 GiB (0xffffff00: 4 GiB), or tried to allocate that much in a `Cursor<Vec<u8>>`. APPNOTE 4.4.24: the offset of the start of the central directory is relative to the starting disk number. An empty central directory ends where it starts, directly before the EOCD, so its offset cannot be past the EOCD. Apply the same check as non-empty archives, except that an offset equal to the EOCD position (empty central directory immediately before the EOCD) stays valid. Info-ZIP's unzip rejects such a file. The ZIP64 path already rejects it through the file-count check against the EOCD64 position.
Pr0methean
reviewed
Oct 8, 2026
Signed-off-by: Chris Hennick <4961925+Pr0methean@users.noreply.github.com>
Pr0methean
previously approved these changes
Oct 8, 2026
Signed-off-by: Chris Hennick <4961925+Pr0methean@users.noreply.github.com>
Pr0methean
previously approved these changes
Oct 9, 2026
Pr0methean
enabled auto-merge
October 9, 2026 03:29
This was referenced Oct 9, 2026
Closed
Closed
Merged
1 task done
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.
Problem
find_central_directory_endchecks that the central directory starts before the EOCD, but itreturns early for an archive with zero entries, before that check. So a 22-byte EOCD that says
"0 entries, central directory at 0x7fffffff" opens as a valid empty archive, with
central_directory_start()= 2147483647 in a 22-byte file.ZipWriter::new_appendthen takes that offset as the place to write the next entry:finishreturnsOk, and the file is now 2,147,483,770 bytes, with the new local header at0x7fffffff. With offset 0xffffff00 it is 4 GiB. On ext4 the file is sparse, so it takes only a few
KiB on disk, but anything that copies or uploads it moves 2–4 GiB. With a
Cursor<Vec<u8>>,new_append+finishtries to allocate the whole 2–4 GiB. Any program that appends to anarchive it got from somewhere else is affected.
Info-ZIP
unziprejects such a file. The ZIP64 path already rejects the same shape, because itchecks the file count against the EOCD64 position.
Change
In the zero-entry branch, apply the same consistency check as for non-empty archives: the
central directory offset must not be past the EOCD. An offset equal to the EOCD position is still
accepted, because that is exactly where an empty central directory sits (APPNOTE 4.4.24: the
offset is where the central directory starts; with no entries it ends where it starts, right
before the EOCD). On failure the search goes on to the next EOCD candidate, as for the other
checks.
Test
tests/empty_archive_cd_offset.rs:empty_archive_with_cd_offset_past_eocd_is_rejected: offsets 23, 0x7fffffff and 0xffffff00 ina 22-byte EOCD. Both
ZipArchive::newandZipWriter::new_appendmust fail. Fails on master(offset 23 is accepted).
empty_archive_still_opens_and_appends: the normal empty archive (offset 0), with and without aprepended prefix, still opens, takes an appended entry, and the result is small and reads back.
The suite passes on 1.88, stable and nightly with default features,
--no-default-features,--all-features, and the two single-deflate feature sets;cargo clippy --all-targets -- -D warningsandcargo doc --no-depsare clean with default,--no-default-featuresand--all-features;cargo fmt --check --allis clean.Found with a fuzzer that appends to and merges generated archives and checks that existing
entries keep their bytes.