Every CVE Search/ Get API key

CVE-2026-115909

zip: Unbounded Symlink-Target Handling Can Abort Or Exhaust Memory During Extraction

7.5 HighFix available

zip is a zip library for Rust that supports reading and writing simple ZIP files. From 1.3.0 until 9.0.0, ZipArchive::extract in src/read/mod.rs calls Vec::with_capacity for a symbolic link target using the attacker-controlled ZIP64 uncompressed_size before reading entry data. A small archive can request an impossible capacity, causing the infallible allocation path to abort the process before the entry is validated. The failure cannot be contained with catch_unwind or a worker thread, allowing repeated denial of service in archive-processing applications. This issue is fixed in version 9.0.0.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
None
User interaction
None

What an attacker can affect

Confidentiality
None
Integrity
None
Availability
High

Exploit likelihood

0.46%Unchanged since Oct 27, 2026
90%50%10%1%

What each source reports

CVE List Score used 7.5

zip: Unbounded Symlink-Target Handling Can Abort Or Exhaust Memory During Extraction

zip is a zip library for Rust that supports reading and writing simple ZIP files. From 1.3.0 until 9.0.0, ZipArchive::extract in src/read/mod.rs calls Vec::with_capacity for a symbolic link target using the attacker-controlled ZIP64 uncompressed_size before reading entry data. A small archive can request an impossible capacity, causing the infallible allocation path to abort the process before the entry is validated. The failure cannot be contained with catch_unwind or a worker thread, allowing repeated denial of service in archive-processing applications. This issue is fixed in version 9.0.0.

Record
CVE-2026-115909
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Weakness
CWE-400, CWE-789
Updated
2026-11-02
EUVDEUVD-2026-109987 7.5

zip is a zip library for Rust that supports reading and writing simple ZIP files. From 1.3.0 until 9.0.0, ZipArchive::extract in src/read/mod.rs calls Vec::with_capacity for a symbolic link target using the attacker-controlled ZIP64 uncompressed_size before reading entry data. A small archive can request an impossible capacity, causing the infallible allocation path to abort the process before the entry is validated. The failure cannot be contained with catch_unwind or a worker thread, allowing repeated denial of service in archive-processing applications. This issue is fixed in version 9.0.0.

Record
EUVD-2026-109987
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Updated
2026-11-02
GitHub AdvisoriesGHSA-q7v9-x93c-xqv3 7.5

zip: Unbounded Symlink-Target Handling Can Abort Or Exhaust Memory During Extraction

Summary

The symbolic-link branch of ZipArchive::extract_internal() allocates a buffer using an attacker-declared size before reading any entry data. A 112-byte archive terminates the extracting process with SIGABRT through this infallible allocation.

Details

#[cfg(any(unix, windows))]
if file.is_symlink() {
    let mut target = Vec::with_capacity(file.size() as usize); // @audit unbounded memory allocation
    file.read_to_end(&mut target)?;
    drop(file);
    make_symlink(&outpath, &target, &self.shared.files)?;
    continue;
}

src/read/mod.rs#L399-L405 (reviewed commit 6f09b306); the same code is at src/read.rs#L417-L418 in released v8.6.0.

Both inputs are attacker-controlled:

  • ZipFile::size() returns uncompressed_size verbatim from the central directory record. A ZIP64 extended-information extra field widens it to a full u64 (src/read/mod.rs#L619-L625). It is never cross-checked against the compressed size, the remaining archive length, or any platform-appropriate bound for a symlink target.
  • ZipFile::is_symlink() is decided entirely by the central directory's external-attributes field, via the S_IFLNK bit.

Memory allocation failure → uncatchable process abort. The reservation is sized from the declared uncompressed_size before a single byte of the entry is read. Vec::with_capacity() is infallible: on allocator refusal it calls handle_alloc_error(), which aborts the process. This is not a Rust panic — it is not caught by catch_unwind(), is unaffected by panic = "unwind", and is not contained by isolating the call in a worker thread. This was verified by wrapping the call in all three at once; the process still died with exit 134.

The declared value needed is a property of the host's address space, not of reachability. On a 64 GB host with heuristic overcommit, declared sizes from roughly 2^38 upward abort reliably. Sizes at or above 2^63 instead trip Vec's internal capacity check and produce a catchable capacity overflow panic, so an attacker simply avoids that band. The reproducer declares 2^62, which exceeds the 47-bit user address space of x86-64 Linux outright and therefore aborts deterministically regardless of installed RAM or overcommit policy. Under a ulimit -v cap or a memory-constrained container the threshold drops far enough that a plain 32-bit uncompressed_size with no ZIP64 field suffices — a virtual-memory limit lowers the bar rather than mitigating the defect.

This is process termination, not memory exhaustion: Vec::with_capacity() only maps address space and never touches pages, so resident memory stays flat and the abort happens on the refused reservation itself, before any byte is read.

PoC

The reproducer consists of the following zip harness and payload. It requires only the zip crate; use a standard Base64 decoder to materialise the archive before running it.

[package]
name = "zip-poc"
version = "0.1.0"
edition = "2021"

[dependencies]
zip = "8.6.0"
use std::{env, fs::File, io::BufReader};

fn main() {
    let archive_path = env::args().nth(1).expect("usage: poc <archive.zip>");
    let outdir = std::env::temp_dir().join("zip-poc");
    std::fs::create_dir_all(&outdir).unwrap();

    let file = File::open(archive_path).unwrap();
    let mut archive = zip::ZipArchive::new(BufReader::new(file)).unwrap();
    let r = archive.extract(&outdir);            // <-- process dies here
   …
Record
GHSA-q7v9-x93c-xqv3
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Weakness
CWE-400, CWE-789
Updated
2026-11-02
NVD 7.5

zip is a zip library for Rust that supports reading and writing simple ZIP files. From 1.3.0 until 9.0.0, ZipArchive::extract in src/read/mod.rs calls Vec::with_capacity for a symbolic link target using the attacker-controlled ZIP64 uncompressed_size before reading entry data. A small archive can request an impossible capacity, causing the infallible allocation path to abort the process before the entry is validated. The failure cannot be contained with catch_unwind or a worker thread, allowing repeated denial of service in archive-processing applications. This issue is fixed in version 9.0.0.

Record
CVE-2026-115909
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Weakness
CWE-400, CWE-789
Updated
2026-11-02
OSV 7.5

zip: Unbounded Symlink-Target Handling Can Abort Or Exhaust Memory During Extraction

zip is a zip library for Rust that supports reading and writing simple ZIP files. From 1.3.0 until 9.0.0, ZipArchive::extract in src/read/mod.rs calls Vec::with_capacity for a symbolic link target using the attacker-controlled ZIP64 uncompressed_size before reading entry data. A small archive can request an impossible capacity, causing the infallible allocation path to abort the process before the entry is validated. The failure cannot be contained with catch_unwind or a worker thread, allowing repeated denial of service in archive-processing applications. This issue is fixed in version 9.0.0.

Record
CVE-2026-115909
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Weakness
CWE-400, CWE-789
Updated
2026-11-02
OSVDEBIAN-CVE-2026-115909 7.5

zip is a zip library for Rust that supports reading and writing simple ZIP files. From 1.3.0 until 9.0.0, ZipArchive::extract in src/read/mod.rs calls Vec::with_capacity for a symbolic link target using the attacker-controlled ZIP64 uncompressed_size before reading entry data. A small archive can request an impossible capacity, causing the infallible allocation path to abort the process before the entry is validated. The failure cannot be contained with catch_unwind or a worker thread, allowing repeated denial of service in archive-processing applications. This issue is fixed in version 9.0.0.

Record
DEBIAN-CVE-2026-115909
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Updated
2026-11-02
Show 7 moreShow less
OSVGHSA-q7v9-x93c-xqv3 7.5

zip: Unbounded Symlink-Target Handling Can Abort Or Exhaust Memory During Extraction

Summary

The symbolic-link branch of ZipArchive::extract_internal() allocates a buffer using an attacker-declared size before reading any entry data. A 112-byte archive terminates the extracting process with SIGABRT through this infallible allocation.

Details

#[cfg(any(unix, windows))]
if file.is_symlink() {
    let mut target = Vec::with_capacity(file.size() as usize); // @audit unbounded memory allocation
    file.read_to_end(&mut target)?;
    drop(file);
    make_symlink(&outpath, &target, &self.shared.files)?;
    continue;
}

src/read/mod.rs#L399-L405 (reviewed commit 6f09b306); the same code is at src/read.rs#L417-L418 in released v8.6.0.

Both inputs are attacker-controlled:

  • ZipFile::size() returns uncompressed_size verbatim from the central directory record. A ZIP64 extended-information extra field widens it to a full u64 (src/read/mod.rs#L619-L625). It is never cross-checked against the compressed size, the remaining archive length, or any platform-appropriate bound for a symlink target.
  • ZipFile::is_symlink() is decided entirely by the central directory's external-attributes field, via the S_IFLNK bit.

Memory allocation failure → uncatchable process abort. The reservation is sized from the declared uncompressed_size before a single byte of the entry is read. Vec::with_capacity() is infallible: on allocator refusal it calls handle_alloc_error(), which aborts the process. This is not a Rust panic — it is not caught by catch_unwind(), is unaffected by panic = "unwind", and is not contained by isolating the call in a worker thread. This was verified by wrapping the call in all three at once; the process still died with exit 134.

The declared value needed is a property of the host's address space, not of reachability. On a 64 GB host with heuristic overcommit, declared sizes from roughly 2^38 upward abort reliably. Sizes at or above 2^63 instead trip Vec's internal capacity check and produce a catchable capacity overflow panic, so an attacker simply avoids that band. The reproducer declares 2^62, which exceeds the 47-bit user address space of x86-64 Linux outright and therefore aborts deterministically regardless of installed RAM or overcommit policy. Under a ulimit -v cap or a memory-constrained container the threshold drops far enough that a plain 32-bit uncompressed_size with no ZIP64 field suffices — a virtual-memory limit lowers the bar rather than mitigating the defect.

This is process termination, not memory exhaustion: Vec::with_capacity() only maps address space and never touches pages, so resident memory stays flat and the abort happens on the refused reservation itself, before any byte is read.

PoC

The reproducer consists of the following zip harness and payload. It requires only the zip crate; use a standard Base64 decoder to materialise the archive before running it.

[package]
name = "zip-poc"
version = "0.1.0"
edition = "2021"

[dependencies]
zip = "8.6.0"
use std::{env, fs::File, io::BufReader};

fn main() {
    let archive_path = env::args().nth(1).expect("usage: poc <archive.zip>");
    let outdir = std::env::temp_dir().join("zip-poc");
    std::fs::create_dir_all(&outdir).unwrap();

    let file = File::open(archive_path).unwrap();
    let mut archive = zip::ZipArchive::new(BufReader::new(file)).unwrap();
    let r = archive.extract(&outdir);            // <-- process dies here
   …
Record
GHSA-q7v9-x93c-xqv3
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Weakness
CWE-400, CWE-789
Updated
2026-11-02
OSVRUSTSEC-2026-0429 7.5

zip: `ZipArchive::extract` aborts the process on a symlink entry with a large declared size

ZipArchive::extract() sizes the symlink-target buffer from the uncompressed size declared in the central directory record, before reading a single byte of entry data:

let mut target = Vec::with_capacity(file.size() as usize);

Both inputs are attacker-controlled. ZipFile::size() returns uncompressed_size verbatim from the central directory, widened to a full u64 by a ZIP64 extended-information extra field, and is never cross-checked against the compressed size, the remaining archive length, or any platform-appropriate bound for a symlink target. ZipFile::is_symlink() is decided entirely by the S_IFLNK bit of the external-attributes field.

Vec::with_capacity() is infallible: when the reservation is refused it calls handle_alloc_error() and aborts the process. This is not a Rust panic. It is not caught by catch_unwind(), is unaffected by panic = "unwind", and is not contained by running the call on a worker thread.

A 112-byte archive is sufficient. One Stored entry flagged S_IFLNK with a ZIP64 field declaring uncompressed_size = 2^62 and a zero-byte payload makes extract() fail with:

memory allocation of 4611686018427387904 bytes failed
Aborted (core dumped)          # exit 134

The declared value only needs to exceed the host's address space, not its RAM: Vec::with_capacity() maps address space without touching pages, so resident memory stays flat and the abort happens on the refused reservation itself. Under a ulimit -v cap or a memory-constrained container the threshold drops far enough that a plain 32-bit uncompressed_size with no ZIP64 field suffices.

Applications that extract archives from untrusted input are affected on Unix and Windows targets with default features and no special configuration: upload handling, mail-attachment processing, package and artefact ingestion, backup restore and container-image layer extraction. No confidentiality or integrity property is affected: there is no memory unsafety, no out-of-bounds access, no disclosure and no data corruption.

The fix landed in zip-rs/zip2#984 and shipped in 9.0.0.

For further details see: https://github.com/zip-rs/zip2/security/advisories/GHSA-q7v9-x93c-xqv3

Record
RUSTSEC-2026-0429
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Updated
2026-11-02
OSVUBUNTU-CVE-2026-115909 7.5

zip is a zip library for Rust that supports reading and writing simple ZIP files. From 1.3.0 until 9.0.0, ZipArchive::extract in src/read/mod.rs calls Vec::with_capacity for a symbolic link target using the attacker-controlled ZIP64 uncompressed_size before reading entry data. A small archive can request an impossible capacity, causing the infallible allocation path to abort the process before the entry is validated. The failure cannot be contained with catch_unwind or a worker thread, allowing repeated denial of service in archive-processing applications. This issue is fixed in version 9.0.0.

Record
UBUNTU-CVE-2026-115909
CVSS 3.1
7.5 HighCVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Updated
2026-11-04
OSVAZL-112211 No score

CVE-2026-115909 affecting package rust 1.75.0-31

zip is a zip library for Rust that supports reading and writing simple ZIP files. From 1.3.0 until 9.0.0, ZipArchive::extract in src/read/mod.rs calls Vec::with_capacity for a symbolic link target using the attacker-controlled ZIP64 uncompressed_size before reading entry data. A small archive can request an impossible capacity, causing the infallible allocation path to abort the process before the entry is validated. The failure cannot be contained with catch_unwind or a worker thread, allowing repeated denial of service in archive-processing applications. This issue is fixed in version 9.0.0.

Record
AZL-112211
Updated
2026-11-05
OSVAZL-112220 No score

CVE-2026-115909 affecting package rust 1.98.1-1

zip is a zip library for Rust that supports reading and writing simple ZIP files. From 1.3.0 until 9.0.0, ZipArchive::extract in src/read/mod.rs calls Vec::with_capacity for a symbolic link target using the attacker-controlled ZIP64 uncompressed_size before reading entry data. A small archive can request an impossible capacity, causing the infallible allocation path to abort the process before the entry is validated. The failure cannot be contained with catch_unwind or a worker thread, allowing repeated denial of service in archive-processing applications. This issue is fixed in version 9.0.0.

Record
AZL-112220
Updated
2026-11-05
OSVSUSE-SU-2026:4930-1 No score

Security update for rust-keylime

This update for rust-keylime fixes the following issue:

  • CVE-2026-115905: zip: security control bypass via parser differential between central directory and local headers (bsc#1287921)
  • CVE-2026-115906: zip: authentication bypass in AES encrypted entries due to improper HMAC verification (bsc#1287921)
  • CVE-2026-115907: zip: denial of service via unbounded memory allocation in legacy decoders (bsc#1287921)
  • CVE-2026-115908: zip: path traversal via lexical symlink validation during extraction (bsc#1287921)
  • CVE-2026-115909: zip: denial of service via uncontrolled memory allocation on symlink targets (bsc#1287921)

Changes for rust-keylime:

  • Update to version 0.2.10+12:
  • log Agent UUID at push agent startup
  • Limit actix-web workers
  • Fix clippy needless_late_init warnings
  • Unwrap OCTET STRING wrapped EK certificates
  • build(deps): bump rand from 0.9.4 to 0.10.1
  • build(deps): bump glob from 0.3.3 to 0.3.4
  • build(deps): bump reqwest from 0.13.3 to 0.13.4
  • Check shutdown marker inside ml_extend loop
  • Fix clippy useless_borrows_in_formatting warnings
  • build(deps): bump tokio from 1.52.2 to 1.53.1
  • Fix payload key upgrade regression by falling back to mTLS key
  • Accept any RSA key size for payload encryption
  • Bump version to 0.2.10
  • keylime: use runtime OpenSSL algorithm detection instead of compile-time symbols
Record
SUSE-SU-2026:4930-1
Updated
2026-11-02
OSVSUSE-SU-2026:4931-1 No score

Security update for rust-keylime

This update for rust-keylime fixes the following issue:

  • CVE-2026-115905: zip: security control bypass via parser differential between central directory and local headers (bsc#1287921)
  • CVE-2026-115906: zip: authentication bypass in AES encrypted entries due to improper HMAC verification (bsc#1287921)
  • CVE-2026-115907: zip: denial of service via unbounded memory allocation in legacy decoders (bsc#1287921)
  • CVE-2026-115908: zip: path traversal via lexical symlink validation during extraction (bsc#1287921)
  • CVE-2026-115909: zip: denial of service via uncontrolled memory allocation on symlink targets (bsc#1287921)

Changes for rust-keylime:

  • Update to version 0.2.10+12:
  • log Agent UUID at push agent startup
  • Limit actix-web workers
  • Fix clippy needless_late_init warnings
  • Unwrap OCTET STRING wrapped EK certificates
  • build(deps): bump rand from 0.9.4 to 0.10.1
  • build(deps): bump glob from 0.3.3 to 0.3.4
  • build(deps): bump reqwest from 0.13.3 to 0.13.4
  • Check shutdown marker inside ml_extend loop
  • Fix clippy useless_borrows_in_formatting warnings
  • build(deps): bump tokio from 1.52.2 to 1.53.1
  • Fix payload key upgrade regression by falling back to mTLS key
  • Accept any RSA key size for payload encryption
  • Bump version to 0.2.10
  • keylime: use runtime OpenSSL algorithm detection instead of compile-time symbols
Record
SUSE-SU-2026:4931-1
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
zip
crates.io
1.3.0 up to 9.0.0
9.0.0
rust
Azure Linux:3
through 1.75.0-31 None known
rust
Azure Linux:3
1.85.0 to 1.98.1-1 None known
rust-zip
Debian:12
All versions, plus listed versions
0.6.3-30.6.6-10.6.6-20.6.6-30.6.6-4
Show 7 moreShow less
0.6.6-52.5.0-15.1.1+dfsg-15.1.1-15.1.1-25.1.1-35.1.1-4
None known
rust-zip
Debian:13
All versions, plus listed versions
2.5.0-15.1.1+dfsg-15.1.1-15.1.1-25.1.1-35.1.1-4
None known
rust-zip
Debian:14
All versions, plus listed versions
2.5.0-15.1.1+dfsg-15.1.1-15.1.1-25.1.1-35.1.1-4
None known
zip
crates.io
0.0.0-0 up to 9.0.0
9.0.0
rust-keylime
SUSE:Linux Enterprise Micro 5.4
From an advisory covering 5 CVEs
before 0.2.10+12-150400.3.22.1
0.2.10+12-150400.3.22.1
rust-keylime
SUSE:Linux Enterprise Micro 5.5
From an advisory covering 5 CVEs
before 0.2.10+12-150500.3.22.1
0.2.10+12-150500.3.22.1
rust-zip
Ubuntu:26.10
All versions, plus listed versions
5.1.1-35.1.1+dfsg-1
None known
rust-zip
Ubuntu:26.04:LTS
All versions, plus listed versions
2.5.0-15.1.1-25.1.1-3
None known

History

History
RecordedChangedSources
affectedOSV
affected, factsOSV
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-115909 is a high vulnerability (CVSS 7.5) in Zip-rs Zip2, published October 22, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.46%, the 40th percentile. Fixed in zip 9.0.0.

References

Show 20 moreShow less
This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open